UNIT 4
Structures
Why use structure?
In C, there are cases where we need to store multiple attributes of an entity. It is not necessary that an entity has all the information of one type only. It can have different attributes of different data types. For example, an entity Student may have its name (string), roll number (int), marks (float). To store such type of information regarding an entity student, we have the following approaches:
- Construct individual arrays for storing names, roll numbers, and marks.
- Use a special data structure to store the collection of different data types.
Let's look at the first approach in detail.
- #include<stdio.h>
- Void main ()
- {
- Char names[2][10],dummy; // 2-dimensioanal character array names is used to store the names of the students
- Int roll_numbers[2],i;
- Float marks[2];
- For (i=0;i<3;i++)
- {
- Printf("Enter the name, roll number, and marks of the student %d",i+1);
- Scanf("%s %d %f",&names[i],&roll_numbers[i],&marks[i]);
- Scanf("%c",&dummy); // enter will be stored into dummy character at each iteration
- }
- Printf("Printing the Student details ...\n");
- For (i=0;i<3;i++)
- {
- Printf("%s %d %f\n",names[i],roll_numbers[i],marks[i]);
- }
- }
Output
Enter the name, roll number, and marks of the student 1Arun 90 91
Enter the name, roll number, and marks of the student 2Varun 91 56
Enter the name, roll number, and marks of the student 3Sham 89 69
Printing the Student details...
Arun 90 91.000000
Varun 91 56.000000
Sham 89 69.000000
The above program may fulfil our requirement of storing the information of an entity student. However, the program is very complex, and the complexity increase with the amount of the input. The elements of each of the array are stored contiguously, but all the arrays may not be stored contiguously in the memory. C provides you with an additional and simpler approach where you can use a special data structure, i.e., structure, in which, you can group all the information of different data type regarding an entity.
What is Structure
Structure in c is a user-defined data type that enables us to store the collection of different data types. Each element of a structure is called a member. Structures ca; simulate the use of classes and templates as it can store various information
The ,struct keyword is used to define the structure. Let's see the syntax to define the structure in c.
- Struct structure_name
- {
- Data_type member1;
- Data_type member2;
- .
- .
- Data_type memeberN;
- };
Let's see the example to define a structure for an entity employee in c.
- Struct employee
- { int id;
- Char name[20];
- Float salary;
- };
The following image shows the memory allocation of the structure employee that is defined in the above example.
Here, struct is the keyword; employee is the name of the structure; id, name, and salary are the members or fields of the structure. Let's understand it by the diagram given below:
Declaring structure variable
We can declare a variable for the structure so that we can access the member of the structure easily. There are two ways to declare structure variable:
- By struct keyword within main() function
- By declaring a variable at the time of defining the structure.
1st way:
Let's see the example to declare the structure variable by struct keyword. It should be declared within the main function.
- Struct employee
- { int id;
- Char name[50];
- Float salary;
- };
Now write given code inside the main() function.
- Struct employee e1, e2;
The variables e1 and e2 can be used to access the values stored in the structure. Here, e1 and e2 can be treated in the same way as the objects in C++ and Java.
2nd way:
Let's see another way to declare variable at the time of defining the structure.
- Struct employee
- { int id;
- Char name[50];
- Float salary;
- }e1,e2;
Which approach is good?
If number of variables are not fixed, use the 1st approach. It provides you the flexibility to declare the structure variable many times.
If no. Of variables are fixed, use 2nd approach. It saves your code to declare a variable in main() function.
Accessing members of the structure
There are two ways to access structure members:
- By . (member or dot operator)
- By -> (structure pointer operator)
Let's see the code to access the id member of p1 variable by. (member) operator.
- p1.id
C Structure example
Let's see a simple example of structure in C language.
- #include<stdio.h>
- #include <string.h>
- Struct employee
- { int id;
- Char name[50];
- }e1; //declaring e1 variable for structure
- Int main( )
- {
- //store first employee information
- e1.id=101;
- Strcpy(e1.name, "Sonoo Jaiswal");//copying string into char array
- //printing first employee information
- Printf( "employee 1 id : %d\n", e1.id);
- Printf( "employee 1 name : %s\n", e1.name);
- Return 0;
- }
Output:
Employee 1 id : 101
Employee 1 name : Sonoo Jaiswal
Let's see another example of the structure to store many employee information.
- #include<stdio.h>
- #include <string.h>
- Struct employee
- { int id;
- Char name[50];
- Float salary;
- }e1,e2; //declaring e1 and e2 variables for structure
- Int main( )
- {
- //store first employee information
- e1.id=101;
- Strcpy(e1.name, "Sonoo Jaiswal");//copying string into char array
- e1.salary=56000;
- //store second employee information
- e2.id=102;
- Strcpy(e2.name, "James Bond");
- e2.salary=126000;
- //printing first employee information
- Printf( "employee 1 id : %d\n", e1.id);
- Printf( "employee 1 name : %s\n", e1.name);
- Printf( "employee 1 salary : %f\n", e1.salary);
- //printing second employee information
- Printf( "employee 2 id : %d\n", e2.id);
- Printf( "employee 2 name : %s\n", e2.name);
- Printf( "employee 2 salary : %f\n", e2.salary);
- Return 0;
- }
Output:
Employee 1 id : 101
Employee 1 name : Sonoo Jaiswal
Employee 1 salary : 56000.000000
Employee 2 id : 102
Employee 2 name : James Bond
Employee 2 salary : 126000.000000
Here we will see what type of operations can be performed on struct variables. Here basically one operation can be performed for struct. The operation is assignment operation. Some other operations like equality check or other are not available for stack.
Example
#include <stdio.h>
Typedef struct { //define a structure for complex objects
Int real, imag;
}complex;
Void displayComplex(complex c){
Printf("(%d + %di)\n", c.real, c.imag);
}
Main() {
Complex c1 = {5, 2};
Complex c2 = {8, 6};
Printf("Complex numbers are:\n");
DisplayComplex(c1);
DisplayComplex(c2);
}
Output
Complex numbers are:
(5 + 2i)
(8 + 6i)
This works fine as we have assigned some values into struct. Now if we want to compare two struct objects, let us see the difference.
Example
#include <stdio.h>
Typedef struct { //define a structure for complex objects
Int real, imag;
}complex;
Void displayComplex(complex c){
Printf("(%d + %di)\n", c.real, c.imag);
}
Main() {
Complex c1 = {5, 2};
Complex c2 = c1;
Printf("Complex numbers are:\n");
DisplayComplex(c1);
DisplayComplex(c2);
If(c1 == c2){
Printf("Complex numbers are same.");
} else {
Printf("Complex numbers are not same.");
}
}
Output
[Error] invalid operands to binary == (have 'complex' and 'complex')
Why use an array of structures?
Consider a case, where we need to store the data of 5 students. We can store it by using the structure as given below.
- #include<stdio.h>
- Struct student
- {
- Char name[20];
- Int id;
- Float marks;
- };
- Void main()
- {
- Struct student s1,s2,s3;
- Int dummy;
- Printf("Enter the name, id, and marks of student 1 ");
- Scanf("%s %d %f",s1.name,&s1.id,&s1.marks);
- Scanf("%c",&dummy);
- Printf("Enter the name, id, and marks of student 2 ");
- Scanf("%s %d %f",s2.name,&s2.id,&s2.marks);
- Scanf("%c",&dummy);
- Printf("Enter the name, id, and marks of student 3 ");
- Scanf("%s %d %f",s3.name,&s3.id,&s3.marks);
- Scanf("%c",&dummy);
- Printf("Printing the details....\n");
- Printf("%s %d %f\n",s1.name,s1.id,s1.marks);
- Printf("%s %d %f\n",s2.name,s2.id,s2.marks);
- Printf("%s %d %f\n",s3.name,s3.id,s3.marks);
- }
Output
Enter the name, id, and marks of student 1 James 90 90
Enter the name, id, and marks of student 2 Adoms 90 90
Enter the name, id, and marks of student 3 Nick 90 90
Printing the details....
James 90 90.000000
Adoms 90 90.000000
Nick 90 90.000000
In the above program, we have stored data of 3 students in the structure. However, the complexity of the program will be increased if there are 20 students. In that case, we will have to declare 20 different structure variables and store them one by one. This will always be tough since we will have to declare a variable every time we add a student. Remembering the name of all the variables is also a very tricky task. However, c enables us to declare an array of structures by using which, we can avoid declaring the different structure variables; instead we can make a collection containing all the structures that store the information of different entities.
Array of Structures in C
An array of structures in C can be defined as the collection of multiple structures variables where each variable contains information about different entities. The array of structure in C are used to store information about multiple entities of different data types. The array of structures is also known as the collection of structures.
Let's see an example of an array of structures that stores information of 5 students and prints it.
- #include<stdio.h>
- #include <string.h>
- Struct student{
- Int rollno;
- Char name[10];
- };
- Int main(){
- Int i;
- Struct student st[5];
- Printf("Enter Records of 5 students");
- For(i=0;i<5;i++){
- Printf("\nEnter Rollno:");
- Scanf("%d",&st[i].rollno);
- Printf("\nEnter Name:");
- Scanf("%s",&st[i].name);
- }
- Printf("\nStudent Information List:");
- For(i=0;i<5;i++){
- Printf("\nRollno:%d, Name:%s",st[i].rollno,st[i].name);
- }
- Return 0;
- }
Output:
Enter Records of 5 students
Enter Rollno:1
Enter Name:Sonoo
Enter Rollno:2
Enter Name:Ratan
Enter Rollno:3
Enter Name:Vimal
Enter Rollno:4
Enter Name:James
Enter Rollno:5
Enter Name:Sarfraz
Student Information List:
Rollno:1, Name:Sonoo
Rollno:2, Name:Ratan
Rollno:3, Name:Vimal
Rollno:4, Name:James
Rollno:5, Name:Sarfraz
The typedef is a keyword used in C programming to provide some meaningful names to the already existing variable in the C program. It behaves similarly as we define the alias for the commands. In short, we can say that this keyword is used to redefine the name of an already existing variable.
Syntax of typedef
- Typedef <existing_name> <alias_name>
In the above syntax, 'existing_name' is the name of an already existing variable while 'alias name' is another name given to the existing variable.
For example, suppose we want to create a variable of type unsigned int, then it becomes a tedious task if we want to declare multiple variables of this type. To overcome the problem, we use a typedef keyword.
- Typedef unsigned int unit;
In the above statements, we have declared the unit variable of type unsigned int by using a typedef keyword.
Now, we can create the variables of type unsigned int by writing the following statement:
- Unit a, b;
Instead of writing:
- Unsigned int a, b;
Till now, we have observed that the typedef keyword provides a nice shortcut by providing an alternative name for an already existing variable. This keyword is useful when we are dealing with the long data type especially, structure declarations.
Let's understand through a simple example.
- #include <stdio.h>
- Int main()
- {
- Typedef unsigned int unit;
- Unit i,j;
- i=10;
- j=20;
- Printf("Value of i is :%d",i);
- Printf("\nValue of j is :%d",j);
- Return 0;
- }
Output
Value of i is :10
Value of j is :20
Using typedef with structures
Consider the below structure declaration:
- Struct student
- {
- Char name[20];
- Int age;
- };
- Struct student s1;
In the above structure declaration, we have created the variable of student type by writing the following statement:
- Struct student s1;
The above statement shows the creation of a variable, i.e., s1, but the statement is quite big. To avoid such a big statement, we use the typedef keyword to create the variable of type student.
- Struct student
- {
- Char name[20];
- Int age;
- };
- Typedef struct student stud;
- Stud s1, s2;
In the above statement, we have declared the variable stud of type struct student. Now, we can use the stud variable in a program to create the variables of type struct student.
The above typedef can be written as:
- Typedef struct student
- {
- Char name[20];
- Int age;
- } stud;
- Stud s1,s2;
From the above declarations, we conclude that typedef keyword reduces the length of the code and complexity of data types. It also helps in understanding the program.
Let's see another example where we typedef the structure declaration.
- #include <stdio.h>
- Typedef struct student
- {
- Char name[20];
- Int age;
- }stud;
- Int main()
- {
- Stud s1;
- Printf("Enter the details of student s1: ");
- Printf("\nEnter the name of the student:");
- Scanf("%s",&s1.name);
- Printf("\nEnter the age of student:");
- Scanf("%d",&s1.age);
- Printf("\n Name of the student is : %s", s1.name);
- Printf("\n Age of the student is : %d", s1.age);
- Return 0;
- }
Output
Enter the details of student s1:
Enter the name of the student: Peter
Enter the age of student: 28
Name of the student is : Peter
Age of the student is : 28
Using typedef with pointers
We can also provide another name or alias name to the pointer variables with the help of the typedef.
For example, we normally declare a pointer, as shown below:
- Int* ptr;
We can rename the above pointer variable as given below:
- Typedef int* ptr;
In the above statement, we have declared the variable of type int*. Now, we can create the variable of type int* by simply using the 'ptr' variable as shown in the below statement:
- Ptr p1, p2 ;
In the above statement, p1 and p2 are the variables of type 'ptr'.
C Pointers to struct
Here's how you can create pointers to structs.
Struct name {
Member1;
Member2;
.
.
};
Int main()
{
Struct name *ptr, Harry;
}
Here, ptr is a pointer to struct.
Example: Access members using Pointer
To access members of a structure using pointers, we use the -> operator.
#include <stdio.h>
Struct person
{
Int age;
Float weight;
};
Int main()
{
Struct person *personPtr, person1;
PersonPtr = &person1;
Printf("Enter age: ");
Scanf("%d", &personPtr->age);
Printf("Enter weight: ");
Scanf("%f", &personPtr->weight);
Printf("Displaying:\n");
Printf("Age: %d\n", personPtr->age);
Printf("weight: %f", personPtr->weight);
Return 0;
}
In this example, the address of person1 is stored in the personPtr pointer using personPtr = &person1;.
Now, you can access the members of person1 using the personPtr pointer.
By the way,
- PersonPtr->age is equivalent to (*personPtr).age
- PersonPtr->weight is equivalent to (*personPtr).weight
Dynamic memory allocation of structs
Sometimes, the number of struct variables you declared may be insufficient. You may need to allocate memory during run-time. Here's how you can achieve this in C programming.
Example: Dynamic memory allocation of structs
#include <stdio.h>
#include <stdlib.h>
Struct person {
Int age;
Float weight;
Char name[30];
};
Int main()
{
Struct person *ptr;
Int i, n;
Printf("Enter the number of persons: ");
Scanf("%d", &n);
// allocating memory for n numbers of struct person
Ptr = (struct person*) malloc(n * sizeof(struct person));
For(i = 0; i < n; ++i)
{
Printf("Enter first name and age respectively: ");
// To access members of 1st struct person,
// ptr->name and ptr->age is used
// To access members of 2nd struct person,
// (ptr+1)->name and (ptr+1)->age is used
Scanf("%s %d", (ptr+i)->name, &(ptr+i)->age);
}
Printf("Displaying Information:\n");
For(i = 0; i < n; ++i)
Printf("Name: %s\tAge: %d\n", (ptr+i)->name, (ptr+i)->age);
Return 0;
}
When you run the program, the output will be:
Enter the number of persons: 2
Enter first name and age respectively: Harry 24
Enter first name and age respectively: Gary 32
Displaying Information:
Name: Harry Age: 24
Name: Gary Age: 32
In the above example, n number of struct variables are created where n is entered by the user.
To allocate the memory for n number of struct person, we used,
Ptr = (struct person*) malloc(n * sizeof(struct person));
Then, we used the ptr pointer to access elements of person.
The arguments passed from command line are called command line arguments. These arguments are handled by main() function.
To support command line argument, you need to change the structure of main() function as given below.
- Int main(int argc, char *argv[] )
Here, argc counts the number of arguments. It counts the file name as the first argument.
The argv[] contains the total number of arguments. The first argument is the file name always.
Example
Let's see the example of command line arguments where we are passing one argument with file name.
- #include <stdio.h>
- Void main(int argc, char *argv[] ) {
- Printf("Program name is: %s\n", argv[0]);
- If(argc < 2){
- Printf("No argument passed through command line.\n");
- }
- Else{
- Printf("First argument is: %s\n", argv[1]);
- }
- }
Run this program as follows in Linux:
- ./program hello
Run this program as follows in Windows from command line:
- Program.exe hello
Output:
Program name is: program
First argument is: hello
If you pass many arguments, it will print only one.
- ./program hello c how r u
Output:
Program name is: program
First argument is: hello
But if you pass many arguments within double quote, all arguments will be treated as a single argument only.
- ./program "hello c how r u"
Output:
Program name is: program
First argument is: hello c how r u
You can write your program to print all the arguments. In this program, we are printing only argv[1], that is why it is printing only one argument.
Introduction
- A collection of data which is stored on a secondary device like a hard disk is known as a file.
- A file is generally used as real-life applications that contain a large amount of data.
There are two problems with such applications:
I) It is time-consuming and unmanageable for handling such huge amount of data,
II) When the I/O terminal is used the entire data is lost if the program is terminated or the computer is being turned off. So it is a compulsion for storing the data on a permanent device.
Files are divided into two types
1. Stream-oriented – they are standard or high-level files. They are easier to work with than the sytem-oriented data-files and are used more commonly.
2. System-oriented – they are low-level files.
The library functions which are used for operating the files are:
1. High-level file I/O functions – they do their own buffer management.
2. Low-level file I/O functions – the buffer management is done by the programmer.
Let us go through the file operations in detail one by one.
Opening a file
Before opening any file, a file pointer needs to be established.
Syntax : Establishing a file pointer
FILE *fptr;
Where,
FILE is the structure which is defined in the header file <stdio.h>.
- A file should be opened before any operation is being performed on it.
- The fopen() function is being used for opening the file.
Syntax:
FILE *fopen(const char *filename, const char *mode);
In the above syntax, filename is the literal which is used for naming the files.
They can be accessed by using the following modes:
Mode | Description |
“r” | It opens an existing file for reading only. |
“w” | It opens a new file for writing. If the filename does not exist it will be created and if the file already exists then its contents are deleted. |
“a” | It appends the existing file. If the filename does not exist it will be created. |
“r+” | It opens an existing file for reading and writing. It indicates that the file is to be read before writing. |
“w+” | It opens a new file for reading and writing. If a file with the current filename exists then it is destroyed and a new file name is created. |
“a+” | It opens an existing file for reading and appending. Its stream is positioned at the end of the file content. |
Closing a file
- The fclose() function is used for closing a file.
- When this function is used the file pointer is disconnected from a file.
Syntax:
int fclose(FILE *fp);
Where,
fp is the file pointer that points to the file that has to be closed.
- An integer value is returned which will indicate if the function was successful or not.
- In addition to the fclose() function we even have the fcloseall() function which will close all the streams which are open currently except the standard streams (stdin, stdout and stderr).
Syntax:
intfcloseall(void);
- This function will flush any of the stream buffers and will return the number of streams which are closed.
Reading a file
Following are the list of functions which are used for reading a file:
Functions | Syntax | Description |
Fscanf( ) | Int fscanf (FILE *stream, const char *format,....); | It is used for reading the formatted data from the stream. |
Fgets( ) | Char *fgets(char *str, int size, FILE *stream); | It stands for file get string. It is used for getting the string from a stream. |
Fgetc( ) | Int fgetc (FILE *stream); | It will return the next character from the stream from the end of the file or an error. |
Fread( ) | Int fread(void *str, size_t size, size_t num, FILE *stream); | It is used for reading data from a file. |
Writing a file
Following are the list of functions which are used for writing a file:
Functions | Syntax | Description |
Fprintf() | Int fprintf (FILE *stream, const char * format,...); | It is used for writing the formatted output of the stream. |
Fputs() | Int fputs(const char *str, FILE *stream); | It is used for writing a line to a file. |
Fputc() | Int fputc(int c, FILE *stream); | It is opposite to fgetc() and is used for writing a character to the stream. |
Fwrite() | Int fwrite(const void *str, size_t size, size_t count, file *stream); | It is used for writing data to a file. |
Error handling in file operations
The function ferror() is used for checking the errors in the stream.
Syntax:
int ferror(FILE *stream);
This function returns 0 if there are no errors and a value if there are some errors.
Following are the functions which are used for detecting the errors:
Functions | Syntax | Description |
Clearerr() | Void clearerr(FILE *stream); | It is used for clearing the end-of-file and error indicators for the stream. |
Perror() | Void perror(char *msg); | It stands for the print error. |
Accepting the command line arguments
The main() can accept two arguments
I) First argument will be an integer value that will specify the number of command-line arguments.
II) The second argument is a full list of all the command-line arguments.
Syntax:
int main (int arg c, char *argv[])
Where,
arg c will specify the number of arguments that are to be passed into the program from the command-line including the name of the program.
- Argv will contain the list of all the arguments.
- Each element of the array argv is a pointer where each pointer points to a string.
- In main() the command line arguments are accepted by using the argc and argv.
Example
Write a program for reading a file character by character and display it on the screen.
#include <stdio.h>
#include <string.h>
void main()
{
FILE *fp;
int c;
char fnm[25];
printf("\n Enter a filename:");
scanf("%s",fnm);
fp = fopen(fnm, "r");
if (fp==NULL)
{
printf("\n Error in opening the file");
exit(1);
}
c=fgetc(fp);
while(c!=EOF)
{
putchar(c);
c =fgetc(fp);
}
fclose(fp);
}
Output:
Assuming that we are using a text file hello.txt, that has the following content:
Welcome to TutorialRide
Now, the output is of the above problem will be:
Welcome to TutorialRide
Functions used for selecting a record randomly
Following are the functions which are used for selecting a record randomly:
Functions | Syntax | Description |
Fseek() | Int fseek(FILE *stream, long offset, int origin); | It is used to reposition a binary stream. |
Ftell() | Long ftell (FILE *stream); | It is used to know the current position of the file pointer. |
Rewind() | Void rewind (FILE *f); | It is used for adjusting the position of the file pointer to the next I/O operation and it will take place at the beginning of the file. |
Fgetpos() | Int fgetpos (FILE *stream, fpos_t *pos); | It is used for determining the current position of the stream. |
Remove()
The remove() function is used for erasing a file.
Syntax:
int remove (const char *filename);
- All the files which are specified by the filename will be erased.
- If this function is successful it will return a zero else it will return a value other than zero.
Example : Removing a file
#include <stdio.h>
void main()
{
remove(“hello.txt”);
}
Renaming the file
The rename() function is used for renaming a file.
Syntax:
int rename(const char *oldname, const char *newname);
Where,
oldname will be the pathname of the file that needs to be renamed.
newname will be the new pathname of the file.
- If this function is successful it will return a zero else it will return a value other than zero.
- If an error occurs neither the oldfile name nor the newfile name are renamed or changed.
Example : Renaming a file
#include <stdio.h>
void main()
{
int successful=0;
successful = rename("hello.txt", "hey.txt");
if (successful !=0)
printf("\nThe file is not renamed");
}
Fwrite() and fread() is used to write to a file in C.
Fwrite() syntax
Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
Where
Ptr - A pointer to array of elements to be written
Size - Size in bytes of each element to be written
Nmemb - Number of elements, each one with a size of bytes
Stream – A pointer to a FILE object that specifies an output stream
Fread() syntax
Fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
Where
Ptr - A pointer to a block of memory with a minimum size of size*nmemb bytes.
Size - Size in bytes of each element to be read.
Nmemb - Number of elements, each one with a size of bytes.
Stream - A pointer to a FILE object that specifies an input stream.
Algorithm
Begin
Create a structure Student to declare variables.
Open file to write.
Check if any error occurs in file opening.
Initialize the variables with data.
If file open successfully, write struct using write method.
Close the file for writing.
Open the file to read.
Check if any error occurs in file opening.
If file open successfully, read the file using read method.
Close the file for reading.
Check if any error occurs.
Print the data.
End.
This is an example to read/write structure in C:
Example Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Struct Student {
Int roll_no;
Char name[20];
};
Int main () {
FILE *of;
Of= fopen ("c1.txt", "w");
If (of == NULL) {
Fprintf(stderr, "\nError to open the file\n");
Exit (1);
}
Struct Student inp1 = {1, "Ram"};
Struct Student inp2 = {2, "Shyam"};
Fwrite (&inp1, sizeof(struct Student), 1, of);
Fwrite (&inp2, sizeof(struct Student), 1, of);
If(fwrite != 0)
Printf("Contents to file written successfully !\n");
Else
Printf("Error writing file !\n");
Fclose (of);
FILE *inf;
Struct Student inp;
Inf = fopen ("c1.txt", "r");
If (inf == NULL) {
Fprintf(stderr, "\nError to open the file\n");
Exit (1);
}
While(fread(&inp, sizeof(struct Student), 1, inf))
Printf ("roll_no = %d name = %s\n", inp.roll_no, inp.name);
Fclose (inf);
}
Ouput
Contents to file written successfully !
Roll_no = 1 name = Ram
Roll_no = 2 name = Shyam
In programming, we may require some specific input data to be generated several numbers of times. Sometimes, it is not enough to only display the data on the console. The data to be displayed may be very large, and only a limited amount of data can be displayed on the console, and since the memory is volatile, it is impossible to recover the programmatically generated data again and again. However, if we need to do so, we may store it onto the local file system which is volatile and can be accessed every time. Here, comes the need of file handling in C.
File handling in C enables us to create, update, read, and delete the files stored on the local file system through our C program. The following operations can be performed on a file.
- Creation of the new file
- Opening an existing file
- Reading from the file
- Writing to the file
- Deleting the file
Functions for file handling
There are many functions in the C library to open, read, write, search and close the file. A list of file functions are given below:
No. | Function | Description |
1 | Fopen() | Opens new or existing file |
2 | Fprintf() | Write data into the file |
3 | Fscanf() | Reads data from the file |
4 | Fputc() | Writes a character into the file |
5 | Fgetc() | Reads a character from file |
6 | Fclose() | Closes the file |
7 | Fseek() | Sets the file pointer to given position |
8 | Fputw() | Writes an integer to file |
9 | Fgetw() | Reads an integer from file |
10 | Ftell() | Returns current position |
11 | Rewind() | Sets the file pointer to the beginning of the file |
Opening File: fopen()
We must open a file before it can be read, write, or update. The fopen() function is used to open a file. The syntax of the fopen() is given below.
- FILE *fopen( const char * filename, const char * mode );
The fopen() function accepts two parameters:
- The file name (string). If the file is stored at some specific location, then we must mention the path at which the file is stored. For example, a file name can be like "c://some_folder/some_file.ext".
- The mode in which the file is to be opened. It is a string.
We can use one of the following modes in the fopen() function.
Mode | Description |
r | Opens a text file in read mode |
w | Opens a text file in write mode |
a | Opens a text file in append mode |
r+ | Opens a text file in read and write mode |
w+ | Opens a text file in read and write mode |
a+ | Opens a text file in read and write mode |
Rb | Opens a binary file in read mode |
Wb | Opens a binary file in write mode |
Ab | Opens a binary file in append mode |
Rb+ | Opens a binary file in read and write mode |
Wb+ | Opens a binary file in read and write mode |
Ab+ | Opens a binary file in read and write mode |
The fopen function works in the following way.
- Firstly, It searches the file to be opened.
- Then, it loads the file from the disk and place it into the buffer. The buffer is used to provide efficiency for the read operations.
- It sets up a character pointer which points to the first character of the file.
Consider the following example which opens a file in write mode.
- #include<stdio.h>
- Void main( )
- {
- FILE *fp ;
- Char ch ;
- Fp = fopen("file_handle.c","r") ;
- While ( 1 )
- {
- Ch = fgetc ( fp ) ;
- If ( ch == EOF )
- Break ;
- Printf("%c",ch) ;
- }
- Fclose (fp ) ;
- }
Output
The content of the file will be printed.
#include;
Void main( )
{
FILE *fp; // file pointer
Char ch;
Fp = fopen("file_handle.c","r");
While ( 1 )
{
Ch = fgetc ( fp ); //Each character of the file is read and stored in the character file.
If ( ch == EOF )
Break;
Printf("%c",ch);
}
Fclose (fp );
}
Closing File: fclose()
The fclose() function is used to close a file. The file must be closed after performing all the operations on it. The syntax of fclose() function is given below:
- Int fclose( FILE *fp );
C fprintf() and fscanf()
Writing File : fprintf() function
The fprintf() function is used to write set of characters into file. It sends formatted output to a stream.
Syntax:
- Int fprintf(FILE *stream, const char *format [, argument, ...])
Example:
- #include <stdio.h>
- Main(){
- FILE *fp;
- Fp = fopen("file.txt", "w");//opening file
- Fprintf(fp, "Hello file by fprintf...\n");//writing data into file
- Fclose(fp);//closing file
- }
Reading File : fscanf() function
The fscanf() function is used to read set of characters from file. It reads a word from the file and returns EOF at the end of file.
Syntax:
- Int fscanf(FILE *stream, const char *format [, argument, ...])
Example:
- #include <stdio.h>
- Main(){
- FILE *fp;
- Char buff[255];//creating char array to store data of file
- Fp = fopen("file.txt", "r");
- While(fscanf(fp, "%s", buff)!=EOF){
- Printf("%s ", buff );
- }
- Fclose(fp);
- }
Output:
Hello file by fprintf...
C File Example: Storing employee information
Let's see a file handling example to store employee information as entered by user from console. We are going to store id, name and salary of the employee.
- #include <stdio.h>
- Void main()
- {
- FILE *fptr;
- Int id;
- Char name[30];
- Float salary;
- Fptr = fopen("emp.txt", "w+");/* open for writing */
- If (fptr == NULL)
- {
- Printf("File does not exists \n");
- Return;
- }
- Printf("Enter the id\n");
- Scanf("%d", &id);
- Fprintf(fptr, "Id= %d\n", id);
- Printf("Enter the name \n");
- Scanf("%s", name);
- Fprintf(fptr, "Name= %s\n", name);
- Printf("Enter the salary\n");
- Scanf("%f", &salary);
- Fprintf(fptr, "Salary= %.2f\n", salary);
- Fclose(fptr);
- }
Output:
Enter the id
1
Enter the name
Sonoo
Enter the salary
120000
Now open file from current directory. For windows operating system, go to TC\bin directory, you will see emp.txt file. It will have following information.
Emp.txt
Id= 1
Name= sonoo
Salary= 120000
C fputc() and fgetc()
Writing File : fputc() function
The fputc() function is used to write a single character into file. It outputs a character to a stream.
Syntax:
- Int fputc(int c, FILE *stream)
Example:
- #include <stdio.h>
- Main(){
- FILE *fp;
- Fp = fopen("file1.txt", "w");//opening file
- Fputc('a',fp);//writing single character into file
- Fclose(fp);//closing file
- }
File1.txt
a
Reading File : fgetc() function
The fgetc() function returns a single character from the file. It gets a character from the stream. It returns EOF at the end of file.
Syntax:
- Int fgetc(FILE *stream)
Example:
- #include<stdio.h>
- #include<conio.h>
- Void main(){
- FILE *fp;
- Char c;
- Clrscr();
- Fp=fopen("myfile.txt","r");
- While((c=fgetc(fp))!=EOF){
- Printf("%c",c);
- }
- Fclose(fp);
- Getch();
- }
Myfile.txt
This is simple text message
C fputs() and fgets()
The fputs() and fgets() in C programming are used to write and read string from stream. Let's see examples of writing and reading file using fgets() and fgets() functions.
Writing File : fputs() function
The fputs() function writes a line of characters into file. It outputs string to a stream.
Syntax:
- Int fputs(const char *s, FILE *stream)
Example:
- #include<stdio.h>
- #include<conio.h>
- Void main(){
- FILE *fp;
- Clrscr();
- Fp=fopen("myfile2.txt","w");
- Fputs("hello c programming",fp);
- Fclose(fp);
- Getch();
- }
Myfile2.txt
Hello c programming
Reading File : fgets() function
The fgets() function reads a line of characters from file. It gets string from a stream.
Syntax:
- Char* fgets(char *s, int n, FILE *stream)
Example:
- #include<stdio.h>
- #include<conio.h>
- Void main(){
- FILE *fp;
- Char text[300];
- Clrscr();
- Fp=fopen("myfile2.txt","r");
- Printf("%s",fgets(text,200,fp));
- Fclose(fp);
- Getch();
- }
Output:
Hello c programming
C fseek() function
The fseek() function is used to set the file pointer to the specified offset. It is used to write data into file at desired location.
Syntax:
- Int fseek(FILE *stream, long int offset, int whence)
There are 3 constants used in the fseek() function for whence: SEEK_SET, SEEK_CUR and SEEK_END.
Example:
- #include <stdio.h>
- Void main(){
- FILE *fp;
- Fp = fopen("myfile.txt","w+");
- Fputs("This is javatpoint", fp);
- Fseek( fp, 7, SEEK_SET );
- Fputs("sonoo jaiswal", fp);
- Fclose(fp);
- }
Myfile.txt
This is sonoo jaiswal
Example
Compiling C programs requires you to work with five kinds of files:
- Source files: These files contain function definitions, and have names which end in .c by convention. Note: .cc and .cpp are C++ files; not C files.
e.g., foo.c - Header files: These files contain function prototypes and various pre-processor statements (see below). They are used to allow source code files to access externally-defined functions. Header files end in .h by convention.
e.g., foo.h - Object files: These files are produced as the output of the compiler. They consist of function definitions in binary form, but they are not executable by themselves. Object files end in .o by convention, although on some operating systems (e.g. Windows, MS-DOS), they often end in .obj.
e.g., foo.o foo.obj - Binary executables: These are produced as the output of a program called a "linker". The linker links together a number of object files to produce a binary file which can be directly executed. Binary executables have no special suffix on Unix operating systems, although they generally end in .exe on Windows.
e.g., foo foo.exe - Libraries: A library is a compiled binary but is not in itself an an executable (i.e., there is no main() function in a library). A library contains functions that may be used by more than one program. A library should ship with header files which contain prototypes for all functions in the library; these header files should be referenced (e.g; #include <library.h>) in any source file that uses the library. The linker then needs to be referred to the library so the program can successfully compiled. There are two types of libraries: static and dynamic.
- Static library: A static library (.a files for POSIX systems and .lib files for Windows — not to be confused with DLL import library files, which also use the .lib extension) is statically built into the program . Static libraries have the advantage that the program knows exactly which version of a library is used. On the other hand, the sizes of executables are bigger as all used library functions are included.
e.g., libfoo.a foo.lib - Dynamic library: A dynamic library (.so files for most POSIX systems, .dylib for OSX and .dll files for Windows) is dynamically linked at runtime by the program. These are also sometimes referred to as shared libraries because one library image can be shared by many programs. Dynamic libraries have the advantage of taking up less disk space if more than one application is using the library. Also, they allow library updates (bug fixes) without having to rebuild executables.
e.g., foo.so foo.dylib foo.dll
- Static library: A static library (.a files for POSIX systems and .lib files for Windows — not to be confused with DLL import library files, which also use the .lib extension) is statically built into the program . Static libraries have the advantage that the program knows exactly which version of a library is used. On the other hand, the sizes of executables are bigger as all used library functions are included.
As such, C programming does not provide direct support for error handling but being a system programming language, it provides you access at lower level in the form of return values. Most of the C or even Unix function calls return -1 or NULL in case of any error and set an error code errno. It is set as a global variable and indicates an error occurred during any function call. You can find various error codes defined in <error.h> header file.
So a C programmer can check the returned values and can take appropriate action depending on the return value. It is a good practice, to set errno to 0 at the time of initializing a program. A value of 0 indicates that there is no error in the program.
Errno, perror(). And strerror()
The C programming language provides perror() and strerror() functions which can be used to display the text message associated with errno.
- The perror() function displays the string you pass to it, followed by a colon, a space, and then the textual representation of the current errno value.
- The strerror() function, which returns a pointer to the textual representation of the current errno value.
Let's try to simulate an error condition and try to open a file which does not exist. Here I'm using both the functions to show the usage, but you can use one or more ways of printing your errors. Second important point to note is that you should use stderr file stream to output all the errors.
#include <stdio.h>
#include <errno.h>
#include <string.h>
Extern int errno ;
Int main () {
FILE * pf;
Int errnum;
Pf = fopen ("unexist.txt", "rb");
If (pf == NULL) {
Errnum = errno;
Fprintf(stderr, "Value of errno: %d\n", errno);
Perror("Error printed by perror");
Fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));
} else {
Fclose (pf);
}
Return 0;
}
When the above code is compiled and executed, it produces the following result −
Value of errno: 2
Error printed by perror: No such file or directory
Error opening file: No such file or directory
Divide by Zero Errors
It is a common problem that at the time of dividing any number, programmers do not check if a divisor is zero and finally it creates a runtime error.
The code below fixes this by checking if the divisor is zero before dividing −
#include <stdio.h>
#include <stdlib.h>
Main() {
Int dividend = 20;
Int divisor = 0;
Int quotient;
If( divisor == 0){
Fprintf(stderr, "Division by zero! Exiting...\n");
Exit(-1);
}
Quotient = dividend / divisor;
Fprintf(stderr, "Value of quotient : %d\n", quotient );
Exit(0);
}
When the above code is compiled and executed, it produces the following result −
Division by zero! Exiting...
Program Exit Status
It is a common practice to exit with a value of EXIT_SUCCESS in case of program coming out after a successful operation. Here, EXIT_SUCCESS is a macro and it is defined as 0.
If you have an error condition in your program and you are coming out then you should exit with a status EXIT_FAILURE which is defined as -1. So let's write above program as follows −
#include <stdio.h>
#include <stdlib.h>
Main() {
Int dividend = 20;
Int divisor = 5;
Int quotient;
If( divisor == 0) {
Fprintf(stderr, "Division by zero! Exiting...\n");
Exit(EXIT_FAILURE);
}
Quotient = dividend / divisor;
Fprintf(stderr, "Value of quotient : %d\n", quotient );
Exit(EXIT_SUCCESS);
}
When the above code is compiled and executed, it produces the following result −
Value of quotient : 4
A File can be used to store a large volume of persistent data. Like many other languages, 'C' provides following file management functions,
- Creation of a file
- Opening a file
- Reading a file
- Writing to a file
- Closing a file
Following are the most important file management functions available in 'C,'
Function | Purpose |
Fopen () | Creating a file or opening an existing file |
Fclose () | Closing a file |
Fprintf () | Writing a block of data to a file |
Fscanf () | Reading a block data from a file |
Getc () | Reads a single character from a file |
Putc () | Writes a single character to a file |
Getw () | Reads an integer from a file |
Putw () | Writing an integer to a file |
Fseek () | Sets the position of a file pointer to a specified location |
Ftell () | Returns the current position of a file pointer |
Rewind () | Sets the file pointer at the beginning of a file |
How to Create a File
Whenever you want to work with a file, the first step is to create a file. A file is nothing but space in a memory where data is stored.
To create a file in a 'C' program following syntax is used,
FILE *fp;
Fp = fopen ("file_name", "mode");
In the above syntax, the file is a data structure which is defined in the standard library.
Fopen is a standard function which is used to open a file.
- If the file is not present on the system, then it is created and then opened.
- If a file is already present on the system, then it is directly opened using this function.
Fp is a file pointer which points to the type file.
Whenever you open or create a file, you have to specify what you are going to do with the file. A file in 'C' programming can be created or opened for reading/writing purposes. A mode is used to specify whether you want to open a file for any of the below-given purposes. Following are the different types of modes in 'C' programming which can be used while working with a file.
File Mode | Description |
r | Open a file for reading. If a file is in reading mode, then no data is deleted if a file is already present on a system. |
w | Open a file for writing. If a file is in writing mode, then a new file is created if a file doesn't exist at all. If a file is already present on a system, then all the data inside the file is truncated, and it is opened for writing purposes. |
a | Open a file in append mode. If a file is in append mode, then the file is opened. The content within the file doesn't change. |
r+ | Open for reading and writing from beginning |
w+ | Open for reading and writing, overwriting a file |
a+ | Open for reading and writing, appending to file |
In the given syntax, the filename and the mode are specified as strings hence they must always be enclosed within double quotes.
Example:
#include <stdio.h>
Int main() {
FILE *fp;
Fp = fopen ("data.txt", "w");
}
Output:
File is created in the same folder where you have saved your code.
You can specify the path where you want to create your file
#include <stdio.h>
Int main() {
FILE *fp;
Fp = fopen ("D://data.txt", "w");
}
How to Close a file
One should always close a file whenever the operations on file are over. It means the contents and links to the file are terminated. This prevents accidental damage to the file.
'C' provides the fclose function to perform file closing operation. The syntax of fclose is as follows,
Fclose (file_pointer);
Example:
FILE *fp;
Fp = fopen ("data.txt", "r");
Fclose (fp);
The fclose function takes a file pointer as an argument. The file associated with the file pointer is then closed with the help of fclose function. It returns 0 if close was successful and EOF (end of file) if there is an error has occurred while file closing.
After closing the file, the same file pointer can also be used with other files.
In 'C' programming, files are automatically close when the program is terminated. Closing a file manually by writing fclose function is a good programming practice.
Writing to a File
In C, when you write to a file, newline characters '\n' must be explicitly added.
The stdio library offers the necessary functions to write to a file:
- Fputc(char, file_pointer): It writes a character to the file pointed to by file_pointer.
- Fputs(str, file_pointer): It writes a string to the file pointed to by file_pointer.
- Fprintf(file_pointer, str, variable_lists): It prints a string to the file pointed to by file_pointer. The string can optionally include format specifiers and a list of variables variable_lists.
The program below shows how to perform writing to a file:
Fputc() Function:
#include <stdio.h>
Int main() {
Int i;
FILE * fptr;
Char fn[50];
Char str[] = "Guru99 Rocks\n";
Fptr = fopen("fputc_test.txt", "w"); // "w" defines "writing mode"
For (i = 0; str[i] != '\n'; i++) {
/* write to file using fputc() function */
Fputc(str[i], fptr);
}
Fclose(fptr);
Return 0;
}
Output:
The above program writes a single character into the fputc_test.txt file until it reaches the next line symbol "\n" which indicates that the sentence was successfully written. The process is to take each character of the array and write it into the file.
- In the above program, we have created and opened a file called fputc_test.txt in a write mode and declare our string which will be written into the file.
- We do a character by character write operation using for loop and put each character in our file until the "\n" character is encountered then the file is closed using the fclose function.
Fputs () Function:
#include <stdio.h>
Int main() {
FILE * fp;
Fp = fopen("fputs_test.txt", "w+");
Fputs("This is Guru99 Tutorial on fputs,", fp);
Fputs("We don't need to use for loop\n", fp);
Fputs("Easier than fputc function\n", fp);
Fclose(fp);
Return (0);
}
OUTPUT:
- In the above program, we have created and opened a file called fputs_test.txt in a write mode.
- After we do a write operation using fputs() function by writing three different strings
- Then the file is closed using the fclose function.
Fprintf()Function:
#include <stdio.h>
Int main() {
FILE *fptr;
Fptr = fopen("fprintf_test.txt", "w"); // "w" defines "writing mode"
/* write to file */
Fprintf(fptr, "Learning C with Guru99\n");
Fclose(fptr);
Return 0;
}
OUTPUT:
- In the above program we have created and opened a file called fprintf_test.txt in a write mode.
- After a write operation is performed using fprintf() function by writing a string, then the file is closed using the fclose function.
Reading data from a File
There are three different functions dedicated to reading data from a file
- Fgetc(file_pointer): It returns the next character from the file pointed to by the file pointer. When the end of the file has been reached, the EOF is sent back.
- Fgets(buffer, n, file_pointer): It reads n-1 characters from the file and stores the string in a buffer in which the NULL character '\0' is appended as the last character.
- Fscanf(file_pointer, conversion_specifiers, variable_adresses): It is used to parse and analyze data. It reads characters from the file and assigns the input to a list of variable pointers variable_adresses using conversion specifiers. Keep in mind that as with scanf, fscanf stops reading a string when space or newline is encountered.
The following program demonstrates reading from fputs_test.txt file using fgets(),fscanf() and fgetc () functions respectively :
#include <stdio.h>
Int main() {
FILE * file_pointer;
Char buffer[30], c;
File_pointer = fopen("fprintf_test.txt", "r");
Printf("----read a line----\n");
Fgets(buffer, 50, file_pointer);
Printf("%s\n", buffer);
Printf("----read and parse data----\n");
File_pointer = fopen("fprintf_test.txt", "r"); //reset the pointer
Char str1[10], str2[2], str3[20], str4[2];
Fscanf(file_pointer, "%s %s %s %s", str1, str2, str3, str4);
Printf("Read String1 |%s|\n", str1);
Printf("Read String2 |%s|\n", str2);
Printf("Read String3 |%s|\n", str3);
Printf("Read String4 |%s|\n", str4);
Printf("----read the entire file----\n");
File_pointer = fopen("fprintf_test.txt", "r"); //reset the pointer
While ((c = getc(file_pointer)) != EOF) printf("%c", c);
Fclose(file_pointer);
Return 0;
}
Result:
----read a line----
Learning C with Guru99
----read and parse data----
Read String1 |Learning|
Read String2 |C|
Read String3 |with|
Read String4 |Guru99|
----read the entire file----
Learning C with Guru99
- In the above program, we have opened the file called "fprintf_test.txt" which was previously written using fprintf() function, and it contains "Learning C with Guru99" string. We read it using the fgets() function which reads line by line where the buffer size must be enough to handle the entire line.
- We reopen the file to reset the pointer file to point at the beginning of the file. Create various strings variables to handle each word separately. Print the variables to see their contents. The fscanf() is mainly used to extract and parse data from a file.
- Reopen the file to reset the pointer file to point at the beginning of the file. Read data and print it from the file character by character using getc() function until the EOF statement is encountered
- After performing a reading operation file using different variants, we again closed the file using the fclose function.
Interactive File Read and Write with getc and putc
These are the simplest file operations. Getc stands for get character, and putc stands for put character. These two functions are used to handle only a single character at a time.
Following program demonstrates the file handling functions in 'C' programming:
#include <stdio.h>
Int main() {
FILE * fp;
Char c;
Printf("File Handling\n");
//open a file
Fp = fopen("demo.txt", "w");
//writing operation
While ((c = getchar()) != EOF) {
Putc(c, fp);
}
//close file
Fclose(fp);
Printf("Data Entered:\n");
//reading
Fp = fopen("demo.txt", "r");
While ((c = getc(fp)) != EOF) {
Printf("%c", c);
}
Fclose(fp);
Return 0;
}
Output:
- In the above program we have created and opened a file called demo in a write mode.
- After a write operation is performed, then the file is closed using the fclose function.
- We have again opened a file which now contains data in a reading mode. A while loop will execute until the eof is found. Once the end of file is found the operation will be terminated and data will be displayed using printf function.
- After performing a reading operation file is again closed using the fclose function.
Summary
- A file is a space in a memory where data is stored.
- 'C' programming provides various functions to deal with a file.
- A mechanism of manipulating with the files is called as file management.
- A file must be opened before performing operations on it.
- A file can be opened in a read, write or an append mode.
- Getc and putc functions are used to read and write a single character.
- The function fscanf() permits to read and parse data from a file
- We can read (using the getc function) an entire file by looping to cover all the file until the EOF is encountered
- We can write to a file after creating its name, by using the function fprintf() and it must have the newline character at the end of the string text.
Text Books:
1. Programming with C-Gottfried-Schaums Outline Series-TMH
2. C Programming – Anitha Goel/Ajay Mittal/E.Sreenivasa Reddy-Pearson India
References:
1. Problem Solving with C- Somasekharan-PHI.
2. C Programming- Behrouz A forouzan – CENGAGE Learning
3. Test your c skills-Yaswanth kanithker
4. Let us C- Yaswanth kanithker