C PDF
C PDF
Pointers in C are used to store the address of variables or a memory location. This
variable can be of any data type i.e, int, char, function, array, or any other pointer. The
size of the pointer depends on the architecture.
Syntax:
datatype *var_name;
Example:
C
// C program to illustrate Pointers
#include <stdio.h>
void geeks()
{
int var = 20;
// Driver program
int main()
{
geeks();
return 0;
}
Output
C Pointers Application
C
// C program to demonstrate that we can change
// local values of one function in another using pointers.
#include <stdio.h>
int main()
{
int x = 10, y = 20;
swap(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
Output :
20 10
(ii) For efficiency purpose. Example passing large structure without reference would
create a copy of the structure (hence wastage of space).
2. For accessing array elements. Compiler internally uses pointers to access array
elements.
C
// C program to demonstrate that we can change
// local values of one function in another using pointers.
#include <stdio.h>
int main()
{
int x = 10, y = 20;
swap(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
Output :
20 10
(ii) For efficiency purpose. Example passing large structure without reference would
create a copy of the structure (hence wastage of space).
3. For accessing array elements. Compiler internally uses pointers to access array
elements.
C
// C program to demonstrate that compiler
// internally uses pointer arithmetic to access
// array elements.
#include <stdio.h>
int main()
{
int arr[] = { 100, 200, 300, 400 };
return 0;
}
Output :
300 300
4. To return multiple values. Example returning square and square root of numbers.
C
// C program to demonstrate that using a pointer
// we can return multiple values.
#include <math.h>
#include <stdio.h>
int main()
{
int n = 100;
int sq;
double sq_root;
fun(n, &sq, &sq_root);
Output :
10000 10
C
// C program to dynamically allocate an
// array of given size.
#include <stdio.h>
#include <stdlib.h>
int* createArr(int n)
{
int* arr = (int*)(malloc(n * sizeof(int)));
return arr;
}
int main()
{
int* pt = createArr(10);
return 0;
}
C Function Pointers
In C, like normal data pointers (int *, char *, etc), we can have pointers to functions.
Following is a simple example that shows declaration and function call using function
pointer.
C
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
return 0;
}
Output:
Value of a is 10
Why do we need an extra bracket around function pointers like fun_ptr in above example?
If we remove bracket, then the expression “void (*fun_ptr)(int)” becomes “void
*fun_ptr(int)” which is declaration of a function that returns void pointer.
1) Unlike normal pointers, a function pointer points to code, not data. Typically a function
pointer stores the start of executable code.
3) A function’s name can also be used to get functions’ address. For example, in the below
program, we have removed address operator ‘&’ in assignment. We have also changed
function call by removing *, the program still works.
C
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
void (*fun_ptr)(int) = fun; // & removed
fun_ptr(10); // * removed
return 0;
}
Output:
Value of a is 10
4) Like normal pointers, we can have an array of function pointers. Below example in
point 5 shows syntax for array of pointers.
5) Function pointer can be used in place of switch case. For example, in below program,
user is asked for a choice between 0 and 2 to do different tasks.
C
#include <stdio.h>
void add(int a, int b)
{
printf("Addition is %d\n", a+b);
}
void subtract(int a, int b)
{
printf("Subtraction is %d\n", a-b);
}
void multiply(int a, int b)
{
printf("Multiplication is %d\n", a*b);
}
int main()
{
// fun_ptr_arr is an array of function pointers
void (*fun_ptr_arr[])(int, int) = {add, subtract, multiply};
unsigned int ch, a = 15, b = 10;
printf("Enter Choice: 0 for add, 1 for subtract and 2 "
"for multiply\n");
scanf("%d", &ch);
(*fun_ptr_arr[ch])(a, b);
return 0;
}
Output
6) Like normal data pointers, a function pointer can be passed as an argument and can
also be returned from a function.
For example, consider the following C program where wrapper() receives a void fun() as
parameter and calls the passed function.
C
// A simple C program to show function pointers as parameter
#include <stdio.h>
int main()
{
wrapper(fun1);
wrapper(fun2);
return 0;
}
This point in particular is very useful in C. In C, we can use function pointers to avoid code
redundancy. For example a simple qsort() function can be used to sort arrays in
ascending order or descending or by any other order in case of array of structures. Not
only this, with function pointers and void pointers, it is possible to use qsort for any data
type.
C
// An example for qsort and comparator
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int arr[] = {10, 5, 15, 12, 90, 80};
int n = sizeof(arr)/sizeof(arr[0]), i;
Output:
5 10 12 15 80 90
7) Many object oriented features in C++ are implemented using function pointers in C.
For example virtual functions. Class methods are another example implemented using
function pointers.
C NULL Pointers
At a very high level, we can think of NULL as a null pointer which is used in C for various
purposes. Some of the most common use cases for NULL are:
a) To initialize a pointer variable when that pointer variable hasn’t been assigned any
valid memory address yet.
Example:
C
int * pInt = NULL;
b) To check for a null pointer before accessing any pointer variable. By doing so, we can
perform error handling in pointer related code, e.g., dereference a pointer variable only
if it’s not NULL.
Example:
C
if(pInt != NULL) /*We could use if(pInt) as well*/
{ /*Some code*/}
else
{ /*Some code*/}
c) To pass a null pointer to a function argument when we don’t want to pass any valid
memory address.
Example:
C
int fun(int *ptr)
{
/*Fun specific stuff is done with ptr here*/
return 10;
}
fun(NULL);
C
#include <stdio.h>
int main()
{
int *i, *j;
int *ii = NULL, *jj = NULL;
if(i == j)
{
printf("This might get printed if both i and j are same by
chance.");
}
if(ii == jj)
{
printf("This is always printed coz ii and jj are same.");
}
return 0;
}
“An integer constant expression with the value 0, or such an expression cast to type void *,
is called a null pointer constant. If a null pointer constant is converted to a pointer type, the
resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to
any object or function.”
Before we proceed further on this NULL discussion :), let’s mention a few lines about C
standard just in case you want to refer to it for further study. Please note that ISO/IEC
9899:2011 is the C language’s latest standard which was published in Dec 2011. This is
also called the C11 standard. For completeness, let us mention that the previous C
standards were C99, C90 (also known as ISO C) and C89 (also known as ANSI C). Though
the actual C11 standard can be purchased from ISO, there’s a draft document which is
available in public domains for free.
Coming back to our discussion, the NULL macro is defined as ((void *)0) in the header
files of most of the C compiler implementations. But, C standard is saying that 0 is also a
null pointer constant. It means that the following is also perfectly legal as per standard:
C
int * ptr = 0;
Please note that 0 in the above C statement is used in pointer-context and it’s different
from 0 as integer. This is one of the reasons why the usage of NULL is preferred because
it makes it explicit in the code that the programmer is using a null pointer, not integer 0.
C Void Pointer
A void pointer is a pointer that has no associated data type with it. A void pointer can hold
address of any type and can be typecasted to any type.
C
int a = 10;
char b = 'x';
void *p = &a; // void pointer holds address of int 'a'
p = &b; // void pointer holds address of char 'b'
1) malloc() and calloc() return void * type and this allows these functions to be used to
allocate memory of any data type (just because of void *)
Note that the above program compiles in C, but doesn’t compile in C++. In C++, we must
explicitly typecast return value of malloc to (int *).
2) void pointers in C are used to implement generic functions in C. For example compare
function which is used in qsort().
1) void pointers cannot be dereferenced. For example the following program doesn’t
compile.
C
#include <stdio.h>
int main()
{
int a = 10;
void *ptr = &a;
printf("%d", *ptr);
return 0;
}
Output:
C
#include <stdio.h>
int main()
{
int a = 10;
void *ptr = &a;
printf("%d", *(int *)ptr);
return 0;
}
Output:
10
2) The C standard doesn’t allow pointer arithmetic with void pointers. However, in GNU
C it is allowed by considering the size of void is 1. For example the following program
compiles and runs fine in gcc.
C
#include<stdio.h>
int main()
{
int a[2] = {1, 2};
void *ptr = &a;
ptr = ptr + sizeof(int);
printf("%d", *(int *)ptr);
return 0;
}
Output:
2
1. Text Segment: A text segment, also known as a code segment or simply as text, is one
of the sections of a program in an object file or in memory, which contains executable
instructions.
As a memory region, a text segment may be placed below the heap or stack in order to
prevent heaps and stack overflows from overwriting it.
Usually, the text segment is sharable so that only a single copy needs to be in memory for
frequently executed programs, such as text editors, the C compiler, the shells, and so on.
Also, the text segment is often read-only, to prevent a program from accidentally
modifying its instructions.
2. Initialized Data Segment: Initialized data segment, usually called simply the Data
Segment. A data segment is a portion of the virtual address space of a program, which
contains the global variables and static variables that are initialized by the programmer.
Note that, the data segment is not read-only, since the values of the variables can be
altered at run time.
This segment can be further classified into the initialized read-only area and the
initialized read-write area.
For instance, the global string defined by char s[] = “hello world” in C and a C statement
like int debug=1 outside the main (i.e. global) would be stored in the initialized read-write
area. And a global C statement like const char* string = “hello world” makes the string
literal “hello world” to be stored in the initialized read-only area and the character
pointer variable string in the initialized read-write area.
Ex: static int i = 10 will be stored in the data segment and global int i = 10 will also be
stored in data segment
3. Uninitialized Data Segment: Uninitialized data segment often called the “bss”
segment, named after an ancient assembler operator that stood for “block started by
symbol.” Data in this segment is initialized by the kernel to arithmetic 0 before the
program starts executing uninitialized data starts at the end of the data segment and
contains all global variables and static variables that are initialized to zero or do not have
explicit initialization in source code.
For instance, a variable declared static int i; would be contained in the BSS segment.
For instance, a global variable declared int j; would be contained in the BSS segment.
4. Stack: The stack area traditionally adjoined the heap area and grew in the opposite
direction; when the stack pointer met the heap pointer, free memory was exhausted.
(With modern large address spaces and virtual memory techniques they may be placed
almost anywhere, but they still typically grow in opposite directions.)
The stack area contains the program stack, a LIFO structure, typically located in the
higher parts of memory. On the standard PC x86 computer architecture, it grows toward
address zero; on some other architectures, it grows in the opposite direction. A “stack
pointer” register tracks the top of the stack; it is adjusted each time a value is “pushed”
onto the stack. The set of values pushed for one function call is termed a “stack frame”; A
stack frame consists at minimum of a return address.
Stack, where automatic variables are stored, along with information that is saved each
time a function is called. Each time a function is called, the address of where to return to
and certain information about the caller’s environment, such as some of the machine
registers, are saved on the stack. The newly called function then allocates room on the
stack for its automatic variables. This is how recursive functions in C can work. Each time
a recursive function calls itself, a new stack frame is used, so one set of variables doesn’t
interfere with the variables from another instance of the function.
5. Heap: Heap is the segment where dynamic memory allocation usually takes place.
The heap area begins at the end of the BSS segment and grows to larger addresses from
there. The Heap area is managed by malloc, realloc, and free, which may use the brk and
sbrk system calls to adjust its size (note that the use of brk/sbrk and a single “heap area”
is not required to fulfill the contract of malloc/realloc/free; they may also be
implemented using mmap to reserve potentially non-contiguous regions of virtual
memory into the process’ virtual address space). The Heap area is shared by all shared
libraries and dynamically loaded modules in a process.
Examples:
The size(1) command reports the sizes (in bytes) of the text, data, and bss segments. ( for
more details please refer man page of size(1) )
int main(void)
{
return 0;
}
2. Let us add one global variable in the program, now check the size of bss (highlighted in
red color).
C
#include <stdio.h>
int main(void)
{
return 0;
}
C
#include <stdio.h>
int main(void)
{
static int i; /* Uninitialized static variable stored in bss
*/
return 0;
}
4. Let us initialize the static variable which will then be stored in the Data Segment (DS)
C
#include <stdio.h>
int main(void)
{
static int i = 100; /* Initialized static variable stored in
DS*/
return 0;
}
5. Let us initialize the global variable which will then be stored in the Data Segment (DS)
C
#include <stdio.h>
int main(void)
{
static int i = 100; /* Initialized static variable stored in
DS*/
return 0;
}
C Memory Leak
Memory leak occurs when programmers create a memory in heap and forget to delete it.
The consequences of memory leak is that it reduces the performance of the computer by
reducing the amount of available memory. Eventually, in the worst case, too much of the
available memory may become allocated and all or part of the system or device stops
working correctly, the application fails, or the system slows down vastly .
Memory leaks are particularly serious issues for programs like daemons and servers
which by definition never terminate.
C
/* Function with memory leak */
#include <stdlib.h>
void f()
{
int *ptr = (int *) malloc(sizeof(int));
/* Do some work */
C
/* Function without memory leak */
#include <stdlib.h>
void f()
{
int *ptr = (int *) malloc(sizeof(int));
/* Do some work */
free(ptr);
return;
}
C
// C Program to check whether the memory is
// freed or not
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* ptr;
ptr = (int*) malloc(sizeof(int));
if (ptr == NULL)
printf("Memory Is Insuffficient\n");
else
{
free(ptr);
printf("Memory Freed\n");
}
}
Output
Memory Freed
C Struct
A structure is a key word that create user defined data type in C/C++. A structure creates
a data type that can be used to group items of possibly different types into a single type.
C
struct address
{
char name[50];
char street[100];
char city[50];
char state[20];
int pin;
};
How to declare structure variables?
A structure variable can either be declared with structure declaration or as a separate
declaration like basic types.
C
// A variable declaration with structure declaration.
struct Point
{
int x, y;
} p1; // The variable p1 is declared with 'Point'
int main()
{
struct Point p1; // The variable p1 is declared like a normal
variable
}
Structure members cannot be initialized with declaration. For example the following C
program fails in compilation.
C
struct Point
{
int x = 0; // COMPILER ERROR: cannot initialize members here
int y = 0; // COMPILER ERROR: cannot initialize members here
};
The reason for above error is simple, when a datatype is declared, no memory is allocated
for it. Memory is allocated only when variables are created.
Structure members can be initialized using curly braces ‘{}’. For example, following is a
valid initialization.
C
struct Point
{
int x, y;
};
int main()
{
// A valid initialization. member x gets value 0 and y
// gets value 1. The order of declaration is followed.
struct Point p1 = {0, 1};
}
C
#include<stdio.h>
struct Point
{
int x, y;
};
int main()
{
struct Point p1 = {0, 1};
// Accessing members of point p1
p1.x = 20;
printf ("x = %d, y = %d", p1.x, p1.y);
return 0;
}
Output:
x = 20, y = 1
C
#include<stdio.h>
struct Point
{
int x, y, z;
};
int main()
{
// Examples of initialization using designated initialization
struct Point p1 = {.y = 0, .z = 1, .x = 2};
struct Point p2 = {.x = 20};
Output:
x = 2, y = 0, z = 1
x = 20
C
#include<stdio.h>
struct Point
{
int x, y;
};
int main()
{
// Create an array of structures
struct Point arr[10];
Output:
10 20
What is a structure pointer?
Like primitive types, we can have pointer to a structure. If we have a pointer to structure,
members are accessed using arrow ( -> ) operator.
C
#include<stdio.h>
struct Point
{
int x, y;
};
int main()
{
struct Point p1 = {1, 2};
// p2 is a pointer to structure p1
struct Point *p2 = &p1;
Output:
1 2
C Structure Alignment
Every data type in C/C++ will have alignment requirement (infact it is mandated by
processor architecture, not by language). A processor will have processing word length
as that of data bus size. On a 32 bit machine, the processing word size will be 4 bytes.
Historically memory is byte addressable and arranged sequentially. If the memory is
arranged as single bank of one byte width, the processor needs to issue 4 memory read
cycles to fetch an integer. It is more economical to read all 4 bytes of integer in one
memory cycle. To take such advantage, the memory will be arranged as group of 4 banks
as shown in the above figure.
The memory addressing still be sequential. If bank 0 occupies an address X, bank 1, bank
2 and bank 3 will be at (X + 1), (X + 2) and (X + 3) addresses. If an integer of 4 bytes is
allocated on X address (X is multiple of 4), the processor needs only one memory cycle to
read entire integer.
Where as, if the integer is allocated at an address other than multiple of 4, it spans across
two rows of the banks as shown in the below figure. Such an integer requires two memory
read cycle to fetch the data.
A variable’s data alignment deals with the way the data stored in these banks. For
example, the natural alignment of int on 32-bit machine is 4 bytes. When a data type is
naturally aligned, the CPU fetches it in minimum read cycles.
Similarly, the natural alignment of short int is 2 bytes. It means, a short int can be stored
in bank 0 – bank 1 pair or bank 2 – bank 3 pair. A double requires 8 bytes, and occupies
two rows in the memory banks. Any misalignment of double will force more than two
read cycles to fetch double data.
Note that a double variable will be allocated on 8 byte boundary on 32 bit machine and
requires two memory read cycles. On a 64 bit machine, based on number of
banks, double variable will be allocated on 8 byte boundary and requires only one
memory read cycle.
C Union
Like Structures, union is a user defined data type. In union, all members share the same
memory location.
For example in the following C program, both x and y share the same location. If we
change x, we can see the changes being reflected in y.
C
#include <stdio.h>
int main()
{
// A union variable t
union test t;
Output:
After making x = 2:
x = 2, y = 2
C
#include <stdio.h>
union test1 {
int x;
int y;
} Test1;
union test2 {
int x;
char y;
} Test2;
union test3 {
int arr[10];
char y;
} Test3;
int main()
{
printf("sizeof(test1) = %lu, sizeof(test2) = %lu, "
"sizeof(test3) = %lu",
sizeof(Test1),
sizeof(Test2), sizeof(Test3));
return 0;
}
Output:
Pointers to unions?
Like structures, we can have pointers to unions and can access members using the arrow
operator (->). The following example demonstrates the same.
C
#include <stdio.h>
union test {
int x;
char y;
};
int main()
{
union test p1;
p1.x = 65;
// p2 is a pointer to union p1
union test* p2 = &p1;
Output:
65 A
C Applications of Union
Unions can be useful in many situations where we want to use the same memory for two
or more members. For example, suppose we want to implement a binary tree data
structure where each leaf node has a double data value, while each internal node has
pointers to two children, but no data. If we declare this as:
C
struct NODE {
struct NODE* left;
struct NODE* right;
double data;
};
then every node requires 16 bytes, with half the bytes wasted for each type of node. On
the other hand, if we declare a node as following, then we can save space.
C
struct NODE {
bool is_leaf;
union {
struct
{
struct NODE* left;
struct NODE* right;
} internal;
double data;
} info;
};
C Function Pointers
In C, like normal data pointers (int *, char *, etc), we can have pointers to functions.
Following is a simple example that shows declaration and function call using function
pointer.
C
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
// fun_ptr is a pointer to function fun()
void (*fun_ptr)(int) = &fun;
return 0;
}
Output:
Value of a is 10
Why do we need an extra bracket around function pointers like fun_ptr in above example?
If we remove bracket, then the expression “void (*fun_ptr)(int)” becomes “void
*fun_ptr(int)” which is declaration of a function that returns void pointer.
1) Unlike normal pointers, a function pointer points to code, not data. Typically a function
pointer stores the start of executable code.
C
#include <stdio.h>
// A normal function with an int parameter
// and void return type
void fun(int a)
{
printf("Value of a is %d\n", a);
}
int main()
{
void (*fun_ptr)(int) = fun; // & removed
fun_ptr(10); // * removed
return 0;
}
Output:
Value of a is 10
4) Like normal pointers, we can have an array of function pointers. Below example in
point 5 shows syntax for array of pointers.
5) Function pointer can be used in place of switch case. For example, in below program,
user is asked for a choice between 0 and 2 to do different tasks.
C
#include <stdio.h>
void add(int a, int b)
{
printf("Addition is %d\n", a+b);
}
void subtract(int a, int b)
{
printf("Subtraction is %d\n", a-b);
}
void multiply(int a, int b)
{
printf("Multiplication is %d\n", a*b);
}
int main()
{
// fun_ptr_arr is an array of function pointers
void (*fun_ptr_arr[])(int, int) = {add, subtract, multiply};
unsigned int ch, a = 15, b = 10;
(*fun_ptr_arr[ch])(a, b);
return 0;
}
Output
6) Like normal data pointers, a function pointer can be passed as an argument and can
also be returned from a function.
For example, consider the following C program where wrapper() receives a void fun() as
parameter and calls the passed function.
C
// A simple C program to show function pointers as parameter
#include <stdio.h>
// Two simple functions
void fun1() { printf("Fun1\n"); }
void fun2() { printf("Fun2\n"); }
int main()
{
wrapper(fun1);
wrapper(fun2);
return 0;
}
This point in particular is very useful in C. In C, we can use function pointers to avoid code
redundancy. For example a simple qsort() function can be used to sort arrays in
ascending order or descending or by any other order in case of array of structures. Not
only this, with function pointers and void pointers, it is possible to use qsort for any data
type.
C
// An example for qsort and comparator
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int arr[] = {10, 5, 15, 12, 90, 80};
int n = sizeof(arr)/sizeof(arr[0]), i;
Output:
5 10 12 15 80 90
7) Many object oriented features in C++ are implemented using function pointers in C.
For example virtual functions. Class methods are another example implemented using
function pointers.
C File Handling
So far the operations using C program are done on a prompt / terminal which is not stored
anywhere. But in the software industry, most of the programs are written to store the
information fetched from the program. One such way is to store the fetched information
in a file. Different operations that can be performed on a file are:
1. Creation of a new file (fopen with attributes as “a” or “a+” or “w” or “w+”)
2. Opening an existing file (fopen)
3. Reading from file (fscanf or fgets)
4. Writing to a file (fprintf or fputs)
5. Moving to a specific location in a file (fseek, rewind)
6. Closing a file (fclose)
The text in the brackets denotes the functions used for performing those operations.
“r” – Searches file. If the file is opened successfully fopen( ) loads it into memory
and sets up a pointer which points to the first character in it. If the file cannot be
opened fopen( ) returns NULL.
“rb” – Open for reading in binary mode. If the file does not exist, fopen( ) returns
NULL.
“w” – Searches file. If the file exists, its contents are overwritten. If the file doesn’t
exist, a new file is created. Returns NULL, if unable to open file.
“wb” – Open for writing in binary mode. If the file exists, its contents are
overwritten. If the file does not exist, it will be created.
“a” – Searches file. If the file is opened successfully fopen( ) loads it into memory
and sets up a pointer that points to the last character in it. If the file doesn’t exist,
a new file is created. Returns NULL, if unable to open file.
“ab” – Open for append in binary mode. Data is added to the end of the file. If the
file does not exist, it will be created.
“r+” – Searches file. If is opened successfully fopen( ) loads it into memory and
sets up a pointer which points to the first character in it. Returns NULL, if unable
to open the file.
“rb+” – Open for both reading and writing in binary mode. If the file does not exist,
fopen( ) returns NULL.
“w+” – Searches file. If the file exists, its contents are overwritten. If the file doesn’t
exist a new file is created. Returns NULL, if unable to open file.
“wb+” – Open for both reading and writing in binary mode. If the file exists, its
contents are overwritten. If the file does not exist, it will be created.
“a+” – Searches file. If the file is opened successfully fopen( ) loads it into memory
and sets up a pointer which points to the last character in it. If the file doesn’t exist,
a new file is created. Returns NULL, if unable to open file.
“ab+” – Open for both reading and appending in binary mode. If the file does not
exist, it will be created.
As given above, if you want to perform operations on a binary file, then you have to
append ‘b’ at the last. For example, instead of “w”, you have to use “wb”, instead of “a+”
you have to use “a+b”. For performing the operations on the file, a special pointer called
File pointer is used which is declared as
FILE *filePointer;
So, the file can be opened as
The second parameter can be changed to contain all the attributes listed in the above
table.
FILE * filePointer;
Writing a file –:
The file write operations can be performed by the functions fprintf and fputs with
similarities to read operations. The snippet for writing to a file is as :
FILE *filePointer ;
Closing a file –:
After every successful file operations, you must always close a file. For closing a
file, you have to use fclose function. The snippet for closing a file is given as :
FILE *filePointer ;
Example 1: Program to Open a File, Write in it, And Close the File
C
// C program to Open a File,
// Write in it, And Close the File
# include <stdio.h>
# include <string.h>
int main( )
{
Example 2: Program to Open a File, Read from it, And Close the File
C
// C program to Open a File,
// Read from it, And Close the File
# include <stdio.h>
# include <string.h>
int main( )
{
C programming language supports four pre-defined functions to read contents from a file,
defined in stdio.h header file:
1. fgetc()– This function is used to read a single character from the file.
2. fgets()– This function is used to read strings from files.
3. fscanf()– This function is used to read formatted input from a file.
4. fread()– This function is used to read the block of raw bytes from files. This is used to
read binary files.
Open a file using the function fopen() and store the reference of the file in a FILE pointer.
Read contents of the file using any of these functions fgetc(), fgets(), fscanf(), or fread().
File close the file using the function fclose().
fgetc()
fgetc() reads characters pointed by the function pointer at that time. On each successful
read, it returns the character (ASCII value) read from the stream and advances the read
position to the next character. This function returns a constant EOF (-1) when there is no
content to read or an unsuccessful read.
Syntax:
This program reads the whole content of the file, using this function by reading characters
one by one.
Do-While loop will be used which will read character until it reaches to the end of the file.
When it reaches end it returns EOF character (-1).
Using EOF:
Below is the C program to implement the above approach -
C
// C program to implement
// the above approach
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Driver code
int main()
{
FILE* ptr;
char ch;
if (NULL == ptr) {
printf("file can't be opened \n");
}
Input File:
Output:
In the above code, the approach is to read one character from the file and check if it is not
EOF, if it is not then print it and if it is then stop reading.
Using feof():
feof() function takes file pointer as argument and returns true if pointer reaches the end
of the file.
Syntax:
C
// C program to implement
// the above approach
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Driver code
int main()
{
FILE* ptr;
char ch;
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
printf("file can't be opened \n");
}
printf("content of this file are \n");
while (!feof(ptr)) {
ch = fgetc(ptr);
printf("%c", ch);
}
fclose(ptr);
return 0;
}
Input File:
Output:
fgets()
fgets() reads one string at a time from the file. fgets() returns a string if it is successfully
read by function or returns NULL if can not read.
Syntax:
Here,
str: It is string in which fgets() store string after reading it from file.
size: It is maximum characters to read from stream.
ptr: It is file pointer.
Approach:
In this approach, the contents of the file are read one character at a time until we reach
the end of the file.
When we reach the end of the file fgets() can’t read and returns NULL and the program
will stop reading.
// Driver code
int main()
{
FILE* ptr;
char str[50];
ptr = fopen("test.txt", "a+");
if (NULL == ptr) {
printf("file can't be opened \n");
}
fclose(ptr);
return 0;
}
Input File:
Output:
fscanf()
Syntax:
fscanf reads formatted data from the files and stores it in variables.
The data in the buffer is printed on the console till the end of the file is reached.
C
// C program to implement
// the above approach
#include <stdio.h>
// Driver code
int main()
{
FILE* ptr = fopen("abc.txt", "r");
if (ptr == NULL) {
printf("no such file.");
return 0;
}
Output:
fread()
fread() makes it easier to read blocks of data from a file. For instance, in the case of
reading a structure from the file, it becomes an easy job to read using fread.
Syntax:
ptr: This is the pointer to a block of memory with a minimum size of size*nmemb
bytes.
size: This is the size in bytes of each element to be read.
nmemb: This is the number of elements, each one with a size of size bytes.
stream: This is the pointer to a FILE object that specifies an input stream.
Approach:
It first, reads the count number of objects, each one with a size of size bytes from the given
input stream.
The total amount of bytes reads if successful is (size*count).
According to the no. of characters read, the indicator file position is incremented.
If the objects read are not trivially copy-able, then the behavior is undefined and if the
value of size or count is equal to zero, then this program will simply return 0.
C
// C program to implement
// the above approach
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structure to store
// course details
struct Course {
char cname[30];
char sdate[30];
};
// Driver code
int main()
{
FILE* of;
of = fopen("test.txt", "w");
if (of == NULL) {
fprintf(stderr,
"\nError to open the file\n");
exit(1);
}
Output:
C Writing to a File
fputs() is a function declared in stdio.h header file. It is used to write the contents of the
file. The function takes 2 arguments. The first argument is a pointer to the string which is
to be written and the second argument is the pointer of the file where the string is to be
written. It returns 1 if the write operation was successful, otherwise, it returns 0. fputs()
writes a single line of characters in a file.
Syntax-
fputs(const *char str, FILE *fp); where str is a name of char array that we write in a
file and fp is the file pointer.
Example -
C
// C program to implement
// the above approach
#include <stdio.h>
#include <string.h>
// Function to write
// string to file
// using fputs
void writeToFile(char str[])
{
// Pointer to file
FILE* fp;
// Driver Code
int main()
{
char str[20];
strcpy(str, "GeeksforGeeks");
writeToFile(str);
return 0;
}
Output-