UNIT- 5
Pointer & File Handling
Pointers in C language is a variable that stores/points the address of another variable. A Pointer in C is used to allocate memory dynamically i.e. at run time. The pointer variable might be belonging to any of the data type such as int, float, char, double, short etc. Pointer Syntax : data_type *var_name; Example : int *p; char *p; Where, * is used to denote that “p” is pointer variable and not a normal variable. Normal variable stores the value whereas pointer variable stores the address of the variable. The content of the C pointer always be a whole number i.e. address. Always C pointer is initialized to null, i.e. int *p = null. The value of null pointer is 0. & symbol is used to get the address of the variable. * symbol is used to get the value of the variable that the pointer is pointing to. If a pointer in C is assigned to NULL, it means it is pointing to nothing. Two pointers can be subtracted to know how many elements are available between these two pointers. But, Pointer addition, multiplication, division are not allowed. The size of any pointer is 2 byte (for 16 bit compiler). Example: #include <stdio.h> int main() { int *ptr, q; q = 50; /* address of q is assigned to ptr */ ptr = &q; /* display q's value using ptr variable */ printf("%d", *ptr); return 0; } 1 2 3 4 5 6 7 8 9 10 11
5.1.1 Introduction One of the vital and heavily used feature ‘C’ is pointer. Most of the other programming languages also support pointers but only few of them use it freely. Support pointers but only few of them use it freely. When we declare any variable in C language, there are three things associated with that variable. 1. Data type of variable: Data type defines the type of data that variable can hold. Data type tells compiler about the amount of memory allocate to the variable. 2. Address of Variable: Address of variable represent the exact address of memory location which is allocated to variable. 3. Value of variable: It is the value of variable which is store at the address of memory location allocated to variable. Example: int n = 5; In the above example ‘int’ is the data type which tells compiler to allocate 2 bytes of memory to variable ‘n’. Once the variable is declare compiler allocated two bytes of memory to variable ‘n’. Suppose the address of that memory location is 1020. At the address of memory location 1020 the value 5 is store. Memory map for above declaration is as follows. use of &,/and ‘*’ operator Consider the following program. #include<stdio.h> #include<conio.h> void main() { int a,b,c, printf (“Enter two numbers”); scanf (“%d%d”, & a,&b); c=a+b; printf(“/n Addition is %d”, C); printf(“/n Address of variable C is %d”, &C); getch (); } Above program is the program for addition of two numbers in ‘C’ language. In the seventh instruction of above program we used operator ‘%’ and ‘&’ ‘%d’ is the access specifier which tells compiler to take integer value as a input whereas. ‘&a’ tells compile to store the taken value at the address of variable ‘a’. In the ninth instruction compiler will print me value of ‘C’ so the output of 9th instruction is as follows. Addition is 5 [Note : considering a = 2 and b = 3] In the tenth instruction compiler will print me address of variable C. So the output of lenth instruction is as follows. Address of variable C is 1020. Now consider the following program. #include<stdio.h> #include<conio.h> void main() { int a,b,c; printf(“Enter two numbers”); scanf(“%d %d”, & a, &b); c=a+b; printf(“\n Addition is %d”,C); printf(“\n Address of variable C is %d”,&C); printf(‘\n value of variable C is %d”, *(&C)); getch(); } Now, we all are clear about the output of instruction 9 and 10. In the 11th instruction, operator *and & is used. ‘*’ operator tells compile to pickup the value which is stored at the address of variable C. So the output of 11th instruction is as follow. Value of variable C is 5 [considering a = 24 b = 3;]
5.1.2 Declaration Pointers are declare with the help of operator ‘*’. ‘*’ is known as ‘value at address’. Pointers are the variables which are used to store the address of another variable As the address of variable is always whole numbers so pointer always contains whole numbers. The declaration of pointer are as follows. Syntax : Data type * pointer Name. Example: int *I; Data type defines the type of value defined at the address of pointer variable. In the above example value at the address of ‘I’ is of type integer. Consider the following program. # include<stdio.h> # include<conio.h> void main() { int a,b,c; int *p,*q,*r; p=&a; q=&b; r=&c; printf(“Enter two numbers”); scanf(“%d%d,&a,&b); c=a + b; printf(“\n Address of variable C is %d”,&C); printf(“\n Address of variable C is %d,r); printf(“\n Address of variable r is %d”,&r); printf(“\n value of variable C is %d”,C); printf(“\n value of variable C is %d,*^); getch (); } In the above program variable ‘r’ is the integer pointer which holds the address of variable ‘C’ Case 1: In ‘printf’ statement whenever we used (“%d”,r) men me value of r is printed but ‘r’ is holding the address of variable ‘C’. so, address of variable C is copied to the value of ‘r’ and it is printed on output screen Case 2: Whenever we used (“%d”,&r) in ‘printf’ function men the address of variable ‘r’ is pointed on o/p screen. Case 3: When we used (“%d”,*r) in pointf function at mat time value which is stored at the address which holds by variable ‘r’ is printed. Now me variable ‘r’ is holding the address of variable ‘C’. So, the value which is stored at the address of ‘C’ is printed on the output screen. Consider the following example. #include<stdio.h> #include<conio.h> void main() { int a=3; int *p; p=&a; printf(“\n%d”,a); printf(“\n%d”,&a); printf(“\n%d”,P); printf(“\n%d”,&P); printf(“\n%d”,*P); printf(“\n%d”,*(&a)); } Run the above program on the computer system so that you will familiar with the basic use of pointers. Following is the explanation O/p of above program.
Data type of pointer variable can be anything. Such as char *C; In the above instruction pointer ‘C’ is of type character so the variable ‘C’ can store the address of variable which contains character type of value. Consider the following program. #include<stdio.h> #include<conio.h> void main() { int I,*ip; char C, *cp; I = 3; ip = & I; c=’M’; cp=&c; printf(“%d”,I); printf(“\n%d”,*ip); printf(“\n%C;,C); printf(“\n%c”, *cp); getch(); } The output of above program is. 3 3 m m
5.1.3 Applications #include <stdio.h> void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; }
int main() { int x = 10, y = 20; swap(&x, &y); printf("%d %d\n", x, y); return 0; }
Output : 20 10
5.1.4 Introduction to dynamic memory allocation (malloc, calloc, realloc, free)
C malloc() The name "malloc" stands for memory allocation.
The malloc() function reserves a block of memory of the specified number of bytes. And, it returns a pointer of void which can be casted into pointers of any form.
Syntax of malloc() ptr = (castType*) malloc(size); Example
ptr = (float*) malloc(100 * sizeof(float)); The above statement allocates 400 bytes of memory. It's because the size of float is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
The expression results in a NULL pointer if the memory cannot be allocated.
C calloc() The name "calloc" stands for contiguous allocation.
The malloc() function allocates memory and leaves the memory uninitialized. Whereas, the calloc() function allocates memory and initializes all bits to zero.
Syntax of calloc() ptr = (castType*)calloc(n, size); Example:
ptr = (float*) calloc(25, sizeof(float)); The above statement allocates contiguous space in memory for 25 elements of type float.
C free() Dynamically allocated memory created with either calloc() or malloc() doesn't get freed on their own. You must explicitly use free() to release the space.
Syntax of free() free(ptr); This statement frees the space allocated in the memory pointed by ptr.
Example 1: malloc() and free() // Program to calculate the sum of n numbers entered by the user
#include <stdio.h> #include <stdlib.h>
int main() { int n, i, *ptr, sum = 0;
printf("Enter number of elements: "); scanf("%d", &n);
ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated if(ptr == NULL) { printf("Error! memory not allocated."); exit(0); }
printf("Enter elements: "); for(i = 0; i < n; ++i) { scanf("%d", ptr + i); sum += *(ptr + i); }
printf("Sum = %d", sum);
// deallocating the memory free(ptr);
return 0; } Here, we have dynamically allocated the memory for n number of int.
Example 2: calloc() and free() // Program to calculate the sum of n numbers entered by the user
#include <stdio.h> #include <stdlib.h>
int main() { int n, i, *ptr, sum = 0; printf("Enter number of elements: "); scanf("%d", &n);
ptr = (int*) calloc(n, sizeof(int)); if(ptr == NULL) { printf("Error! memory not allocated."); exit(0); }
printf("Enter elements: "); for(i = 0; i < n; ++i) { scanf("%d", ptr + i); sum += *(ptr + i); }
printf("Sum = %d", sum); free(ptr); return 0; } C realloc() If the dynamically allocated memory is insufficient or more than required, you can change the size of previously allocated memory using the realloc() function.
Syntax of realloc() ptr = realloc(ptr, x); Here, ptr is reallocated with a new size x.
Example 3: realloc() #include <stdio.h> #include <stdlib.h>
int main() { int *ptr, i , n1, n2; printf("Enter size: "); scanf("%d", &n1);
ptr = (int*) malloc(n1 * sizeof(int));
printf("Addresses of previously allocated memory: "); for(i = 0; i < n1; ++i) printf("%u\n",ptr + i);
printf("\nEnter the new size: "); scanf("%d", &n2);
// rellocating the memory ptr = realloc(ptr, n2 * sizeof(int));
printf("Addresses of newly allocated memory: "); for(i = 0; i < n2; ++i) printf("%u\n", ptr + i);
free(ptr);
return 0; } When you run the program, the output will be:
Enter size: 2 Addresses of previously allocated memory:26855472 26855476
Enter the new size: 4 Addresses of newly allocated memory:26855472 26855476 26855480 26855484
5.1.5 Use of pointers in self-referential structures Self -Referential structures are those structures that have one or more pointers which point to the same type of structure, as their member. The structures pointing to the same type of structures are self-referential in nature. struct node { int data1; char data2; struct node* link; };
int main() { struct node ob; return 0; } In the above example ‘link’ is a pointer to a structure of type ‘node’. Hence, the structure ‘node’ is a self-referential structure with ‘link’ as the referencing pointer.
5.1.6 Notion of linked list (no implementation) Linked List is a collection of multiple nodes. Each node is connected to other node via link or pointer. Every node consists of two fields.
Fig.1 Structure of a node Data Field is used to store information and Address Field stores the memory address of next node. Fig.2 Structure of a Linked List This Linked List consists of three nodes. First node is called as Head node. Assume that first node is stored at memory location 1000.First node stores value 2 in data field. Second node starts at memory address 2000 and hence 2000 is stored at address field of First node. Third node is located at memory location 3000 and hence 3000 is stored at address field of Second node. Same concept is used for all nodes in Linked List. Address field of last node contains NULL as last node does not point to any other node.
Types of Linked List:
We will discuss these types in more detail.
Singly Linked List
Each node in singly linked list points to next node and it appears to move in one direction. Thus SLL is unidirectional. Fig.4 shows schematic diagram of singly linked list with 4 nodes.
DOUBLY LINKED LIST: Singly or Circular Linked List can be traversed only in forward direction since node contains only one pointer field. Node in doubly linked list contains one data field and two pointer fields.
Fig.5 Structure of a node in DLL Left Link points to predecessor node and right link points to successor node. Information is stored in data field. Left link of First node and Right link of last node points to NULL. These two links enable bi-directional traversing, i.e. traversing the list in backward and forward direction. Hence called as bidirectional or doubly linked list. CIRCULAR LINKED LIST: A circular linked list is a linked list in which last node points to first node i.e next pointer of last node points to first node. Circular linked list does not contain NULL pointers.
Here A is the first node and C is the last node. C points to A and hence C stores address of A. |
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:
The text in the brackets denotes the functions used for performing those operations. Functions in File Operations: File opening modes in C: “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. “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. “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. “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. “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. “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. 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 filePointer = fopen(“fileName.txt”, “w”) The second parameter can be changed to contain all the attributes listed in the above table.
Reading from a file – The file read operations can be performed using functions fscanf or fgets. Both the functions performed the same operations as that of scanf and gets but with an additional parameter, the file pointer. So, it depends on you if you want to read the file line by line or character by character. And the code snippet for reading a file is as:
FILE * filePointer; filePointer = fopen(“fileName.txt”, “r”); fscanf(filePointer, "%s %s %s %d", str1, str2, str3, &year); Writing a file –: The file write operations can be perfomed by the functions fprintf and fputs with similarities to read operations. The snippet for writing to a file is as :
FILE *filePointer ; filePointer = fopen(“fileName.txt”, “w”); fprintf(filePointer, "%s %s %s %d", "We", "are", "in", 2012); Closing a file –: After every successful fie 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 ; filePointer= fopen(“fileName.txt”, “w”); ---------- Some file Operations ------- fclose(filePointer) Example 1: Program to Open a File, Write in it, And Close the File
filter_none brightness_4 // C program to Open a File, // Write in it, And Close the File
# include <stdio.h> # include <string.h>
int main( ) {
// Declare the file pointer FILE *filePointer ;
// Get the data to be written in file char dataToBeWritten[50] = "GeeksforGeeks-A Computer Science Portal for Geeks";
// Open the existing file GfgTest.c using fopen() // in write mode using "w" attribute filePointer = fopen("GfgTest.c", "w") ;
// Check if this filePointer is null // which maybe if the file does not exist if ( filePointer == NULL ) { printf( "GfgTest.c file failed to open." ) ; } else {
printf("The file is now opened.\n") ;
// Write the dataToBeWritten into the file if ( strlen ( dataToBeWritten ) > 0 ) {
// writing in the file using fputs() fputs(dataToBeWritten, filePointer) ; fputs("\n", filePointer) ; }
// Closing the file using fclose() fclose(filePointer) ;
printf("Data successfully written in file GfgTest.c\n"); printf("The file is now closed.") ; } return 0; } Example 2: Program to Open a File, Read from it, And Close the File
filter_none brightness_4 // C program to Open a File, // Read from it, And Close the File
# include <stdio.h> # include <string.h>
int main( ) {
// Declare the file pointer FILE *filePointer ;
// Declare the variable for the data to be read from file char dataToBeRead[50];
// Open the existing file GfgTest.c using fopen() // in read mode using "r" attribute filePointer = fopen("GfgTest.c", "r") ;
// Check if this filePointer is null // which maybe if the file does not exist if ( filePointer == NULL ) { printf( "GfgTest.c file failed to open." ) ; } else {
printf("The file is now opened.\n") ;
// Read the dataToBeRead from the file // using fgets() method while( fgets ( dataToBeRead, 50, filePointer ) != NULL ) {
// Print the dataToBeRead printf( "%s" , dataToBeRead ) ; }
// Closing the file using fclose() fclose(filePointer) ;
printf("Data successfully read from file GfgTest.c\n"); printf("The file is now closed.") ; } return 0; }
5.2.1 File I/O functions Functions used in File Handling are as follows : 1. open
ifstream infile; For output stream we will write ofstream outfile; For Input/Output stream we will write fstream iofile;
ofstream outfile; outfile.open(“Example”);
ifstream infile; infile.open(“Example”); 2. Close() We use member function close() to close a file. The close function neither takes parameters nor returns any value. e.g. outfile.close(); Program to illustrate working with files. #include<iostream> using namespace std; #include<fstream> int main() { char str1[50]; ofstream fout; // create out stream fout.open(“Sample”); //opening file named “Sample” with open function cout<<”Enter string”; cin>>str; //accepting string from user fout<<str<<\n”; //writing string to “Sample”file fout.close(); //closing “Sample” file
ifstream fin; //create in stream fin.open(“Sample”); // open “Sample” file for reading” fin>>str; reading string from “Sample” file
cout<<”String is”<<str; // display string to user fin.close(); return 0 ; } Output Enter String C++ String is C++ 3. read()
in.read((char *)&S, sizeof(S)); where “in” is input stream. ‘S’ is variable.
4. write()
out.write((char *)&S, sizeof(S)); where “out” is output streams and ‘S’ is variable. Program to illustrate I/O operations (read and write) on binary files. #include<iostream> using namespace std; #include<fstream> int main() { int marks[5],i; cout<<”Enter marks”; for(i=0;i<=5;i++) cin>>marks[i]; ofstream fout; fout.open(“Example”);// open file for writing fout.write((char*)& marks, sizeof(marks));// write data to file fout.close(); ifstream fin; fin.open(“Example”); // open file for reading fin.read((char*)& marks, sizeof (marks));// reading data from file cout<<”Marks are”; for(i=0;i<=5;i++) cout<<marks[i]; //displaying data to screen fin.close(); return 0 ; } 5. Detecting end of file
Program to illustrate eof() function. #include<iostream> using namespace std; #include<fstream> int main() { int x; ifstream fin; // declares stream fin.open(“myfile”, ios::in); // open file in read mode fin>>x; //get first number while(!fin.eof()) //if not at end of file, continue { reading numbers cout<<x<<endl; //print numbers fin>>x; //get another number } fin.close(); //close file return 0 ; }
5.2.2 Standard C 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 required pre-processing before the actual compilation. All preprocessor commands begin with a hash symbol (#). It must be the first nonblank character, and for readability, a preprocessor directive should begin in the first column. The following section lists down all the important preprocessor directives − Sr.No. Directive & Description 1 #define Substitutes a preprocessor macro. 2 #include Inserts a particular header from another file. 3 #undef Undefines a preprocessor macro. 4 #ifdef Returns true if this macro is defined. 5 #ifndef Returns true if this macro is not defined. 6 #if
Tests if a compile time condition is true. 7 #else The alternative for #if. 8 #elif #else and #if in one statement. 9 #endif Ends preprocessor conditional. 10 #error Prints error message on stderr. 11 #pragma Issues special commands to the compiler, using a standardized method.
5.2.3 Defining and calling macros Macros using #define A macro is a fragment of code that is given a name. You can define a macro in C using the #define preprocessor directive.
Here's an example.
#define c 299792458 // speed of light Here, when we use c in our program, it is replaced with 299792458.
Example 1: #define preprocessor #include <stdio.h> #define PI 3.1415
int main() { float radius, area; printf("Enter the radius: "); scanf("%f", &radius);
// Notice, the use of PI area = PI*radius*radius;
printf("Area=%.2f",area); return 0; } Function like Macros You can also define macros that work in a similar way like a function call. This is known as function-like macros. For example,
#define circleArea(r) (3.1415*(r)*(r))
Every time the program encounters circleArea(argument), it is replaced by (3.1415*(argument)*(argument)).
Suppose, we passed 5 as an argument then, it expands as below:
circleArea(5) expands to (3.1415*5*5) Example 2: Using #define preprocessor #include <stdio.h> #define PI 3.1415 #define circleArea(r) (PI*r*r)
int main() { float radius, area;
printf("Enter the radius: "); scanf("%f", &radius); area = circleArea(radius); printf("Area = %.2f", area);
return 0; }
5.2.4 Command - line arguments The most important function of C/C++ is main() function. It is mostly defined with a return type of int and without parameters :
int main() { /* ... */ } We can also give command-line arguments in C and C++. Command-line arguments are given after the name of the program in command-line shell of Operating Systems. To pass command line arguments, we typically define main() with two arguments : first argument is the number of command line arguments and second is list of command-line arguments.
int main(int argc, char *argv[]) { /* ... */ } or
int main(int argc, char **argv) { /* ... */ } argc (ARGument Count) is int and stores number of command-line arguments passed by the user including the name of the program. So if we pass a value to a program, value of argc would be 2 (one for argument and one for program name) The value of argc should be non negative. argv(ARGument Vector) is array of character pointers listing all the arguments. If argc is greater than zero,the array elements from argv[0] to argv[argc-1] will contain pointers to strings. Argv[0] is the name of the program , After that till argv[argc-1] every element is command -line arguments. |
References:
- The C Programming Language. 2nd Edition Book by Brian Kernighan and Dennis Ritchie
- C Programming: A Modern Approach Book by Kim N. King
- C Programming Absolute Beginner’s Guide book by S.D Perry