Author: saqibkhan

  • Working of Preprocessor

    When we write a C program, it goes through multiple steps before becoming an executable file. The very first step is preprocessing, which is handled by the C Preprocessor. It prepares the source code for compilation by processing all instructions that start with the symbol, called preprocessor directives.

    Here is the overall build process of a C program, showing where the preprocessor comes in −

    build flow of c program

    In this chapter, we’ll see what the preprocessor does, how it works, and why it is important in a C program.

    What is a preprocessor?

    The preprocessor is a program that executes at the very first stage of compilation. It looks for preprocessor directives and performs tasks like including header files, defining constants, or selectively compiling parts of the code. It returns the modified source code with the ‘.i’ extension, which then goes to the assembler.

    For example −

    #include <stdio.h>#define PI 3.14

    Here, #include and #define are preprocessor directives. #include uses standard functions, and #define creates a constant value for the program.

    Main Functions of Preprocessor

    The preprocessor works purely with text and does not understand C language syntax, variables, functions, or data types. It performs text manipulation based on preprocessor directives. Its main functions are −

    • It removes all comments (// or /* */).
    • It expands macros wherever they are used by replacing them with their definitions.
    • It includes files based on standard header files or custom files.
    • It selects only the required parts of the code for compilation.
    • It adjusts line numbers, handles control and special instructions, throws errors, or gives special compiler instructions.

    Working of Preprocessor in C

    Let’s see the steps below to understand how internally our preprocessor works before the compilation process.

    Step 1: Reading the File

    The preprocessor opens your .c source file and reads it as plain text. It breaks the program into tokens, which are the smallest units like keywords, symbols, and numbers.

    For example −

    intmain(){return0;}

    The tokens for this program will be: int, main(){return, 0;}. These tokens are used in the next steps to identify preprocessor instructions.

    Step 2: Looking for Preprocessor Instructions

    The preprocessor scans the program line by line to identify preprocessor directives. These lines always start with #, such as #include#define, and #ifdef. At this step, it only marks these lines for further processing and does not act on them yet.

    For example −

    #include <stdio.h>   // Preprocessor instruction#define MAX 100      // Preprocessor instructionint x = MAX;// Normal C code

    Here, only the lines starting with # are recognized as preprocessor instructions. The rest of the code is ignored at this step.

    Step 3: Removing Comments

    Before processing any directives, the preprocessor removes all comments from the code. This includes both single-line (//) and multi-line (/* */) comments.

    For example –

    // This is a single line commentint a =10;/* This is a block comment */

    After preprocessing, it becomes –

    int a =10;

    Step 4: File Inclusion

    Now the preprocessor processes the #include directives that were identified earlier. It opens the specified file and copies its entire content into the program.

    For example, consider a main.c program and a myheader.h header file –

    main.c

    #include "myheader.h"intmain(){return0;}

    myheader.h

    #define PI 3.14intcalculate();

    After preprocessing, it will look like this −

    #define PI 3.14intcalculate();intmain(){return0;}

    The #include line is replaced by the actual content of the header file.

    Step 5: Macro Definition and Expansion

    Macros are text replacements defined by the preprocessor. They can be object-like or function-like, and they are replaced wherever they appear in the code. Let’s see an example below −

    Object-like Macros

    #define MAX 100#define MIN 1int array[MAX];int value = MIN +5;

    After preprocessing, the code becomes −

    int array[100];int value =1+5;

    Here, the preprocessor repalces MAX with 100 and MIN with 1.

    Function like Macros

    #define SQUARE(x) ((x) * (x))double result =SQUARE(5);

    After preprocessing, it becomes −

    double result =((5)*(5));

    The processor works like a small inline function and repalces the function-like macro call with the actual expression. Here, SQUARE(5) is replaced with ((5) * (5)).

    Step 6: Conditional Compilation

    The preprocessor can also include or skip certain parts of the program depending on the conditions provided using directives like #if#ifdef, and #ifndef.

    For example −

    #define DEBUG#ifdef DEBUGprintf("Debug mode\n");#elseprintf("Release mode\n");#endif

    If DEBUG is defined, the program will print Debug mode and if it is not defined, the program will print Release mode.

    Step 7: Line Control and Special Directives

    The preprocessor also handles special directives that control the compiler or show custom messages. For example#line can set custom line numbers in error messages, #error stops compilation and displays a message, and #pragma sends instructions to the compiler. These directives gives us more control over compilation and error reporting.

    For example −

    #error This program requires C99

    Here, #error stops the compilation and shows a message that displays the program requires the C99 standard.

    Step 8: Producing Modified Source Code

    After processing all directives, expanding macros, including files, handling conditional compilation, and removing comments, the preprocessor generates the modified source code. This code is what the compiler actually works with.

    For example, if main.c contains −

    #include <stdio.h>#define MAX 5intmain(){int arr[MAX];printf("Array size is %d\n", MAX);return0;}

    It will produce the main.i file. Normally, we don’t see the preprocessed file, but we can generate it using GCC like this −

    gcc -E main.c -o main.i
    

    Here, the -E option stops compilation after preprocessing and creates the main.i file −

    #include <stdio.h>intmain(){int arr[5];printf("Array size is %d\n",5);return0;}

    In this file, the macro MAX is replaced with 5, the content of <stdio.h> is included, and comments are removed.

    Final Example: Working of Preprocessor

    Let’s take a complete program example that uses different preprocessor directives and see how the preprocessor transforms the code for the next step of compilation process.

    Original Code (main.c) −

    #include <stdio.h>#define PI 3.14#define AREA(r) (PI * (r) * (r))#define DEBUGintmain(){#ifdef DEBUGprintf("Debugging Mode\n");#endifdouble result =AREA(5);printf("Area = %f\n", result);return0;}

    Preprocessed Code (main.i) −

    #include <stdio.h>intmain(){printf("Debugging Mode\n");double result =(3.14*(5)*(5));printf("Area = %f\n", result);return0;}

    In the above program the preprocessor performs the following task before generating the file with .i extension.

    • It replaced the macro PI with 3.14.
    • It expanded the macro AREA(5) into (3.14 * (5) * (5)).
    • It included the printf(“Debugging Mode\n“); line because DEBUG was defined.
    • It processed the #include <stdio.h> directive by inserting the contents of the standard I/O header file.

    In this chapter, we learned about the preprocessor, which is the first stage of the build process and prepares the source code for compilation. It takes the source file, processes all directives, macros, and comments, and generates an assembly file that is then passed to the assembler and linker, continuing through the build process to produce the final executable.

  • Macros in C

    Macros in C are the names given to specific constant values or code statements which are replaced with their value/code before the compilation processor. C Macros are defined using the #define preprocessor directive.

    Macros are useful for code reusability, defining constant values, defining inline functions, and conditional compilations.

    The following are the different types of C macros that we are going to cover in this tutorial –

    • Object-like Macros
    • Function-like Macros
    • Chained Macros
    • Variadic Macros
    • Predefined Macros

    Object-like Macros

    A macro that defines a constant is an object-like macro.

    Syntax

    It is done with the following syntax −

    #define name value

    Example of Object-like Macros

    In the following example, we are defining an object-like macro −

    #include <stdio.h>// Defining macros#define PI 3.14#define MAX 10intmain(){// Printing the valuesprintf("Value of PI = %d\n", PI);printf("Value of MAX = %d\n", MAX);return0;}

    Function-like Macro

    To define a function-like macro, you use the same “#define” directive, but you put a pair of parentheses immediately after the macro name, with one or more arguments. Such a macro is expanded only when its name appears with a pair of parentheses after it.

    When the preprocessor expands such a macro, it incorporates the specified arguments in the replacement text. The function-like macros are often called Macros with parameters (or arguments).

    Syntax

    A function-like macro is defined as follows −

    #define macro_name([parameter_list]) replacement_text

    Example of Function-like Macros

    An example of function-like macro is given below −

    #include <stdio.h>#define square(x) ((x) * (x))intmain(){int x =5;printf("x: %d \tSquare of x: %d", x,square(x));return0;}

    Output

    When you run this code, it will produce the following output −

    x: 5 	Square of x: 25
    

    Rules for Defining Function-like Macros

    Some rules of defining a function also apply to macros −

    • A macro can be defined without arguments
    • A macro can be defined with a fixed number of arguments
    • A macro can be defined with a variable number of arguments

    For example, when you use such a macro, the comma-separated argument list must contain as many arguments as there are parameters in the macro definition.

    Function-like Macros without Arguments

    A function-like macro may also be defined without arguments.

    Example 1

    The following example shows how you can use a macro without arguments −

    #include <stdio.h>#define MESSAGE() printf("Hello World");intmain(){int x =5;MESSAGE();return0;}

    Output

    Run the code and check its output −

    Hello World
    

    Some standard libraries also provide macro definitions in it. For example, the getchar() macro when expanded, implements the getc() function as follows −

    #define getchar() getc(stdin)

    Similarly, the putchar() macro encapsulates the putc() function −

    #define putchar(x) putc(x, stdout)

    Example 2

    The following program defines a macro named as LOOP(x) and runs a for loop for the number of times as its argument −

    #include <stdio.h>#define LOOP(x) {\
       for (int i = 1; i <= x; i++)\
       printf("Iteration no: %d\n", i);\
    }intmain(){int x =3;LOOP(x);}

    Output

    When you run this code, it will produce the following output −

    Iteration no: 1
    Iteration no: 2
    Iteration no: 3
    

    Chained Macros

    When we have a macro nested inside another macro, they are called Chained Macros.

    Example of Chained Macros

    The following example shows how you can use chained macros −

    #include <stdio.h>#define PI 3.142#define CIRCUMFERENCE(x) (2*PI*x)intmain(){int x =5;printf("Circumference of a circle with radius %d is %f", x,CIRCUMFERENCE(x));return0;}

    Output

    When you run this code, it will produce the following output −

    Circumference of a circle with radius 5 is 31.420000
    

    Variadic Macros

    You can also define a macro with variable number of arguments or variadic macros. A macro with variable-length argument is a feature that enables a macro to accept any number of arguments. You can pass positional as well as keyword arguments to a macro.

    When a variadic macro is defined, the ellipsis () is given as an argument to capture variable number of arguments. To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition. This sequence of tokens replaces the identifier __VA_ARGS__ in the macro body wherever it appears.

    The __VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them. Note that the variadic macros can be used only in the C99 compatible C compilers and above.

    Example of Variadic Macros

    Take a look at the following example −

    #include <stdio.h>#define MAX_ARGS 5		// Define maximum number of allowed arguments#define ARGS(x, ...) do {\
       printf("%d\n", ##__VA_ARGS__); \
    } while (0)intmain(){ARGS(1,2,3);// 3 argumentsARGS(1,2,3,4,5,6);// 6 arguments return0;}

    Output

    Run the code and check its output −

    2
    2
    

    Predefined Macros

    ANSI C defines a number of macros. Although each one is available for use in programming, the predefined macros should not be directly modified.

    MacroDescription
    __DATE__The current date as a character literal in “MMM DD YYYY” format.
    __TIME__The current time as a character literal in “HH:MM:SS” format.
    __FILE__This contains the current filename as a string literal.
    __LINE__This contains the current line number as a decimal constant.
    __STDC__Defined as 1 when the compiler complies with the ANSI standard.

    Example

    The following example demonstrates how you can use the predefined macros in a C program −

    #include <stdio.h>intmain(){printf("File :%s\n",__FILE__);printf("Date :%s\n",__DATE__);printf("Time :%s\n",__TIME__);printf("Line :%d\n",__LINE__);printf("ANSI :%d\n", __STDC__ );}

    Output

    When you run this code, it will produce the following output −

    File: main.c
    Date: Mar 6 2024
    Time: 20:12:19
    Line: 8
    ANSI: 1
    
  • pragma Directive in C

    What is #pragma Directive in C?

    The preprocessor directive #pragma is used to provide additional information to the compiler in C/C++ language. This is used by the compiler to provide some special features.

    Note that pragmas are compiler dependent. Not all the pragma directives are supported by all the compilers.

    Syntax

    Here is the syntax of using a #pragma directive in C/C++ language −

    #pragma token_name

    Types of Pragma Directives in C

    The table of some of #pragma directives in C/C++ language is given as follows,

    DirectiveDescription
    #pragma startupBefore the execution of main(), the function specified in pragma is needed to run.
    #pragma exitBefore the end of program, the function specified in pragma is needed to run.
    #pragma warnUsed to hide the warning messages.
    #pragma GCC dependencyChecks the dates of current and other file. If other file is recent, it shows a warning message.
    #pragma GCC system_headerIt treats the code of current file as if it came from system header.
    #pragma GCC poisonUsed to block an identifier from the program.
    #pragma onceCompiler loads the header file only once.

    #pragma startup and exit

    These pragma directives are executed before and after the main() function. Not all the compilers support these directives.

    Example

    The following code demonstrates how you can use the pragma startup and exit directives −

    #include <stdio.h>intdisplay();#pragma startup display#pragma exit displayintmain(){printf("\nI am in main function");return0;}intdisplay(){printf("\nI am in display function");return0;}

    Output

    When you run this code, it will produce the following output −

    I am in main function
    

    #pragma warn

    The #pragma warn directive is used to hide or display the warning messages which are displayed during compilation.

    The warn pragma is used as per the following syntax −

    #pragma warn +xxx (To show the warning) #pragma warn -xxx (To hide the warning) #pragma warn .xxx (To toggle between hide and show)

    The three character codes to be used are rvl (return value), par (parameter used or not), and rch (if the code is unreachable).

    If any character code is prefixed by “+”, it indicates to show the warning; prefixed by “” means indication to the compiler to hide warnings, and prefix by dot (.) is an instruction to the compiler to toggle between hide and display warnings.

    Example

    The following example shows how you can use the warn pragma in a C program −

    #include <stdio.h>#pragma warn -rvl          /* return value */#pragma warn +par	   /* parameter never used */#pragma warn rch	   /* unreachable code */intsquare(int x){printf("Hello World");}intmain(){square(10);return0;}

    Output

    When you run this code, it will produce the following output −

    Hello World
    

    #pragma GCC poison

    The GCC compiler removes an identifier completely from the program. If we want to block an identifier, then we can use the #pragma GCC poison directive. Its syntax is as follows −

    #pragma GCC poison identifier

    Example

    In this example, we will use the GCC poison pragma to block the printf() function −

    #include <stdio.h>#pragma GCC poison printfintmain(){int a =10;if(a ==10){printf("Hello World");}elseprintf("TutorialsPoint");return0;}

    Output

    When you try to compile this code, it will show the following error −

    error: attempt to use poisoned "printf"
    

    #pragma GCC dependency

    This pragma allows you to check the relative dates of the current file and another file. If the other file is more recent than the current file, a warning is issued.

    Example

    Take a look at the following example −

    #include <stdio.h>#pragma GCC dependency "depends.c"intmain(){printf("Hello, World!");return0;}

    Output

    The above source code is depending on depends.c. If its compilation timestamp is more recent, then the following warning is issued −

    warning: current file is older than depends.c
    

    #pragma GCC system_header

    As a convention, system header files are placed angular brackets in front of the #include directive, whereas the non-system header files are in quotation marks. If you want the compiler to treat the latter as the system header, use this pragma.

    Syntax

    #pragma GCC system_header

    library.h

    We define a “library.h” header file in the current directory.

    #ifndef LIBRARY_H#define LIBRARY_H#pragma GCC system_headervoidmyFunction();#endif

    Example

    To ask the compiler to treat “library.h” as a system header, use the #pragma GCC system_header.

    #include <stdio.h>#include "library.h"intmain(){myFunction();// Using a function from the library.hprintf("Hello, World!\n");return0;}

    #pragma once

    The #pragma once directive causes the header file to be included only once, even if the programmer includes it multiple times.

    Save the “myheader.h” file as −

    myheader.h

    #pragma oncevoidmyFunction();

    Example

    In another code (main.c), call myFunction() as follows −

    #include <stdio.h>#include "myheader.h"intmain(){myFunction();printf("Hello, World!\n");return0;}

    Print Page

  • Preprocessors

    The C Preprocessor is not a part of the compiler, but is a separate step in the compilation process. In simple terms, a C Preprocessor is just a text substitution tool and it instructs the compiler to do the required pre-processing before the actual compilation. We’ll refer to the C Preprocessor as CPP.

    In C programming, preprocessing is the first step in the compilation of a C code. It occurs before the tokenization step. One of the important functions of a preprocessor is to include the header files that contain the library functions used in the program. The preprocessor in C also defines the constants and expands the macros.

    The preprocessor statements in C are called directives. A preprocessor section of the program always appears at the top of the C code. Each preprocessor statement starts with the hash (#) symbol.

    Preprocessor Directives in C

    The following table lists down all the important preprocessor directives −

    DirectiveDescription
    # defineSubstitutes a preprocessor macro.
    #includeInserts a particular header from another file.
    #undefUndefines a preprocessor macro.
    #ifdefReturns true if this macro is defined.
    #ifndefReturns true if this macro is not defined.
    #ifTests if a compile time condition is true.
    #elseThe alternative for #if.
    #elif#else and #if in one statement.
    #endifEnds preprocessor conditional.
    #errorPrints error message on stderr.
    #pragmaIssues special commands to the compiler, using a standardized method.

    Preprocessors Examples

    Analyze the following examples to understand various directives.

    This #define directive tells the CPP to replace the instances of MAX_ARRAY_LENGTH with 20. Use #define for constants to increase readability.

    #define MAX_ARRAY_LENGTH 20

    The following directives tell the CPP to get “stdio.h” from the System Libraries and add the text to the current source file. The next line tells CPP to get “myheader.h” from the local directory and add the content to the current source file.

    #include <stdio.h>#include "myheader.h"

    Now, take a look at the following #define and #undef directives. They tell the CPP to undefine existing FILE_SIZE and define it as 42.

    #undef  FILE_SIZE#define FILE_SIZE 42

    The following directive tells the CPP to define MESSAGE only if MESSAGE isn’t already defined.

    #ifndef MESSAGE#define MESSAGE "You wish!"#endif

    The following directive tells the CPP to process the statements enclosed if DEBUG is defined.

    #ifdef DEBUG/* Your debugging statements here */#endif

    This is useful if you pass the -DDEBUG flag to the gcc compiler at the time of compilation. This will define DEBUG, so you can turn debugging ON and OFF on the fly during compilation.

    Predefined Macros in C

    ANSI C defines a number of macros. Although each one is available for use in programming, the predefined macros should not be directly modified.

    MacroDescription
    __DATE__The current date as a character literal in “MMM DD YYYY” format.
    __TIME__The current time as a character literal in “HH:MM:SS” format.
    __FILE__This contains the current filename as a string literal.
    __LINE__This contains the current line number as a decimal constant.
    __STDC__Defined as 1 when the compiler complies with the ANSI standard.

    Example

    Let’s try the following example −

    #include <stdio.h>intmain(){printf("File: %s\n",__FILE__);printf("Date: %s\n",__DATE__);printf("Time: %s\n",__TIME__);printf("Line: %d\n",__LINE__);printf("ANSI: %d\n", __STDC__ );}

    Output

    When you run this code, it will produce the following output −

    File: main.c
    Date: Mar 6 2024
    Time: 13:32:30
    Line: 8
    ANSI: 1
    

    Preprocessor Operators

    The C preprocessor offers the following operators to help create macros −

    Example: The Macro Continuation (\) Operator in C

    A macro is normally confined to a single line. The macro continuation operator (\) is used to continue a macro that is too long for a single line. Take a look at the following example −

    #include <stdio.h>#define message_for(a, b)  \
       printf(#a " and " #b ": We love you!\n")intmain(){message_for(Ram, Raju);}

    Output

    When you run this code, it will produce the following output −

    Ram and Raju: We love you!
    

    Example: The Stringize (#) Operator in C

    The stringize operator (#), also called number-sign operator, when used within a macro definition, converts a macro parameter into a string constant.

    The stringize operator may be used only in a macro having a specified argument or parameter list. For example −

    #include <stdio.h>#define  message_for(a, b)  \
       printf(#a " and " #b ": We love you!\n")intmain(){message_for(Carole, Debra);return0;}

    Output

    Run the code and check its output −

    Carole and Debra: We love you!
    

    Example: The Token Pasting (##) Operator in C

    The token-pasting operator (##) within a macro definition combines two arguments. It permits two separate tokens in the macro definition to be joined into a single token. For example −

    #include <stdio.h>#define tokenpaster(n) printf ("token" #n " = %d", token##n)intmain(){int token34 =40;tokenpaster(34);return0;}

    Output

    When you run this code, it will produce the following output −

    token34 = 40
    

    Example: The defined() Operator in C

    The preprocessor defined operator is used in constant expressions to determine if an identifier is defined using #define. If the specified identifier is defined, the value is true (non-zero). If the symbol is not defined, the value is false (zero).

    The following example shows how you can use the defined operator in a C program −

    #include <stdio.h>#if !defined (MESSAGE)#define MESSAGE "You wish!"#endifintmain(){printf("Here is the message: %s\n", MESSAGE);return0;}

    Output

    Run the code and check its output −

    Here is the message: You wish!
    

    Parameterized Macros in C

    One of the powerful functions of the CPP is the ability to simulate functions using parameterized macros. For example, we might have some code to square a number as follows −

    intsquare(int x){return x * x;}

    We can rewrite above the code using a macro as follows −

    #define square(x) ((x) * (x))

    Macros with arguments must be defined using the #define directive before they can be used. The argument list is enclosed in parentheses and must immediately follow the macro name. Spaces are not allowed between the macro name and open parenthesis.

    Example

    The following example demonstrates how you can use parameterized macros in C −

    #include <stdio.h>#define MAX(x,y) ((x) > (y) ? (x) : (y))intmain(){printf("Max between 20 and 10 is %d\n",MAX(10,20));return0;}

    Output

    When you run this code, it will produce the following output −

    Max between 20 and 10 is 20
    
  • getc, getchar, getch, getche

    In C, getc()getchar()getch(), and getche() are functions used to read a character from input and return it as an integer.

    Where, the getc() and getChar() are declared in <stdio.h> and getch() and getche() are declared in <conio.h>. Let’s discuss each function in-details.

    getc() Function in C

    In C, the getc() function is used to read a character from a specific file or stream. It returns the next character (as an unsigned char cast to int) from the given file stream, or EOF if the end of file or an error occurs.

    Below is the declaration −

    intgetc(FILE *stream);

    This function accepts a single parameter a pointer to a FILE object that specifies an input stream.

    Example of getc() – Read a Character from a File

    In this example we use the getc() function to display each character from file −

    #include <stdio.h>intmain(){
       FILE *file =fopen("example.txt","r");if(file ==NULL){printf("Unable to open file.\n");return1;}char ch;printf("Contents of the file:\n");while((ch =getc(file))!=EOF){// Display each characterputchar(ch);}fclose(file);return0;}

    Read character one by one from a file until EOF. Following is the output −

    Contents of the file:
    Line 1: Hello tutorialspoint!
    Line 2: Welcome to C programming.
    

    getchar() Function in C

    In C, the getchar() function reads the next character from the standard input (stdin) and returns it as an unsigned char cast to an int. It is mainly used for simple input tasks, such as reading characters one by one.

    Below is the declaration −

    intgetchar(void);

    If the end-of-file (EOF) is reached or if an error occurs, getchar returns EOF. The EOF is typically defined as -1 in the standard library.

    Example of getchar() – Read a Character from Standard Input

    In this example, we use a getchar function to read a entered character from standard input −

    #include <stdio.h>intmain(){char ch;printf("Enter a character: ");// Reads from keyboard
       ch =getchar();printf("You entered: %c\n", ch);return0;}

    Following is the output −

    Enter a character: t
    You entered: t
    

    getch() Function in C

    In C, the getch() is a non-standard function which comes under the <conio.h> header file and used by Turbo C compiler.

    It is also used to read the single character from the keyboard. But it does not use any buffer. So the entered character is immediately returned without waiting for the enter key.

    getch() is not part of the C standard library or ISO C, nor is it defined by POSIX.

    Below is the declaration −

    intgetch(void);

    Return the character read from the keyboard as an int.

    Example of getch() – Read a Character without echo

    In this following example, we use the getch function to display the hidden entered character immediately −

    #include <stdio.h>#include <conio.h>intmain(){char ch;printf("Press any key (hidden): ");// Reads immediately without displaying
       ch =getch();printf("\nYou pressed: %c\n", ch);return0;}

    Following is the output −

    Press any key (hidden):
    You pressed: a
    

    getche() Function in C

    In C, the getche() is also a non-standard function which comes under the <conio.h> header file.

    This function reads a single character from the keyboard and displays immediately on the output screen without waiting for enter key. Like getch().

    Below is the declaration:

    intgetche(void);

    Since the return type is int, the character is returned as an unsigned char cast to int.

    On error, it may return EOF (though in practice, DOS-based <conio.h> rarely uses EOF).

    Example of getche() – Read a Character with Echo

    In this following example, we use the getche function to display the entered character immediately.

    #include <stdio.h>#include <conio.h>intmain(){char ch;printf("Press any key (visible): ");// Reads immediately and displays it
       ch =getche();printf("\nYou pressed: %c\n", ch);return0;}

    Following is the output −

    Press any key (visible): a
    You pressed: a
    

    Why We Use getc(), getchar(), getch(), and getche() in C

    Following are the reasons to use these functions −

    To Read Character as Input

    • getc() − Reads a character from a specific file or input stream. For example, if you are reading from a file, getc() allows you to process it character by character.
    • getchar() − Reads a character from the keyboard (standard input). It is commonly used when you want to take simple input from the user.
    • getch() / getche() − Reads a character immediately from the keyboard, without waiting for the Enter key. This is useful in interactive programs like menus, games, or password fields.

    To Control Input Behaviour

    • getchar() / getc() − Buffered input, these functions wait until the user presses Enter. The input is stored in a buffer before the program reads it.
    • getch() − Unbuffered input, do not wait for Enter. They read the character immediately as soon as it is pressed. The character is not displayed on the screen (hidden input).
    • getche() − Unbuffered input, do not wait for Enter. They read the character immediately as soon as it is pressed. The character is displayed on the screen as soon as it is typed.

    To Handle both Input and End Conditions

    All return an int so they can give either a valid character (as unsigned char) or EOF for error/end of file.

    Comparison Table

    The below table lists the primary differences between the getc(), getchar(), getch() and getche() in C

    FunctionHeader FilePurposeInput SourceBufferingReturn Type
    getc()<stdio.h>Reads a character from a given file.File streamBufferedint
    getchar()<stdio.h>Reads a character from standard input.Standard inputBufferedint
    getch()<conio.h>Reads a single character from keyboard.KeybordUnbufferedchar
    getche()<conio.h>Reads a single character from keyboard.KeybordUnbufferedchar

    Conclusion

    In C, functions such as getc()getchar()getch(), and getche() help in reading characters from files or the keyboard. getc() works with files, getchar() accepts keyboard input, and getch() and getche() read keys immediately without waiting for Enter. They all return an integer, allowing them to properly handle both characters and the unusual EOF value.

  • Formatted Output

    In the C programming language, output functions perform the essential task of displaying or storing information in a well-formatted manner. The Standard Library <stdio.h> provides functions that allow programmers to control how data is presented. Among these, the three most commonly used functions are −

    • printf() − Displays formatted output on the standard output (console).
    • sprintf() − Stores formatted output in a string buffer (memory).
    • fprintf() − Writes formatted output to a file stream.

    Although these functions share a common structure and formatting style, each serves a distinct purpose depending on the output target or destination. First, we will look at the common format specifiers used in these functions, and then we will discuss each function in detail with examples.

    Following are the common format specifiers −

    • %d or %i: Integer
    • %f: Floating-point number
    • %c: Character
    • %s: String
    • %x or %X: Hexadecimal
    • %o: Octal
    • %%: Literal percent sign

    printf() – Printing to the Console

    In C, printf is the most commonly used function to display information on the standard output device (usually the terminal or console). It is used for debugging, user interaction, and displaying program results.

    The syntax of the printf() function is as follows −

    intprintf(constchar*format,...);

    Here, format is a string that contains text and format specifiers, which are placeholders for the values to be printed. The ellipsis (...) indicates that the function can take a variable number of arguments corresponding to the format specifiers.

    Example of using printf()

    In this C example, we demonstrate the working of the printf() function −

    #include <stdio.h>intmain(){int age =25;float height =5.8;char grade ='A';char name[]="Aman Kumar";printf("Name: %s\n", name);printf("Age: %d years\n", age);printf("Height: %.1f feet\n", height);printf("Grade: %c\n", grade);return0;}

    Following is the output of the code −

    Name: Aman Kumar
    Age: 25 years
    Height: 5.8 feet
    Grade: A
    

    sprintf() – Storing in a String Buffer

    In C, sprintf() function is used to format and store a series of characters in a string buffer. It is similar to printf(), but instead of printing to the console, it writes the formatted output to a character array (string).

    The syntax of the sprintf() function is as follows −

    intsprintf(char*str,constchar*format,...);

    Here, str is a pointer to the character array where the formatted string will be stored, format is a string containing text and format specifiers, and the ellipsis (...) indicates that the function can take a variable number of arguments corresponding to the format specifiers.

    Example of using sprintf()

    In this C example, we demonstrate the working of the sprintf() function −

    #include <stdio.h>intmain(){int age =25;float height =5.8;char grade ='A';char name[]="Aman Kumar";char buffer[100];sprintf(buffer,"Name: %s\nAge: %d years\nHeight: %.1f feet\nGrade: %c\n",
    
           name, age, height, grade);// Print the formatted string stored in bufferprintf("%s", buffer);return0;}</code></pre>

    Following is the output of the code −

    Name: Aman Kumar
    Age: 25 years
    Height: 5.8 feet
    Grade: A
    

    fprintf() - Writing to a File

    In C, fprintf() function is used to format and write a series of characters to a file stream. It is similar to printf(), but instead of printing to the console, it writes the formatted output to a file.

    The syntax of the fprintf() function is as follows −

    intfprintf(FILE *stream,constchar*format,...);

    Here, stream is a pointer to a FILE object that identifies the file where the formatted output will be written, format is a string containing text and format specifiers, and the ellipsis (...) indicates that the function can take a variable number of arguments corresponding to the format specifiers.

    Example of using fprintf()

    In this C example, we demonstrate the working of the fprintf() function −

    #include <stdio.h>intmain(){
       FILE *file =fopen("output.txt","w");if(file ==NULL){printf("Error opening file!\n");return1;}int age =25;float height =5.8;char grade ='A';char name[]="Aman Kumar";fprintf(file,"Name: %s\n", name);fprintf(file,"Age: %d years\n", age);fprintf(file,"Height: %.1f feet\n", height);fprintf(file,"Grade: %c\n", grade);fclose(file);return0;}

    This code will create a file named output.txt with the following content.

    Name: Aman Kumar
    Age: 25 years
    Height: 5.8 feet
    Grade: A
    

    Conclusion

    In this article, we have discussed the formatted output functions in C programming language. These functions are essential for displaying and storing information in a structured manner. By using format specifiers, we can control how different data types are represented in the output. The printf()sprintf(), and fprintf() functions provide flexibility in directing output to various destinations, such as the console, memory buffers, or files. Understanding these functions is crucial for effective C programming and data presentation.

  • File Operations

    File operations in C refer to the various tasks that can be performed on files stored in a computer’s storage, such as creatingreadingwriting, and closing them. These process let C program work with data that stays around after the program is done running, which is different from ordinary input/output, which only works with the console.

    File Operations in C

    Following are the file operations −

    • Opening/Creating a file
    • Writing to a file
    • Reading from a file
    • Closing a file

    Let’s briefly discuss the file operations mentioned above. We have already covered these methods in detail in the File I/O chapter. Since there are additional file operations, we will cover all of them in detail in this chapter.

    Opening/Creating a File

    File opening is the first step, whether it is to open an existing file or create a new one to perform operations on it. In C, the fopen() function is used to create a new file or open an existing file.

    Let’s see how we can open or create a file. The syntax is given below −

    FILE *fopen(constchar*filename,constchar*mode);

    Here, filename is the name of the file to be opened, and mode defines the file’s opening mode.

    Here, filename is the name of the file to be opened, and mode defines the file’s opening mode.

    Writing to a File

    Writing to a file means the process of sending data from your program’s memory to a file stored on a persistent storage device, such as a hard drive, SSD, or USB drive.

    The following library functions are provided to write data in a file opened in writeable mode −

    • fputc() − Writes a single character to a file.
    • fputs() − Writes a string to a file.
    • fprintf() − Writes a formatted string (data) to a file.

    Below are the syntax to write in a file −

    // Write a single character to a fileintfputc(int c, FILE *fp);// Write a string to a fileintfputs(constchar*s, FILE *fp);// Writes a formatted string (data) to a file.intfprintf(FILE *stream,constchar*format [, argument,...])

    Reading from a File

    When you read from a file in C, you get data from a file on a storage device and load it into your program’s memory so you can work with it.

    The following library functions are provided to read data from a file that is opened in read mode −

    • fgetc(): Reads a single character from a file.
    • fgets(): Reads a string from a file.
    • fscanf(): Reads a formatted string from a file.

    Below are the syntax to reading from a file −

    // Reads a single character from a fileintfgetc(FILE * fp);// Reads a string from a file.intfgets(buffer,sizeof(buffer), FILE *fp);// Reads a formatted string from a file.intfscanf(FILE *stream,constchar*format,...)

    Closing a File

    Closing a file requires using the fclose() function after performing operations on it.

    Below is the syntax to close a opened file −

    intfclose(FILE *fp);

    Example: File Operations in C

    In this C example, we will demonstrate each file operation that we discussed above −

    #include <stdio.h>intmain(){
    
       FILE * file;char data[100];// Creating/Opening a file in write mode
       file =fopen("example.txt","w");if(file ==NULL){printf("Error! Could not open file.\n");return1;}printf("File created/opened successfully in write mode.\n");// Writing to the filefprintf(file,"Hello, this is a test file.\n");fprintf(file,"We are writing data into it.\n");// Closing after writing    fclose(file);printf("Data written to the file and file closed.\n\n");// Opening the file again in read mode
       file =fopen("example.txt","r");if(file ==NULL){printf("Error! Could not open file for reading.\n");return1;}printf("File opened successfully in read mode.\n");// Reading from the fileprintf("Reading data from the file:\n");while(fgets(data,sizeof(data), file)!=NULL){printf("%s", data);}// Closing the filefclose(file);printf("\n\nFile closed after reading.\n");return0;}

    Following is the output

    File Operations in C

    Additional File Operations

    There are also additional file operations that can be performed on a file, such as removing, rewinding, renaming, and handling errors.

    Removing a File

    Removing a file means deleting a specified file from storage. For example, if you have completed all tasks and operations on a file and want to delete it from storage, you can use the remove() function to delete the file.

    Below is the syntax to remove/delete a file in C

    intremove(FILE *fp);

    Example: Removing a File

    In the following, example we demonstrate how to remove a file

    #include <stdio.h>intmain(){// Create a file to remove
       FILE *file =fopen("remove_example.txt","w");if(file ==NULL){printf("Error creating file.\n");return1;}fprintf(file,"This file will be removed.\n");fclose(file);// Remove the fileif(remove("remove_example.txt")==0){printf("File removed successfully.\n");}else{perror("Error removing file");}return0;}

    Following is the output −

    File removed successfully.
    

    Rename a File

    Rename means change the name of an existing file.

    Below is the syntax to rename an existing file −

    rename("existing file name","new file name");

    Example: Rename a File

    In this following c program, we demonstrate how we can rename the file −

    #include <stdio.h>intmain(){char oldName[]="example.txt";char newName[]="renamed_example.txt";// Renaming the fileif(rename(oldName, newName)==0){printf("File renamed successfully from '%s' to '%s'.\n", oldName, newName);}else{perror("Error renaming file");}return0;}

    Following is the output −

    File renamed successfully from 'example.txt' to 'renamed_example.txt'.
    

    Rewind a File

    Rewind a file means moves the file pointer back to the beginning of the file. It is useful when you want to re-read the file form the start.

    Below is the syntax to rewind a file −

    intrewind(FILE *fp);

    Example: Rewind a File

    In this example, we demonstrate how to rewind the a pointer in file.

    #include <stdio.h>intmain(){
       FILE *file;char data[100];// Open file in write mode and add some data
       file =fopen("example.txt","w+");if(file ==NULL){printf("Error! Could not open file.\n");return1;}// Writing data to the filefprintf(file,"Line 1: Hello tutorialspoint!\n");fprintf(file,"Line 2: Welcome to C programming.\n");// Move file pointer to beginningrewind(file);printf("Reading data after rewind:\n");while(fgets(data,sizeof(data), file)!=NULL){printf("%s", data);}// Close the filefclose(file);return0;}

    Following is the output −

    Rewind a File

    Error Handling of a File

    Error handling helps in identifying file-related errors.

    Example

    In the following c program, we demonstrate the working of error handling of file −

    #include <stdio.h>intmain(){
    	
       FILE *file;char data[100];// Creating/Opening a file in write mode
       file =fopen("example.txt","w");if(file ==NULL){printf("Error! Could not open file.\n");return1;}return0;}

    Following is the output, if we trying running the code online −

    Error! Could not open file.
    

    Conclusion

    File operations in C enable program to create, read, write, rename, rewind, and delete files on a regular basis. These procedures allow data to remain after program execution, while good error handling provides safe and dependable file management.

  • Input and Output Functions

    Reading input from the user and showing it on the console (output) are the common tasks every C program needs. C language provides libraries (header files) that contain various functions for input and output. In this tutorial, we will learn different types of formatted and unformatted input and output functions.

    The Standard Files in C

    The C language treats all the devices as files. So, devices such as the “display” are addressed in the same way as “files”.

    The following three files are automatically opened when a program executes to provide access to the keyboard and screen.

    Standard FileFileDevice
    Standard inputstdinKeyboard
    Standard outputstdoutScreen
    Standard errorstderrYour screen

    To access a file, C uses a predefined FILE struct type to refer to the file for reading and writing purpose. Read this chapter to understand how to read values from the screen and how to print the result on the screen.

    Types of Input and Output Functions

    We have the following categories of IO function in C −

    • Unformatted character IO functions: getchar() and putchar()
    • Unformatted string IO functions: gets() and puts()
    • Formatted IO functions: scanf() and printf()

    The unformatted I/O functions read and write data as a stream of bytes without any format, whereas formatted I/O functions use predefined formats like “%d”, “%c” or “%s” to read and write data from a stream.

    Unformatted Character Input & Output Functions: getchar() and putchar()

    These two functions accept a single character as input from the keyboard, and display a single character on the output terminal, respectively.

    The getchar() function it reads a single key stroke without the Enter key.

    intgetchar(void)

    There are no parameters required. The function returns an integer corresponding to the ASCII value of the character key input by the user.

    Example 1

    The following program reads a single key into a char variable −

    #include <stdio.h>intmain(){char ch;printf("Enter a character: ");
       ch =getchar();puts("You entered: ");putchar(ch);return0;}

    Output

    Run the code and check its output −

    Enter a character: W
    You entered:
    W
    

    Example 2

    The following program shows how you can read a series of characters till the user presses the Enter key −

    #include <stdio.h>intmain(){char ch;char word[10];int i =0;printf("Enter characters. End with pressing enter: ");while(1){
    
      ch =getchar();
      word&#91;i]= ch;if(ch =='\n')break;
      i++;}printf("\nYou entered the word: %s", word);return0;}</code></pre>

    Output

    Run the code and check its output −

    Enter characters. End with pressing enter: Hello
    You entered the word: Hello
    

    You can also use the unformatted putchar() function to print a single character. The C library function "int putchar(int char)" writes a character (an unsigned char) specified by the argument char to stdout.

    intputchar(int c)

    A single parameter to this function is the character to be written. You can also pass its ASCII equivalent integer. This function returns the character written as an unsigned char cast to an int or EOF on error.

    Example 3

    The following example shows how you can use the putchar() function −

    #include <stdio.h>intmain(){char ch;for(ch ='A'; ch <='Z'; ch++){putchar(ch);}return(0);}

    Output

    When you run this code, it will produce the following output −

    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    

    Formatted String Input & Output Functions: gets(), fgets(), puts(), and fputs()

    The char *gets(char *str) function reads a line from stdin into the buffer pointed to by str until either a terminating newline or EOF (End of File) is encountered.

    char*gets(char*str)

    This function has a single argument. It is the pointer to an array of chars where the C string is stored. The function returns "str" on success and NULL on error or when EOF occurs while no characters have been read.

    Example

    Take a look at the following example −

    #include <stdio.h>intmain(){char name[20];printf("Enter your name: ");gets(name);printf("You entered the name: %s", name);return0;}

    Output

    Enter your name: Ravikant Soni
    You entered the name: Ravikant Soni
    

    scanf("%s") reads characters until it encounters a whitespace (space, tab, newline, etc.) or EOF. So, if you try to input a string with multiple words (separated by a whitespace), then it accepts characters before the first whitespace as the input to string.

    fgets() Function

    In newer versions of C, gets() has been deprecated as it is potentially a dangerous function because it doesnt perform bound checks and may result in buffer overflow.

    Instead, it is advised to use fgets() function −

    fgets(char arr[], size, stream);

    fgets() can be used to accept input from any input stream such as stdin (keyboard) or FILE (file stream).

    Example 1

    The following program shows how you can use fgets() to accept multi-word input from the user −

    #include <stdio.h>intmain(){char name[20];printf("Enter a name: \n");fgets(name,sizeof(name),stdin);printf("You entered: \n");printf("%s", name);return0;}

    Output

    Run the code and check its output −

    Enter a name:
    Rakesh Sharma
    
    You entered:
    Rakesh Sharma
    

    The function "int puts (const char *str)" writes the string 's' and a trailing newline to stdout.

    intputs(constchar*str)

    The str parameter is the C string to be written. If successful, it returns a non-negative value. On error, the function returns EOF.

    We can use the printf() function with %s specifier to print a string. We can also use the puts() function (deprecated in C11 and C17 versions) or the fputs() function as an alternative.

    Example 2

    The following example shows the difference between puts() and fputs() −

    #include <stdio.h>intmain(){char name[20]="Rakesh Sharma";printf("With puts(): \n");puts(name);printf("\nWith fputs(): \n");fputs(name,stdout);return0;}

    Output

    Run the code and check its output −

    With puts():
    Rakesh Sharma
    
    With fputs():
    Rakesh Sharma
    

    Formatted Input & Output Functions: scanf() and printf()

    The scanf() function reads the input from the standard input stream stdin and scans that input according to the format provided −

    intscanf(constchar*format,...)

    The printf() function writes the output to the standard output stream stdout and produces the output according to the format provided.

    intprintf(constchar*format,...)

    The format can be a simple constant string, but you can specify %s, %d, %c, %f, etc., to print or read strings, integers, characters or floats respectively. There are many other formatting options available which can be used based on the specific requirements.

    Format Specifiers in C

    The CPU performs IO operations with input and output devices in a streaming manner. The data read from a standard input device (keyboard) through the standard input stream is called stdin. Similarly, the data sent to the standard output (computer display screen) through the standard output device is called stdout.

    The computer receives data from the stream in a text form, however you may want to parse it in variables of different data types such as int, float or a string. Similarly, the data stored in int, float or char variables has to be sent to the output stream in a text format. The format specifier symbols are used exactly for this purpose.

    ANSI C defines a number of format specifiers. The following table lists the different specifiers and their purpose.

    Format SpecifierType
    %cCharacter
    %dSigned integer
    %e or %EScientific notation of floats
    %fFloat values
    %g or %GSimilar as %e or %E
    %hiSigned integer (short)
    %huUnsigned Integer (short)
    %iUnsigned integer
    %l or %ld or %liLong
    %lfDouble
    %LfLong double
    %luUnsigned int or unsigned long
    %lli or %lldLong long
    %lluUnsigned long long
    %oOctal representation
    %pPointer
    %sString
    %uUnsigned int
    %x or %XHexadecimal representation

    minus sign () signifies left alignment. A number after "%" specifies the minimum field width. If a string is less than the width, it will be filled with spaces. A period (.) is used to separate field width and precision.

    Example

    The following example demonstrates the importance of format specifiers −

    #include <stdio.h>intmain(){char str[100];printf("Enter a value: ");gets(str);printf("\nYou entered: ");puts(str);return0;}

    Output

    When the above code is compiled and executed, it waits for you to input some text. When you enter a text and press the Enter button, the program proceeds and reads the input and displays it as follows −

    Enter a value: seven 7
    You entered: seven 7
    

    Here, it should be noted that the scanf() function expects the input in the same format as you provided "%s" and "%d", which means you have to provide valid inputs like "a string followed by an integer". If you provide two consecutive strings "string string" or two consecutive integers "integer integer", then it will be assumed as an incorrect set of input.

    Secondly, while reading a string, the scanf() function stops reading as soon as it encounters a "space", so the string "This is Test" is actually a set of three strings for the scanf() function.

  • File Handling

    File Handling in C

    File handling in C is the process of handling file operations such as creating, opening, writing data, reading data, renaming, and deleting using the C language functions. With the help of these functions, we can perform file operations to store and retrieve the data in/from the file in our program.

    Need of File Handling in C

    If we perform input and output operations using the C program, the data exists as long as the program is running, when the program is terminated, we cannot use that data again. File handling is required to work with files stored in the external memory i.e., to store and access the information to/from the computer’s external memory. You can keep the data permanently using file handling.

    Types of Files

    A file represents a sequence of bytes. There are two types of files: text files and binary files −

    1. Text file − A text file contains data in the form of ASCII characters and is generally used to store a stream of characters. Each line in a text file ends with a new line character (“\n”), and generally has a “.txt” extension.
    2. Binary file − A binary file contains data in raw bits (0 and 1). Different application programs have different ways to represent bits and bytes and use different file formats. The image files (.png, .jpg), the executable files (.exe, .com), etc. are the examples of binary files.

    FILE Pointer (File*)

    While working with file handling, you need a file pointer to store the reference of the FILE structure returned by the fopen() function. The file pointer is required for all file-handling operations.

    The fopen() function returns a pointer of the FILE type. FILE is a predefined struct type in stdio.h and contains attributes such as the file descriptor, size, and position, etc.

    typedefstruct{int fd;/* File descriptor */unsignedchar*buf;/* Buffer */size_t size;/* Size of the file */size_t pos;/* Current position in the file */} FILE;

    Declaring a File Pointer (FILE*)

    Below is the syntax to declare a file pointer −

    FILE* file_pointer;

    Opening (Creating) a File

    A file must be opened to perform any operation. The fopen() function is used to create a new file or open an existing file. You need to specify the mode in which you want to open. There are various file opening modes explained below, any one of them can be used during creating/opening a file.

    The fopen() function returns a FILE pointer which will be used for other operations such as reading, writing, and closing the files.

    Syntax

    Below is the syntax to open a file −

    FILE *fopen(constchar*filename,constchar*mode);

    Here, filename is the name of the file to be opened, and mode defines the file’s opening mode.

    File Opening Modes

    The file access modes by default open the file in the text or ASCII mode. If you are going to handle binary files, then you will use the following access modes instead of the above-mentioned ones:

    "rb","wb","ab","rb+","r+b","wb+","w+b","ab+","a+b"

    There are various modes in which a file can be opened. The following are the different file opening modes −

    ModeDescription
    rOpens an existing text file for reading purposes.
    wOpens a text file for writing. If it does not exist, then a new file is created. Here your program will start writing content from the beginning of the file.
    aOpens a text file for writing in appending mode. If it does not exist, then a new file is created. Here your program will start appending content in the existing file content.
    r+Opens a text file for both reading and writing.
    Opens a text file for both reading and writing. It first truncates the file to zero length if it exists, otherwise creates a file if it does not exist.
    a+Opens a text file for both reading and writing. It creates the file if it does not exist. The reading will start from the beginning but writing can only be appended.

    Example of Creating a File

    In the following example, we are creating a new file. The file mode to create a new file will be “w” (write-mode).

    #include <stdio.h>intmain(){
      FILE * file;// Creating a file
      file =fopen("file1.txt","w");// Checking whether file is // created or notif(file ==NULL){printf("Error in creating file");return1;}printf("File created.");return0;}

    Output

    File created.
    

    Example of Opening a File

    In the following example, we are opening an existing file. The file mode to open an existing file will be “r” (read-only). You may also use other file opening mode options explained above.

    Note: There must be a file to be opened.

    #include <stdio.h>intmain(){
      FILE * file;// Opening a file
      file =fopen("file1.txt","r");// Checking whether file is // opened or not if(file ==NULL){printf("Error in opening file");return1;}printf("File opened.");return0;}

    Output

    File opened.
    

    Closing a File

    Each file must be closed after performing operations on it. The fclose() function closes an opened file.

    Syntax

    Below is the syntax of fclose() function −

    intfclose(FILE *fp);

    The fclose() function returns zero on success, or EOF if there is an error in closing the file.

    The fclose() function actually flushes any data still pending in the buffer to the file, closes the file, and releases any memory used for the file. The EOF is a constant defined in the header file stdio.h.

    Example of Closing a File

    In the following example, we are closing an opened file −

    #include <stdio.h>intmain(){
      FILE * file;// Opening a file
      file =fopen("file1.txt","w");// Checking whether file is // opened or not if(file ==NULL){printf("Error in opening file");return1;}printf("File opened.");// Closing the filefclose(file);printf("\nFile closed.");return0;}

    Output

    File opened.
    File closed.
    

    Writing to a Text File

    The following library functions are provided to write data in a file opened in writeable mode −

    • fputc() : Writes a single character to a file.
    • fputs(): Writes a string to a file.
    • fprintf(): Writes a formatted string (data) to a file.

    Writing Single Character to a File

    The fputc() function is an unformatted function that writes a single character value of the argument “c” to the output stream referenced by “fp“.

    intfputc(int c, FILE *fp);

    Example

    In the following code, one character from a given char array is written into a file opened in the “w” mode:

    #include <stdio.h>intmain(){
    
       FILE *fp;char* string ="C Programming tutorial from TutorialsPoint";int i;char ch;
    
       fp =fopen("file1.txt","w");for(i =0; i <strlen(string); i++){
    
      ch = string&#91;i];if(ch ==EOF)break;fputc(ch, fp);}printf("\n");fclose(fp);return0;}</code></pre>

    Output

    After executing the program, "file1.txt" will be created in the current folder and the string is written to it.
    

    Writing String to a File

    The fputs() function writes the string "s" to the output stream referenced by "fp". It returns a non-negative value on success, else EOF is returned in case of any error.

    intfputs(constchar*s, FILE *fp);

    Example

    The following program writes strings from the given two-dimensional char array to a file −

    #include <stdio.h>intmain(){
    
       FILE *fp;char*sub[]={"C Programming Tutorial\n","C++ Tutorial\n","Python Tutorial\n","Java Tutorial\n"};
       fp =fopen("file2.txt","w");for(int i =0; i <4; i++){fputs(sub[i], fp);}fclose(fp);return0;}

    Output

    When the program is run, a file named "file2.txt" is created in the current folder and save the following lines −

    C Programming Tutorial
    C++ Tutorial
    Python Tutorial
    Java Tutorial
    

    Writing Formatted String to a File

    The fprintf() function sends a formatted stream of data to the disk file represented by the FILE pointer.

    intfprintf(FILE *stream,constchar*format [, argument,...])

    Example

    In the following program, we have an array of struct type called "employee". The structure has a string, an integer, and a float element. Using the fprintf() function, the data is written to a file.

    #include <stdio.h>structemployee{int age;float percent;char*name;};intmain(){
    
       FILE *fp;structemployee emp[]={{25,65.5,"Ravi"},{21,75.5,"Roshan"},{24,60.5,"Reena"}};char*string;
       fp =fopen("file3.txt","w");for(int i =0; i <3; i++){fprintf(fp,"%d %f %s\n", emp[i].age, emp[i].percent, emp[i].name);}fclose(fp);return0;}

    Output

    When the above program is executed, a text file is created with the name "file3.txt" that stores the employee data from the struct array.
    

    Reading from a Text File

    The following library functions are provided to read data from a file that is opened in read mode −

    • fgetc(): Reads a single character from a file.
    • fgets(): Reads a string from a file.
    • fscanf(): Reads a formatted string from a file.

    Reading Single Character from a File

    The fgetc() function reads a character from the input file referenced by "fp". The return value is the character read, or in case of any error, it returns EOF.

    intfgetc(FILE * fp);

    Example

    The following example reads the given file in a character by character manner till it reaches the end of file.

    #include <stdio.h>intmain(){
    
       FILE *fp ;char ch ;
       fp =fopen("file1.txt","r");while(1){
    
      ch =fgetc(fp);if(ch ==EOF)break;printf("%c", ch);}printf("\n");fclose(fp);}</code></pre>

    Output

    Run the code and check its output −

    C Programming tutorial from TutorialsPoint
    

    Reading String from a File

    The fgets() function reads up to "n 1" characters from the input stream referenced by "fp". It copies the read string into the buffer "buf", appending a null character to terminate the string.

    Example

    This following program reads each line in the given file till the end of the file is detected −

    # include <stdio.h>intmain(){
    
       FILE *fp;char*string;
       fp =fopen("file2.txt","r");while(!feof(fp)){fgets(string,256, fp);printf("%s", string);}fclose(fp);}

    Output

    Run the code and check its output −

    C Programming Tutorial
    C++ Tutorial
    Python Tutorial
    Java Tutorial
    

    Reading Formatted String from a File

    The fscanf() function in C programming language is used to read formatted input from a file.

    intfscanf(FILE *stream,constchar*format,...)

    Example

    In the following program, we use the fscanf() function to read the formatted data in different types of variables. Usual format specifiers are used to indicate the field types (%d, %f, %s, etc.)

    #include <stdio.h>intmain(){
    
       FILE *fp;char*s;int i, a;float p;
    
       fp =fopen("file3.txt","r");if(fp ==NULL){puts("Cannot open file");return0;}while(fscanf(fp,"%d %f %s",&a,&p, s)!=EOF)printf("Name: %s Age: %d Percent: %f\n", s, a, p);fclose(fp);return0;}

    Output

    When the above program is executed, it opens the text file "file3.txt" and prints its contents on the screen. After running the code, you will get an output like this −

    Name: Ravi Age: 25 Percent: 65.500000
    Name: Roshan Age: 21 Percent: 75.500000
    Name: Reena Age: 24 Percent: 60.500000
    

    File Handing Binary Read and Write Functions

    The read/write operations are done in a binary form in the case of a binary file. You need to include the character "b" in the access mode ("wb" for writing a binary file, "rb" for reading a binary file).

    There are two functions that can be used for binary input and output: the fread() function and the fwrite() function. Both of these functions should be used to read or write blocks of memories, usually arrays or structures.

    Writing to Binary File

    The fwrite() function writes a specified chunk of bytes from a buffer to a file opened in binary write mode. Here is the prototype to use this function:

    fwrite(*buffer, size, no, FILE);

    Example

    In the following program, an array of a struct type called "employee" has been declared. We use the fwrite() function to write one block of byte, equivalent to the size of one employee data, in a file that is opened in "wb" mode.

    #include <stdio.h>structemployee{int age;float percent;char name[10];};intmain(){
    
       FILE *fp;structemployee e[]={{25,65.5,"Ravi"},{21,75.5,"Roshan"},{24,60.5,"Reena"}};char*string;
    
       fp =fopen("file4.dat","wb");for(int i =0; i <3; i++){fwrite(&e[i],sizeof(structemployee),1, fp);}fclose(fp);return0;}

    Output

    When the above program is run, the given file will be created in the current folder. It will not show the actual data, because the file is in binary mode.
    

    Reading from Binary File

    The fread() function reads a specified chunk of bytes from a file opened in binary read mode to a buffer of the specified size. Here is the prototype to use this function:

    fread(*buffer, size, no, FILE);

    Example

    In the following program, an array of a struct type called "employee" has been declared. We use the fread() function to read one block of byte, equivalent to the size of one employee data, in a file that is opened in "rb" mode.

    #include <stdio.h>structemployee{int age;float percent;char name[10];};intmain(){
    
       FILE *fp;structemployee e;
    
       fp =fopen("file4.dat","rb");if(fp ==NULL){puts("Cannot open file");return0;}while(fread(&e,sizeof(structemployee),1, fp)==1)printf("Name: %s Age: %d Percent: %f\n", e.name, e.age, e.percent);fclose(fp);return0;}

    Output

    When the above program is executed, it opens the file "file4.dat" and prints its contents on the screen. After running the code, you will get an output like this −

    Name: Ravi Age: 25 Percent: 65.500000
    Name: Roshan Age: 21 Percent: 75.500000
    Name: Reena Age: 24 Percent: 60.500000
    

    Renaming a File

    The rename() function is used to rename an existing file from an old file name to a new file name.

    Syntax

    Below is the syntax to rename a file −

    intrename(constchar*old_filename,constchar*new_filename)

    Example

    #include <stdio.h>intmain(){// old and new file nameschar* file_name1 ="file1.txt";char* file_name2 ="file2.txt";// Renaming old file name to new oneif(rename(file_name1, file_name2)==0){printf("File renamed successfully.\n");}else{perror("There is an error.");}return0;}

    Output

    If there is a file (file1.txt) available, the following will be the output −

    Name: Ravi Age: 25 Percent: 65.500000
    Name: Roshan Age: 21 Percent: 75.500000
    Name: Reena Age: 24 Percent: 60.500000
    
  • Memory Leaks

    Memory leaks take place when the memory allocated to variables is not deallocated after their use. The allocated memory is no longer in use by the program, but the space remains reserved for no reason. That’s why it is called a memory leak.

    In a memory leak, some blocks of memory may be wasted. Memory leaks can slow down the system performance, even when the system has enough memory.

    In C programming, memory is allocated using the malloc() / calloc() methods and released using the free() method. Let us understand by example how memory leaks occur −

    Example: Memory Leak in C

    In this example, we are allocating the size of the variable but not deallocating the space after its use, so it may cause a memory leak −

    #include <stdio.h>#include <stdlib.h>	intmain(){// allocate memoryint*ptr =(int*)malloc(sizeof(int));*ptr =100;printf("%d\n",*ptr);// we are just allocating the memory// not deallocatingreturn0;}

    The code will work as expected, but without freeing the allocated memory, it causes a memory leak. Given below is the output of the code −

    100
    

    Causes of Memory Leaks

    C allows programmers to allocate memory during program execution using functions from the stdlib.h library, such as malloc() (allocate a block of memory), calloc() (allocate zero-initialized memory), and realloc() (resize an allocated block). This memory is allocated on the heap. If the allocated memory is not released when no longer needed, it remains reserved unnecessarily, even after the program has finished using it.

    Following are the prime causes that can result in memory leaks −

    • Memory is allocated but not released or deallocated.
    • If a pointer to allocated memory is overwritten or goes out of scope without being freed, the memory it points to becomes unreachable.
    • In long-running programs, even small memory leaks can accumulate over time, gradually consuming system memory and eventually slowing down or crashing the program.

    Example: Memory Leak in C Using calloc()

    In this example, we are allocating memory using the calloc() function, but we are not freeing the memory, which causes a memory leak −

    #include <stdio.h>#include <stdlib.h>intmain(){int*ptr;// Allocate memory for 5 integers using calloc
       ptr =(int*)calloc(5,sizeof(int));if(ptr ==NULL){printf("Memory allocation failed.\n");return1;}// Use the allocated memoryfor(int i =0; i <5; i++){
    
      ptr&#91;i]= i +1;printf("%d ", ptr&#91;i]);}printf("\n");// This line is intentionally commented to // create a memory leak// free(ptr);     return0;}</code></pre>

    When you run this code, it will produce the following output −

    1 2 3 4 5
    

    How to Prevent Memory Leaks

    Following are the ways to prevent memory leaks −

    • Always free/deallocate the memory after use.
    • Do not overwrite the pointer before freeing its old memory.
    • Unlike C++, C does not have smart pointers, so memory must be explicitly freed using the free() function.
    • We can use tools like Valgrind in C to detect memory leaks during testing.

    To prevent memory leaks, we use the free() function. It deallocates the allocated memory and helps avoid memory leaks.

    Example: Preventing Memory Leaks

    In this example, we use the free() function to prevent memory leak −

    #include <stdio.h>#include <stdlib.h>intmain(){// allocate memoryint*ptr =(int*)malloc(sizeof(int));*ptr =100;printf("%d\n",*ptr);// free allocated memoryfree(ptr);return0;}

    Following is the output of the above code −

    100
    

    Conclusion

    Memory leaks take place when a program allocates memory to its variables and fuctions but does not free/deallocate the memory after its use. Over time, unused memory occupies space and becomes wasted, which can slow down the program or even cause it to crash. Proper memory management is important to prevent these issues.