Block-2 Functions, Structures, Pointers and File Handling in C
Block-2 Functions, Structures, Pointers and File Handling in C
Programming in C
Indira Gandhi National Open University
School of Computer and Information
Sciences (SOCIS)
and Python
Functions,structures,pointers,
and file handling in C 2
MCS-201
Block
2
FUNCTIONS, STRUCTURES, POINTERS AND FILE
HANDLING IN C
UNIT 5
FUNCTIONS 117
UNIT 6
STRUCTURES AND UNIONS 139
UNIT 7
POINTERS 155
UNIT 8
FILE HANDLING 177
BLOCK 2 INTRODUCTION
Any C program must have a main() function to contain the code executed by default
when the program is run. You can put as many user defined functions as you like in
the program to achieve the modularity in the programming. In C, all functions in a
program are “visible” to all other functions in that. Detail discussion regarding the
types of functions and their invoking is provided in Unit-5.
Pointers and arrays have a special relationship which is discussed in this unit.
The block contains a wide variety of programming examples to support the concepts
given in the material. Whenever possible, examples contain complete programs or
functions rather than incomplete program fragments. To get the maximum benefit
from this, it is necessary that you should understand and execute all the example
programs given in this block, as well, complete the assignment problems given in
the lab manual also.
Unit - 6 provides an overview of the user defined data-type called as the Structures.
Happy Programming!
Indira Gandhi
National Open University MCS-201
School of Computer and
Information Sciences PROGRAMMING IN
C AND PYTHON
Block
2
FUNCTIONS, STRUCTURES, POINTERS AND
FILE HANDLING IN C
UNIT 5
Functions
UNIT 6
Structures and Unions
UNIT 7
Pointers
UNIT 8
File Handling
Programme / Course Design Committee
Prof. Sanjeev K. Aggarwal, IIT, Kanpur
Prof. V.V. Subrahmanyam
Prof. M. Balakrishnan, IIT , Delhi Director
SOCIS, IGNOU, New Delhi
Prof Harish Karnick, IIT, Kanpur Prof P. Venkata Suresh
SOCIS, IGNOU, New Delhi
Prof. C. Pandurangan, IIT, Madras
Dr. Shashi Bhushan
Dr. Om Vikas, Sr. Director, MIT Associate Professor
SOCIS, IGNOU, New Delhi
Prof P. S. Grover, Sr. Consultant, Shri Akshay Kumar
Prof. (Retd.) S.K. Gupta Associate Professor
IIT, Delhi SOCIS, IGNOU, New Delhi
March, 2021
Indira Gandhi National Open University, 2021
ISBN-
All rights reserved. No part of this work may be reproduced in any form, by mimeograph or any other means,
without permission in writing from the Indira Gandhi National Open University.
Further information on the Indira Gandhi National Open University courses may be obtained from the
University’s office at Maidan Garhi, New Delhi-110 068.
Functions
UNIT 5 FUNCTIONS
Structure
5.0 Introduction
5.1 Objectives
5.2 Definition of a Function
5.3 Declaration of a Function
5.4 Function Prototypes
5.5 The Return Statement
5.6 Types of Variables and Storage Classes
5.6.1 Automatic Variables
5.6.2 External Variables
5.6.3 Static Variables
5.6.4 Register Variables
5.7 Types of Function Invoking
5.8 Call by Value
5.9 Recursion
5.10 Summary
5.11 Solutions / Answers
5.12 Further Readings
5.0 INTRODUCTION
To make programming simple and easy to debug, we break a larger program
into smaller subprograms which perform ‘well defined tasks’. These
subprograms are called functions. So far we have defined a single function
main().
After reading this unit you will be able to define many other functions and the
main() function can call up these functions from several different places within
the program, to carry out the required processing.
In this unit, we will discuss how functions are defined and how are they
accessed from the main program? We will also discuss various types of
functions and how to invoke them. And finally you will learn an interesting
and important programming technique known as Recursion, in which a
function calls within itself.
5.1 OBJECTIVES
After going through this unit, you will learn:
the need of functions in the programming; 117
Functions, Structures, how to define and declare functions in ‘C’ Language;
Pointers and
File Handling in C different types of functions and their purpose;
how the functions are called from other functions;
how data is transferred through parameter passing, to functions and the
Return statement;
recursive functions; and
the concept of ‘Call by Value’ and its drawbacks.
#include <stdio.h>
main ()
{
void sample();
printf(“\n You are in main”);
}
void sample()
{
printf(“\n You are in sample”);
}
OUTPUT
You are in sample
You are in main
where,
return data type is the same as the data type of the variable that is returned
by the function using return statement.
a function_name is formed in the same way as variable names / identifiers
are formed.
the list of arguments or parameters are valid variable names as shown
below, separated by commas: (data type1 var1,data type2 var2,…….. data
type n var n)
for example (int x, float y, char z).
arguments give the values which are passed from the calling function.
the body of function contains executable statements.
the return statement returns a single value to the calling function.
Example 5.2
/* square() function */
{
int square(int no) /*passing of argument */
int result ; /* local variable to function square */
result = no*no;
return(result); /* returns an integer value */
}
OUTPUT
For example,
/* square function */
int square(int no) /*passing of argument */
{
int result ; /* local variable to function square */
result = no*no;
return(result); /* returns an integer value */
}
120
Functions
OUTPUT
Points to remember:
Function prototype requires that the function declaration must include the
return type of function as well as the type and number of arguments or
parameters passed.
The variable names of arguments need not be declared in prototype.
The major reason to use this concept is that they enable the compiler to
check if there is any mismatch between function declaration and function
call.
Check Your Progress 1
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
return (expression);
We have seen in the square() function, the return statement, which returns an
integer value.
Points to remember:
121
Functions, Structures, You can pass any number of arguments to a function but can return only
Pointers and
File Handling in C one value at a time.
For example, the following are the valid return statements
a) return (5);
b) return (x*y);
For example, the following are the invalid return statements
c) return (2, 3);
d) return (x, y);
If a function does not return anything, void specifier is used in the function
declaration.
For example:
void square (int no)
{
int sq;
sq = no*no;
printf (“square is %d”, sq);
}
All the function’s return type is by default is “int”, i.e. a function returns
an integer value, if no type specifier is used in the function declaration.
What happens if a function has to return some value other than integer?
The answer is very simple: use the particular type specifier in the function
declaration.
For example consider the code fragments of function definitions below:
1) Code Fragment - 1
2) Code Fragment - 2
float func_float (……..)
{
float f;
…………..
…………..
…………..
122
return(f); Functions
}
Thus from the above examples, we see that you can return all the data types
from a function, the only condition being that the value returned using return
statement and the type specifier used in function declaration should match.
A function can have many return statements. This thing happens when
some condition based returns are required.
For example,
Points to remember:
# include <stdio.h>
main ( int argc, char * argv[ ])
{
int a, b;
double d;
printf(“%d”, argc);
a = 10;
b = 5;
d = (b * b) – (a/2);
printf(“%d, %d, %f”, a, b, d);
}
All the variables a, b, d, argc and argv [ ] have automatic storage class.
These are global and can be accessed by any function within its scope.
Therefore value may be assigned in one and can be written in another.
There is difference in external variable definition and declaration.
External Definition is the same as any variable declaration:
Usually lies outside or before the function accessing it.
It allocates storage space required.
Initial values can be assigned.
The external specifier is not required in external variable definition.
A declaration is required if the external variable definition comes after the
function definition.
A declaration begins with an external specifier.
Only when external variable is defined is the storage space allocated.
External variables can be assigned initial values as a part of variable
definitions, but the values must be constants rather than expressions.
If initial value is not included then it is automatically assigned a value of
zero.
125
Functions, Structures, Let us study these variables by a sample program given below:
Pointers and
File Handling in C Example 5.5
/* Program to illustrate the use of global variables*/
# include <stdio.h>
int gv; /*global variable*/
main ( )
{
void function1(); /*function declaration*/
gv = 10;
printf (“%d is the value of gv before function call\n”, gv);
function1();
printf (“%d is the value of gv after function call\n”, gv);
}
void function1 ( )
{
gv = 15: }
OUTPUT
The specifier precedes the declaration. Static and the value cannot be
accessed outside of their defining function.
The static variables may have same name as that of external variables but
the local variables take precedence in the function. Therefore external
variables maintain their independence with locally defined auto and static
variables.
Initial value is expressed as the constant and not expression.
Zeros are assigned to all variables whose declarations do not include
explicit initial values. Hence they always have assigned values.
Initialization is done only is the first execution.
Let us study this sample program to print value of a static variable:
Example 5.6
/* Program to illustrate the use of static variable*/
#include <stdio.h>
main()
{
int call_static();
126
int i,j; Functions
i=j=0;
j = call_static();
printf(“%d\n”,j);
j = call_static ();
printf(“%d\n”,j);
j = call_static();
printf(“%d\n”,j);
}
int call_static()
{
static int i=1;
int j;
j = i;
i++;
return(j);
}
OUTPUT
1
2
3
This is because i is a static variable and retains its previous value in next
execution of function call_static(). To remind you j is having auto storage
class. Both functions main and call_static have the same local variable i and j
but their values never get mixed.
register int m;
Points to remember:
These variables are stored in registers of computers. If the registers are
not available they are put in memory.
Usually 2 or 3 register variables are there in the program.
Scope is same as automatic variable, local to a function in which they are
declared.
Address operator ‘&’ cannot be applied to a register variable.
127
Functions, Structures, If the register is not available the variable is though to be like the
Pointers and
File Handling in C automatic variable.
Usually associated integer variable but with other types it is allowed
having same size (short or unsigned).
Can be formal arguments in functions.
Pointers to register variables are not allowed.
These variables can be used for loop indices also to increase efficiency.
Example 5.7
/* Program for illustration of the function with no arguments and no return value*/
#include <stdio.h>
main()
{
void message();
printf(“Control is in main\n”);
message(); /* Type 1 Function */
printf(“Control is again in main\n”);
}
void message()
{
printf(“Control is in message function\n”);
} /* does not return anything */
128
OUTPUT Functions
Control is in main
Control is in message function
Control is again in main
Example 5.8
Write a program to find the sum of the first ten natural numbers.
#include <stdio.h>
int cal_sum()
{
int i, s=0;
for (i=0; i<=10; i++)
s=s + i;
return(s); /* function returning sum of first ten natural numbers */
}
main()
{
int sum;
sum = cal_sum();
printf(“Sum of first ten natural numbers is % d\n”, sum);
}
OUTPUT
Before proceeding further, first we discuss the type of arguments or parameters here.
There are two types of arguments:
Actual arguments
Formal arguments
#include <stdio.h>
main()
129
Functions, Structures, {
Pointers and int a1, a2, a3;
File Handling in C void sum(int, int, int);
printf(“Enter three numbers: “);
scanf (“%d%d%d”,&a1,&a2,&a3);
sum (a1,a2,a3); /* Type 3 function */
}
OUTPUT
Here f1, f2, f3 are formal arguments and a1, a2, a3 are actual arguments.
Thus we see in the function declaration, the arguments are formal arguments, but
when values are passed to the function during function call, they are actual arguments.
Note: The actual and formal arguments should match in type, order and number
In this category two-way communication takes place between the calling and called
function i.e. a function returns a value and also arguments are passed to it. We modify
above Example according to this category.
Example 5.10
Write a program to calculate sum of three numbers.
#include <stdio.h>
main()
{
int a1, a2, a3, result;
int sum(int, int, int);
printf(“Please enter any 3 numbers:\n”);
scanf (“%d %d %d”, & a1, &a2, &a3);
result = sum (a1,a2,a3); /* function call */
printf (“Sum of the given numbers is : %d\n”, result);
}
OUTPUT
130
Please enter any 3 numbers: Functions
345
Sum of the given numbers is: 12
#include <stdio.h>
main()
{
int x, y, z;
int mul(int, int);
printf (“Enter two numbers: \n”);
scanf (“%d %d”,&x,&y);
z= mul(x, y); /* function call by value */
printf (“\n The product of the two numbers is : %d”, z);
}
OUTPUT
Now let us see what happens to the actual and formal arguments in memory.
main() function mul() function
131
Functions, Structures,
Pointers and
x
File Handling in C a
2 2
The variables are local
to the mul() function
which are created in
memory with the
3y 3 b function call and are
destroyed with the
return to the called
6 6 function
z c
What are meant by local variables? The answer is local variables are those which can
be used only by that function.
Let us discuss the second disadvantage more clearly using one example:
Example 5.12
Write a program to swap two values.
#include <stdio.h>
main()
{
int x = 2, y = 3;
void swap(int, int);
OUTPUT
x a a
2 2 3
t 2
y b b t
3 3 2
Here we observe that the changes which takes place in argument variables are not
reflected in the main() function; as these variables namely a, b and t will be destroyed
with function return.
All these disadvantages will be removed by using “call by reference”, which will
be discussed with the introduction of pointers in UNIT 11.
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
133
Functions, Structures,
Pointers and 5.9 RECURSION
File Handling in C
Within a function body, if the function calls itself, the mechanism is known as
‘Recursion’ and the function is known as ‘Recursive function’. Now let us
study this mechanism in detail and understand how it works.
Example 5.13
Write a program to find factorial of a number
#include <stdio.h>
main ()
{
int n, factorial;
int fact(int);
printf (“Enter any number:\n” );
scanf ("%d", &n);
factorial = fact ( n); /* function call */
printf (“Factorial is %d\n”, factorial);
}
OUTPUT
How it works?
Iterations:
1. i= 5 res = 1*5 = 5
2. i= 4 res = 5*4 = 20
3. i= 3 res = 20*4 = 60
4. i= 2 res = 60*2 = 120
134
5. i= 1 res = 120*1 = 120 Functions
Now let us write this function recursively. Before writing any function
recursively, we first have to examine the problem, that it can be implemented
through recursion.
That means this function calls itself but with value of argument decreased by ‘1’.
Example 5.14
Modify the program 8 using recursion.
OUTPUT
Enter any number: 5
Factorial is 120
How it works?
5*fact(4) 5*24
Returning Process
4*fact(3) 4*6(=24)
3*fact(2) 3*2*1(= 6)
2*fact(1) 2* 1(=2)
135
Functions, Structures,
Pointers and
File Handling in C 2*1 (It terminates here)
………………………………………………………………………………
………………………………………………………………………………
………………………………………………………………………………
………………………………………………………………………………
………………………………………………………………………………
5.10 SUMMARY
In this unit, we learnt about “Functions”: definition, declaration, prototypes,
types, function calls datatypes and storage classes, types function invoking and
lastly Recursion. All these subtopics must have given you a clear idea of how
to create and call functions from other functions, how to send values through
arguments, and how to return values to the called function. We have seen that
the functions, which do not return any value, must be declared as “void”,
return type. A function can return only one value at a time, although it can
have many return statements. A function can return any of the data type
specified in ‘C’.
Any variable declared in functions are local to it and are created with function
call and destroyed with function return. The actual and formal arguments
should match in type, order and number. A recursive function should have a
terminating condition i.e. function should return a value instead of a repetitive
function call.
2. #include <stdio.h>
main()
{
int x, y, z;
int mul(int, int); /* function prototype */
printf(“Enter two numbers”);
scanf(“%d %d”, &x, &y);
z = mul(x, y); /* function call */
printf(“result is %d”, z); }
void fib(int n)
{
int curr_term, int count = 0;
int first = 1;
int second = 1;
print(“%d %d”, curr_term);
count = 2;
while(count < = n)
{ curr_term = first + second;
printf(“%d”, curr_term);
first = second;
second = curr_term;
count++;
}
}
138
Structures and
UNIT 6 STRUCTURES AND UNIONS Unions
Structure
6.0 Introduction
6.1 Objectives
6.2 Declaration of Structures
6.3 Accessing the Members of a Structure
6.4 Initializing Structure Variables
6.5 Structures as Function Arguments
6.6 Structures and Arrays
6.7 Unions
6.8 Initializing an Union
6.9 Accessing the Members of an Union
6.10 Summary
6.11 Solutions / Answers
6.12 Further Readings
6.0 INTRODUCTION
We have seen so far how to store numbers, characters, strings, and even large sets of
these primitives using arrays, but what if we want to store collections of different
kinds of data that are somehow related. For example, a file about an employee will
probably have his/her name, age, the hours of work, salary, etc. Physically, all of that
is usually stored in someone’s filing cabinet. In programming, if you have lots of
related information, you group it together in an organized fashion. Let’s say you have
a group of employees, and you want to make a database! It just wouldn’t do to have
tons of loose variables hanging all over the place. Then we need to have a single data
entity where we will be able to store all the related information together. But this can’t
be achieved by using the arrays alone, as in the case of arrays, we can group multiple
data elements that are of the same data type, and is stored in consecutive memory
locations, and is individually accessed by a subscript. That is where the user-defined
datatype Structures come in.
Structure is commonly referred to as a user-defined data type. C’s structures allow
you to store multiple variables of any type in one place (the structure). A structure can
contain any of C’s data types, including arrays and other structures. Each variable
within a structure is called a member of the structure. They can hold any number of
variables, and you can make arrays of structures. This flexibility makes structures
ideally useful for creating databases in C. Similar to the structure there is another user
defined data type called Union which allows the programmer to view a single storage
in more than one way i.e., a variable declared as union can store within its storage
space, the data of different types, at different times. In this unit, we will be discussing
the user-defined data type structures and unions.
6.1 OBJECTIVES
After going through this unit you should be able to:
struct structure-tag {
datatype variable1;
datatype variable2;
dataype variable 3;
...
};
For example, consider the student database in which each student has a roll number,
name and course and the marks obtained. Hence to group this data with a structure-tag
as student, we can have the declaration of structure as:
struct student {
int roll_no;
char name[20];
char course[20];
int marks_obtained;
};
The point you need to remember is that, till this time no memory is allocated to the
structure. This is only the definition of structure that tells us that there exists a user-
defined data type by the name of student which is composed of the following
members. Using this structure type, we have to create the structure variables:
At this point, we have created two instances or structure variables of the user-defined
data type student. Now memory will be allocated. The amount of memory allocated
will be the sum of all the data members which form part of the structure template.
struct {
int roll_no;
char name[20];
char course[20];
int marks_obtained;
} stud1,stud2;
In this case, a tag name student is missing, but still it happens to be a valid declaration
of structure. In this case the two variables are allocated memory equivalent to the
members of the structure.
The advantage of having a tag name is that we can declare any number of variables of
the tagged named structure later in the program as per requirement.
If you have a small structure that you just want to define in the program, you can do
the definition and declaration together as shown below. This will define a structure of
type struct telephone and declare three instances of it.
140
Consider the example for declaring and defining a structure for the telephone billing Structures and
Unions
with three instances:
struct telephone{
int tele_no;
int cust_code;
char cust_address[40];
int bill_amt;
}tele1, tele2, tele3;
The structure can also be declared by using the typedefinition or typedef. This can be
done as shown below:
This defines a structure which can be referred to either as struct country or Country,
whichever you prefer. Strictly speaking, you don’t need a tag name both before and
after the braces if you are not going to use one or the other. But it is a standard
practice to put them both in and to give them the same name, but the one after the
braces starts with an uppercase letter.
The typedef statement doesn’t occupy storage: it simply defines a new type. Variables
that are declared with the typedef above will be of type struct country, just like
population is of type integer. The structure variables can be now defined as below:
structurevariable. member-name;
struct coordinate{
int x;
int y;
};
Thus, to have the structure named first refer to a screen location that has coordinates
x=50, y=100, you could write as,
first.x = 50;
first.y = 100;
To display the screen locations stored in the structure second, you could write,
Example 6.1
/*Program to store and retrieve the values from the student structure*/
#include<stdio.h>
struct student {
int roll_no;
char name[20];
char course[20];
int marks_obtained ;
};
main()
{
student s1 ;
printf(“Enter the student roll number:”);
scanf(“%d”,&s1.roll_no);
printf(“\nEnter the student name: “);
scanf(“%s”,s1.name);
printf(“\nEnter the student course”);
scanf(“%s”,s1.course);
printf(“Enter the student percentage\n”);
scanf(“%d”,&s1.marks_obtained);
printf(“\nData entry is complete”);
printf( “\nThe data entered is as follows:\n”);
printf(“\nThe student roll no is %d”,s1.roll_no);
printf(“\nThe student name is %s”,s1.name);
printf(“\nThe student course is %s”,s1.course);
printf(“\nThe student percentage is %d”,s1.marks_obtained);
}
OUTPUT
Another way of accessing the storing the values in the members of a structure is by
initializing them to some values at the time when we create an instance of the data
type.
142
Structures and
6.4 INITIALIZING STRUCTURE VARIABLES Unions
Like other C variable types, structures can be initialized when they’re declared. This
procedure is similar to that for initializing arrays. The structure declaration is followed
by an equal sign and a list of initialization values is separated by commas and
enclosed in braces. For example, look at the following statements for initializing the
values of the members of the mysale structure variable.
Example 6.2
struct sale {
char customer[20];
char item[20];
float amt;
} mysale = { "XYZ Industries",
“toolskit",
600.00
};
In a structure that contains structures as members, list the initialization values in order.
They are placed in the structure members in the order in which the members are listed
in the structure definition. Here’s an example that expands on the previous one:
Example 6.3
struct customer {
char firm[20];
char contact[25];
}
struct sale {
struct customer buyer1;
char item [20];
float amt;
} mysale = {
{ "XYZ Industries", "Tyran Adams"},
"toolskit",
600.00
};
For example let us consider the following program where the data members are
initialized to some value.
Example 6.4
Write a program to access the values of the structure initialized with some initial
values.
143
Functions, Structures, /* Program to illustrate to access the values of the structure initialized with some
Pointers and initial values*/
File Handling in C
#include<stdio.h>
struct telephone{
int tele_no;
int cust_code;
char cust_name[20];
char cust_address[40];
int bill_amt;
};
main()
{
struct telephone tele = {2314345,
5463,
"Ram",
"New Delhi",
2435 };
OUTPUT
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
144
Structures and
3. Why does size of report a larger size than, one expects, for a structure type, as if Unions
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………….
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
Example 6.5
#include <stdio.h>
struct data{
float amt;
char fname [30];
char lname [30];
} per;
main()
{
void print_per(struct data x);
printf(“Enter the donor’s first and last names separated by a space:”);
scanf(“%s %s”, per.fname, per.lname);
printf(“\nEnter the amount donated in rupees:”); 145
Functions, Structures, scanf(“%f”, &per.amt);
Pointers and print_per(per);
File Handling in C return 0;
}
OUTPUT
Enter the donor’s first and last names separated by a space: RAVI KANT
Enter the amount donated in rupees: 1000.00
RAVI KANT gave donation of the amount Rs. 1000.00.
You can also pass a structure to a function by passing the structure’s address(that is, a
pointer to the structure which we will be discussing in the next unit). In fact, in the
older versions of C, this was the only way to pass a structure as an argument. It is not
necessary now, but you might see the older programs that still use this method. If you
pass a pointer to a structure as an argument, remember that you must use the indirect
membership operator () to access structure members in the function.
Please note the following points with respect to passing the structure as a parameter to
a function.
The return value of the called function must be declared as the value that is being
returned from the function. If the function is returning the entire structure then the
return value should be declared as struct with appropriate tag name.
The actual and formal parameters for the structure data type must be the same as
the struct type.
The return statement is required only when the function is returning some data.
When the return values of type is struct, then it must be assigned to the structure
of identical type in the calling function.
Let us consider another example as shown in the Example 6.6, where structure salary
has three fields related to an employee, namely - name, no_days_worked and
daily_wage. To accept the values from the user we first call the function get_data that
gets the values of the members of the structure. Then using the wages function we
calculate the salary of the person and display it to the user.
Example 6.6
Write a program to accept the data from the user and calculate the salary of the person
using concept of functions.
/* Program to accept the data from the user and calculate the salary of the person*/
#include<stdio.h>
main()
{
struct sal {
char name[30];
int no_days_worked;
int daily_wage; };
struct sal salary;
struct sal get_dat(struct); /* function prototype*/
float wages(struct); /*function prototype*/
float amount_payable; /* variable declaration*/
146
salary = get_data(salary); Structures and
Unions
printf(“The name of employee is %s”,salary.name);
printf(“Number of days worked is %d”,salary.no_daya_worked);
printf(“The daily wage of the employees is %d”,salary.daily_wage);
amount_payable = wages(salary);
printf(“The amount payable to %s is %f”,salary.name,amount_payable);
}
float wages(struct)
{
struct sal amt;
int total_salary ;
total_salary = amt.no_days_worked * amt.daily_wages;
return(total_salary); }
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
2. How can I pass constant values to functions which accept structure arguments?
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
…………………………………………………………………………………..
3. What will be the output of the program?
#include<stdio.h>
main()
{
struct pqr{
int x ;
};
struct pqr pqr ; 147
Functions, Structures, pqr.x =10 ;
Pointers and printf(“%d”, pqr.x);
File Handling in C }
…………………………………………………………………………………………
…………………………………………………………………………………………
…………………………………………………………………………………………
So, revising the array for a few moments we would refresh the fact that an array is
simply a collection of homogeneous data types. Hence, if we make a declaration as:
int temp[20];
It simply means that temp is an array of twenty elements where each element is of
type integer, indicating homogenous data type. Now in the same manner, to extend the
concept a bit further to the structure variables, we would say,
It means that stud is an array of twenty elements where each element is of the type
struct student (which is a user-defined data type we had defined earlier). The various
members of the stud array can be accessed in the similar manner as that of any other
ordinary array.
For example,
struct student stud[20], we can access the roll_no of this array as
stud[0].roll_no;
stud[1].roll_no;
stud[2].roll_no;
stud[3].roll_no;
…
…
…
stud[19].roll_no;
Please remember the fact that for an array of twenty elements the subscripts of the
array will be ranging from 0 to 19 (a total of twenty elements). So let us now start by
seeing how we will write a simple program using array of structures.
Example 6.7
#include <stdio.h>
struct student { int roll_no;
char name[20];
char course[20];
int marks_obtained ;
};
main()
{
struct student stud [20];
int i;
printf(“Enter the student data one by one\n”);
for(i=0; i<=19; i++)
{
printf(“Enter the roll number of %d student”,i+1);
scanf(“%d”,&stud[i].roll_no);
printf(“Enter the name of %d student”,i+1);
scanf(“%s”,stud[i].name);
printf(“Enter the course of %d student”,i+1);
scanf(“%d”,stud[i].course);
printf(“Enter the marks obtained of %d student”,i+1);
scanf(“%d”,&stud[i].marks_obtained);
}
printf(“the data entered is as follows\n”);
for(i=0;i<=19;i++)
{
printf(“The roll number of %d student is %d\n”,i+1,stud[i].roll_no);
printf(“The name of %d student is %s\n”,i+1,stud[i].name);
printf(“The course of %d student is %s\n”,i+1,stud[i].course);
printf(“The marks of %d student is %d\n”,i+1,stud[i].marks_obtained);
}
}
The above program explains to us clearly that the array of structure behaves as any
other normal array of any data type. Just by making use of the subscript we can access
all the elements of the structure individually.
Extending the above concept where we can have arrays as the members of the
structure. For example, let’s see the above example where we have taken a structure
for the student record. Hence in this case it is a real world requirement that each
student will be having marks of more than one subject. Hence one way to declare the
structure, if we consider that each student has 3 subjects, will be as follows:
struct student {
int roll_no;
char name[20];
char course[20];
int subject1 ;
int subject2;
int subject3;
};
The above described method is rather a bit cumbersome, so to make it more efficient
we can have an array inside the structure, that is, we have an array as the member of
the structure.
struct student {
149
Functions, Structures, int roll_no;
Pointers and char name[20];
File Handling in C char course[20];
int subject[3] ;
};
Hence to access the various elements of this array we can the program logic as
follows:
Example 6.8
/*Program to read and print data related to five students having marks of three
subjects each using the concept of arrays */
#include<stdio.h>
struct student {
int roll_no;
char name[20];
char course[20];
int subject[3] ;
};
main()
{
struct student stud[5];
int i,j;
printf(“Enter the data for all the students:\n”);
for(i=0;i<=4;i++)
{
printf(“Enter the roll number of %d student”,i+1);
scanf(“%d”,&stud[i].roll_no);
printf(“Enter the name of %d student”,i+1);
scanf(“%s”,stud[i].name);
printf(“Enter the course of %d student”,i+1);
scanf(“%s”,stud[i].course);
for(j=0;j<=2;j++)
{
printf(“Enter the marks of the %d subject of the student %d:\n”,j+1,i+1);
scanf(“%d”,&stud[i].subject[j]);
}
}
printf(“The data you have entered is as follows:\n”);
for(i=0;i<=4;i++)
{
printf(“The %d th student's roll number is %d\n”,i+1,stud[i].roll_no);
printf(“The %d the student's name is %s\n”,i+1,stud[i].name);
printf(“The %d the student's course is %s\n”,i+1,stud[i].course);
for(j=0;j<=2;j++)
{
printf(“The %d the student's marks of %d I subject are %d\n”,i+1, j+1,
stud[i].subject[j]);
}
}
printf(“End of the program\n”);
}
Hence as described in the example above, the array as well as the arrays of structures
can be used with efficiency to resolve the major hurdles faced in the real world
programming environment.
150
Structures and
6.7 UNIONS Unions
Structures are a way of grouping homogeneous data together. But it often happens that
at any time we require only one of the member’s data. For example, in case of the
support price of shares you require only the latest quotations. And only the ones that
have changed need to be stored. So if we declare a structure for all the scripts, it will
only lead to crowding of the memory space. Hence it is beneficial if we allocate space
to only one of the members. This is achieved with the concepts of the UNIONS.
UNIONS are similar to STRUCTURES in all respects but differ in the concept of
storage space.
A UNION is declared and used in the same way as the structures. Yet another
difference is that only one of its members can be used at any given time. Since all
members of a Union occupy the same memory and storage space, the space allocated
is equal to the largest data member of the Union. Hence, the member which has been
updated last is available at any given time.
For example a union can be declared using the syntax shown below:
union union-tag {
datatype variable1;
datatype variable2;
...
};
For example,
union temp{
int x;
char y;
float z;
};
In this case a float is the member which requires the largest space to store its value
hence the space required for float(4 bytes) is allocated to the union. All members
share the same space. Let us see how to access the members of the union.
Example 6.9
151
Functions, Structures,
Pointers and
6.8 INITIALIZING AN UNION
File Handling in C
Let us see, how to initialize a Union with the help of the following example:
Example 6.10
union date_tag {
char complete_date [9];
struct part_date_tag {
char month[2];
char break_value1;
char day[2];
char break_value2;
char year[2];
} parrt_date;
}date = {“01/01/05”};
#include<stdio.h>
main()
{
union{
struct{
char x;
char y;
char z;
char w;
}xyz;
struct{
int p;
int q ;
}pq;
long a ;
float b;
double d;
}prq;
printf (“%d”,sizeof(prq));
}
152
Structures and
6.10 SUMMARY Unions
In this unit, we have learnt how to use structures, a data type that you design to meet
the needs of a program. A structure can contain any of C’s data types, including other
structures, pointers, and arrays. Each data item within a structure, called a member, is
accessed using the structure member operator (.) between the structure name and the
member name. Structures can be used individually, and can also be used in arrays.
Unions were presented as being similar to structures. The main difference between a
union and a structure is that the union stores all its members in the same area. This
means that only one member of a union can be used at a time.
3. Structures may have this padding (as well as internal padding), to ensure that
alignment properties will be preserved when an array of contiguous structures is
allocated. Even when the structure is not part of an array, the end padding remains,
so that sizeof can always return a consistent size.
4. struct date {
char month[2];
char day[2];
char year[4];
} current_date;
2. C has no way of generating anonymous structure values. You will have to use a
temporary structure variable or a little structure - building function.
3. 10
Check Your Progress 3
1. 8 153
Functions, Structures,
Pointers and
6.12 FURTHER READINGS
File Handling in C
154
Pointers
UNIT 7 POINTERS
Structure
7.0 Introduction
7.1 Objectives
7.2 Pointers and their Characteristics
7.3 Address and Indirection Operators
7.4 Pointer Type Declaration and Assignment
7.4.1 Pointer to a Pointer
7.4.2 Null Pointer Assignment
7.5 Pointer Arithmetic
7.6 Passing Pointers to Functions
7.6.1 A Function Returning More than One Value
7.6.2 Function Returning a Pointer
7.7 Arrays and Pointers
7.8 Array of Pointers
7.9 Pointers and Strings
7.10 Summary
7.11 Solutions / Answers
7.12 Further Readings
7.0 INTRODUCTION
C uses pointers in three main ways. First, they are used to create dynamic data
structures: data structures built up from blocks of memory allocated from the heap at
run-time. Second, C uses pointers to handle variable parameters passed to functions.
And third, pointers in C provide an alternative means of accessing information stored
in arrays, which is especially valuable when you work with strings.
A normal variable is a location in memory that can hold a value. For example, when
you declare a variable i as an integer, four bytes of memory is set aside for it. In your
program, you refer to that location in memory by the name i. At the machine level,
that location has a memory address, at which the four bytes can hold one integer value.
A pointer is a variable that points to another variable. This means that it holds the
memory address of another variable. Put another way, the pointer does not hold a
value in the traditional sense; instead, it holds the address of another variable. It points
to that other variable by holding its address.
Because a pointer holds an address rather than a value, it has two parts. The pointer
itself holds the address. That addresses points to a value. There is the pointer and the
value pointed to. As long as you’re careful to ensure that the pointers in your
programs always point to valid memory locations, pointers can be useful, powerful,
and relatively trouble-free tools. 155
Functions, Structures,
Pointers and We will start this unit with a basic introduction to pointers and the concepts
File Handling in C surrounding pointers, and then move on to the three techniques described above.
Thorough knowledge of the pointers is very much essential for your future courses
like the data structures etc..
7.1 OBJECTIVES
Example 7.1
Write a program to know the size of the various data types on your system.
# include <stdio.h>
main()
{
printf(“n Size of a int = %d bytes”, sizeof(int));
printf(“\n Size of a float = %d bytes”, sizeof(float));
printf(“\n Size of a char = %d bytes”, sizeof(char));
}
OUTPUT
An ordinary variable is a location in memory that can hold a value. For example,
when you declare a variable num as an integer, the compiler sets aside 2 bytes of
memory (depends up the PC) to hold the value of the integer. In your program, you
refer to that location in memory by the name num. At the machine level that location
has a memory address.
156
int num = 100; Pointers
We can access the value 100 either by the name num or by its memory address. Since
addresses are simply digits, they can be stored in any other variable. Such variables
that hold addresses of other variables are called Pointers. In other words, a pointer is
simply a variable that contains an address, which is a location of another variable in
memory. A pointer variable “points to” another variable by holding its address.
Since a pointer holds an address rather than a value, it has two parts. The pointer
itself holds the address. That addresses points to a value. There is a pointer and the
value pointed to. This fact can be a little confusing until you get comfortable with it,
but once you get familiar with it, then it is extremely easy and very powerful. One
good way to visualize this concept is to examine the figure 7.1 given below:
num
2 bytes – integer variable
ch
1 byte – character variable
temp
ptr1
2 bytes – int pointer variable
ptr2
2 bytes – char pointer variable
i. The program execution time will be faster as the data is manipulated with the
help of addresses directly.
ii. Will save the memory space.
iii. The memory access will be very efficient.
iv. Dynamic memory is allocated.
Now we will consider how to determine the address of a variable. The operator that is
available in C for this purpose is “&” (address of ) operator. The operator & and the
immediately preceding variable returns the address of the variable associated with it.
C’s other unary pointer operator is the “*”, also called as value at address or
indirection operator. It returns a value stored at that address. Let us look into the
illustrative example given below to understand how they are useful.
157
Functions, Structures,
Example 7.2
Pointers and
File Handling in C Write a program to print the address associated with a variable and value
stored at that address.
/* Program to print the address associated with a variable and value stored at that
address*/
# include <stdio.h>
main()
{
int qty = 5;
printf("Address of qty = %u\n",&qty);
printf("Value of qty = %d \n",qty);
printf("Value of qty = %d",*(&qty));
}
OUTPUT
Look at the printf statement carefully. The format specifier %u is taken to increase
the range of values the address can possibly cover. The system-generated address of
the variable is not fixed, as this can be different the next time you execute the same
program. Remember unary operator operates on single operands. When & is
preceded by the variable qty, has returned its address. Note that the & operator can
be used only with simple variables or array elements. It cannot be applied to
expressions, constants, or register variables.
Observe the third line of the above program. *(&qty) returns the value stored at
address 65524 i.e. 5 in this case. Therefore, qty and *(&qty) will both evaluate to 5.
We have seen in the previous section that &qty returns the address of qty and this
address can be stored in a variable as shown below:
ptr = &qty;
In C, every variable must be declared for its data type before it is used. Even this
holds good for the pointers too. We know that ptr is not an ordinary variable like any
integer variable. We declare the data type of the pointer variable as that of the type of
the data that will be stored at the address to which it is pointing to. Since ptr is a
variable, which contains the address of an integer variable qty, it can be declared as:
int *ptr;
158
ptr qty Variable Pointers
Example 7.3
# include <stdio.h>
main()
{
int qty = 5;
int *ptr; /* declares ptr as a pointer variable that points to an integer variable
*/
ptr = &qty; /* assigning qty’s address to ptr -> Pointer Assignment */
OUTPUT
/* Program that tries to reference the value of a pointer even though the pointer is
uninitialized */
# include <stdio.h>
main()
{
int *p; /* a pointer to an integer */
*p = 10;
printf(“the value is %d”, *p);
printf(“the value is %u”,p);
}
This gives you an error. The pointer p is uninitialized and points to a random location
in memory when you declare it. It could be pointing into the system stack, or the
global variables, or into the program’s code space, or into the operating system.
159
Functions, Structures,
When you say *p=10; the program will simply try to write a 10 to whatever random
Pointers and location p points to. The program may explode immediately. It may subtly corrupt
File Handling in C data in another part of your program and you may never realize it. Almost always, an
uninitialized pointer or a bad pointer address causes the fault.
This can make it difficult to track down the error. Make sure you initialize all
pointers to a valid address before dereferencing them.
Example 7.5
Let us say,
# include <stdio.h>
main()
{
int *p; /* a pointer to an integer */
int x;
p = &x;
*p=10;
printf("The value of x is %d",*p);
printf("\nThe address in which the x is stored is %d",p);
}
OUTPUT
The value of x is 10
The address in which the x is stored is 52004
This statement puts the value of 20 at the memory location whose address is the value
of px. As we know that the value of px is the address of x and so the old value of x is
replaced by 20. This is equivalent to assigning 20 to x. Thus we can change the value
of a variable indirectly using a pointer and the indirection operator.
Example 7.6
# include<stdio.h>
main()
{
160
int i = 100; Pointers
int *pi;
int **pii;
pi = &i;
pii = π
OUTPUT
Address of i = 65524
Address of i = 65524
Address of i = 65524
Address of pi = 65522
Address of pi = 65522
Address of pii = 65520
Value of i = 100
Value of i = 100
Value of i = 100
Value of i = 100
Consider the following memory map for the above shown example:
pii pi i Variable
65522 65524 100 Value
Example 7.7
# include<stdio.h>
# define NULL 0
161
Functions, Structures,
main()
Pointers and {
File Handling in C int *pi = NULL;
printf(“The value of pi is %u”, pi);
}
OUTPUT
The value of pi is 0
1. How is a pointer variable being declared? What is the purpose of data type
included in the pointer declaration?
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
2. What would be the output of following programs?
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
3. Explain the effect of the following statements:
(iii) int x;
void *ptr = &x;
*(int *) ptr = 10;
…………………………………………………………………………………………
…………………………………………………………………………………………
…………………………………………………………………………………………
162
Pointers
ptr1 = ptr2 + 3;
ptr ++;
-- ptr;
However, ptr++ will cause the pointer ptr to point the next address value of its type.
For example, if ptr is a pointer to float with an initial value of 65526, then after the
operation ptr ++ or ptr = ptr+1, the value of ptr would be 65530. Therefore, if we
increment or decrement a pointer, its value is increased or decreased by the length of
the data type that it points to.
2. If ptr1 and ptr2 are properly declared and initialized pointers, the following
operations are valid:
Note that there is a blank space between / and * in the last statement because if you
write /* together, then it will be considered as the beginning of a comment and the
statement will fail.
3. Expressions like ptr1 == ptr2, ptr1 < ptr2, and ptr2 != ptr1 are permissible
provided the pointers ptr1 and ptr2 refer to same and related variables. These
comparisons are common in handling arrays.
Suppose p1 and p2 are pointers to related variables. The following operations cannot
work with respect to pointers:
163
Functions, Structures,
In the first method, when arguments are passed by value, a copy of the values of
Pointers and actual arguments is passed to the calling function. Thus, any changes made to the
File Handling in C variables inside the function will have no effect on variables used in the actual
argument list.
However, when arguments are passed by reference (i.e. when a pointer is passed as
an argument to a function), the address of a variable is passed. The contents of that
address can be accessed freely, either in the called or calling function. Therefore, the
function called by reference can change the value of the variable used in the call.
Example 7.8
Write a program to swap the values using the pass by value and pass by reference
methods.
/* Program that illustrates the difference between ordinary arguments, which are
passed by value, and pointer arguments, which are passed by reference */
# include <stdio.h>
main()
{
int x = 10;
int y = 20;
void swapVal( int, int ); /* function prototype */
void swapRef( int *, int * ); /*function prototype*/
printf("PASS BY VALUE METHOD\n");
printf("Before calling function swapVal x=%d y=%d",x,y);
swapVal(x, y); /* copy of the arguments are passed */
printf("\nAfter calling function swapVal x=%d y=%d",x,y);
printf("\n\nPASS BY REFERENCE METHOD");
printf("\nBefore calling function swapRef x=%d y=%d",x,y);
swapRef(&x,&y); /*address of arguments are passed */
printf("\nAfter calling function swapRef x=%d y=%d",x,y);
}
In the function swapVal, arguments x and y are passed by value. So, any changes to
the arguments are local to the function in which the changes occur. Note the values of
x and y remain unchanged even after exchanging the values of x and y inside the
function swapVal.
Now consider the function swapRef. This function receives two pointers to integer
variables as arguments identified as pointers by the indirection operators that appear
in argument declaration. This means that in the function swapRef, arguments x and y
are passed by reference. So, any changes made to the arguments inside the function
swapRef are reflected in the function main(). Note the values of x and y is
interchanged after the function call swapRef.
Example 7.9
Write a program to find the perimeter and area of a rectangle, if length and breadth
are given by the user.
#include <stdio.h>
void main()
{
float len,br;
float peri, ar;
void periarea(float length, float breadth, float *, float *);
printf("\nEnter the length and breadth of a rectangle in metres: \n");
scanf("%f %f",&len,&br);
periarea(len,br,&peri,&ar);
printf("\nPerimeter of the rectangle is %f metres", peri);
printf("\nArea of the rectangle is %f sq. metres", ar);
}
Here in the above program, we have seen that the function periarea is returning two
values. We are passing the values of len and br but, addresses of peri and ar. As we
are passing the addresses of peri and ar, any change that we make in values stored at
addresses contained in the variables *perimeter and *area, would make the change
effective even in main() also.
Example: 7.10
# include<stdio.h>
void main()
{
float *a;
float *func(); /* function prototype */
a = func();
printf("Address = %u", a);
}
float *func()
{
float r = 5.2;
return(&r);
}
OUTPUT
Address = 65516
This program only shows how a function can return a pointer. This concept will be
used later while handling arrays.
1. Tick mark( )whether each of the following statements are true or false.
(v) A function can return more than one value. True False
Pointers and arrays are so closely related. An array declaration such as int arr[ 5 ]
will lead the compiler to pick an address to store a sequence of 5 integers, and arr is a
name for that address. The array name in this case is the address where the sequence
of integers starts. Note that the value is not the first integer in the sequence, nor is it
the sequence in its entirety. The value is just an address.
Now, if arr is a one-dimensional array, then the address of the first array element can
be written as &arr[0] or simply arr. Moreover, the address of the second array
element can be written as &arr[1] or simply (arr+1). In general, address of array
element (i+1) can be expressed as either &arr[ i] or as (arr+ i). Thus, we have two
different ways for writing the address of an array element. In the latter case i.e,
expression (arr+ i) is a symbolic representation for an address rather than an
arithmetic expression. Since &arr[ i] and (ar+ i) both represent the address of the ith
element of arr, so arr[ i] and *(ar + i) both represent the contents of that address i.e.,
the value of ith element of arr.
However, we can assign the value of one array element to another through a pointer,
for example,
Example 7.11
# include<stdio.h>
main()
{
Note that i is added to a pointer value (address) pointing to integer data type (i.e., the
array name) the result is the pointer is increased by i times the size (in bytes) of
integer data type. Observe the addresses 65516, 65518 and so on. So if ptr is a char
pointer, containing addresses a, then ptr+1 is a+1. If ptr is a float pointer, then ptr+
1 is a+ 4.
y
(arr+1) 4 5 6 Second 1-d array
*(arr + 2) *(*(arr+2) + 2)
The way there can be an array of integers, or an array of float numbers, similarly,
there can be array of pointers too. Since a pointer contains an address, an array of
pointers would be a collection of addresses. For example, a multidimensional array
can be expressed in terms of an array of pointers rather than a pointer to a group of
contiguous arrays.
int *arr[3];
168
rather than the conventional array definition, Pointers
int arr[3][5];
The subscript1, subscript2 indicate the maximum number of elements associated with
each subscript.
Example 7.12
# include <stdio.h>
# include <stdlib.h>
# define MAXROWS 3
void main()
{
int *ptr1[MAXROWS], *ptr2 [MAXROWS], *ptr3 [MAXROWS];
int rows, cols, i, j;
void inputmat(int *[ ], int, int);
void dispmat(int *[ ], int, int);
void calcdiff(int *[ ], int *[ ], int *[ ], int, int);
OUTPUT
In this program, ptr1, ptr2, ptr3 are each defined as an array of pointers to integers.
Each array has a maximum of MAXROWS elements. Since each element of ptr1,
ptr2, ptr3 is a pointer, we must provide each pointer with enough memory for each
row of integers. This can be done using the library function malloc included in
stdlib.h header file as follows:
170
This function reserves a block of memory whose size(in bytes) is equivalent to cols * Pointers
sizeof(int). Since cols = 3, so 3 * 2(size of int data type) i.e., 6 is allocated to each
ptr1[ 1 ], ptr1[ 2 ] and ptr1[ 3 ]. This malloc function returns a pointer of type void.
This means that we can assign it to any type of pointer. In this case, the pointer is
type-casted to an integer type and assigned to the pointer ptr1[ 1 ], ptr1[ 2 ] and
ptr1[ 3 ]. Now, each of ptr1[ 1 ], ptr1[ 2 ] and ptr1[ 3 ] points to the first byte of the
memory allocated to the corresponding set of one-dimensional integer arrays of the
original two-dimensional array.
The process of calculating and allocating memory at run time is known as dynamic
memory allocation. The library routine malloc can be used for this purpose.
Instead of using conventional array notation, pointer notation has been used for
accessing the address and value of corresponding array elements which has been
explained to you in the previous section. The difference of the array elements within
the function calcdiff is written as
Each initialize a variable to the string “INDIA”. The second declaration creates a
pointer variable country that points to the letter I in the string "INDIA" somewhere in
memory.
Once the base address is obtained in the pointer variable country, *country would
yield the value at this address, which gets printed through,
printf("%s", *country);
Here is a program that dynamically allocates memory to a character pointer using the
library function malloc at run-time. An advantage of doing this way is that a fixed
block of memory need not be reserved in advance, as is done when initializing a
conventional character array.
Example 7.13
# include <stdio.h>
# include <conio.h>
# include <stdlib.h>
main()
171
Functions, Structures,
{
Pointers and char *palin, c;
File Handling in C int i, count;
i = i-1;
palin[i] = '\0';
count = i;
if(palindrome(palin,count) == 1)
printf("\nEntered word is not a palindrome.");
else
printf("\nEntered word is a palindrome");
}
OUTPUT
char *country[ ] = {
“INDIA”, “CHINA”, “BANGLADESH”, “PAKISTAN”, “U.S”
};
172
The *country[ ] of the declaration indicates an array of five elements. The char* of Pointers
the declaration indicates that each element of array country is of type “pointer to
char”. Thus, country [0] will point to INDIA, country[ 1] will point to CHINA, and
so on.
Thus, even though the array country is fixed in size, it provides access to character
strings of any length. However, a specified amount of memory will have to be
allocated for each string later in the program, for example,
The country character strings could have been placed into a two-dimensional array
but such a data structure must have a fixed number of columns per row, and that
number must be as large as the largest string. Therefore, considerable memory is
wasted when a large number of strings are stored with most strings shorter than the
longest string.
Example 7.14
Write a program to enter a list of strings and rearrange them in alphabetical order,
using a one-dimensional array of pointers, where each pointer indicates the beginning
of a string:
# include <stdio.h>
# include <conio.h>
# include <stdlib.h>
# include <string.h>
main()
{
char *country[ 5 ];
int i;
for(i = 0; i < 5; i++)
{
country[ i ] =(char *) malloc(15 * sizeof(char));
}
printf("Enter five countries on a separate line\n");
readinput(country, 5);
reorder(country, 5);
printf("\nReordered list\n");
writeoutput(country, 5);
getch();
}
OUTPUT
Reordered list
BANGLADESH
CHINA
INDIA
PAKISTAN
SRILANKA
The limitation of the string array concept is that when we are using an array of
pointers to strings we can initialize the strings at the place where we are declaring the
array, but we cannot receive the strings from keyboard using scanf().
174
…………………………………………………………………………………… Pointers
……………………………………………………………………………………
2. How the indirection operator can be used to access a multidimensional array
element.
……………………………………………………………………………………
……………………………………………………………………………………
3. A C program contains the following declaration.
float temp[ 3 ][ 2 ] = {{13.4, 45.5}, {16.6, 47.8}, {20.2, 40.8}};
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
7.10 SUMMARY
In this unit we have studied about pointers, pointer arithmetic, passing pointers to
functions, relation to arrays and the concept of dynamic memory allocation. A
pointer is simply a variable that contains an address which is a location of another
variable in memory. The unary operator &, when preceded by any variable returns its
address. C’s other unary pointer operator is *, when preceded by a pointer variable
returns a value stored at that address.
Pointers are often passed to a function as arguments by reference. This allows data
items within the calling function to be accessed, altered by the called function, and
then returned to the calling function in the altered form. There is an intimate
relationship between pointers and arrays as an array name is really a pointer to the
first element in the array. Access to the elements of array using pointers is enabled
by adding the respective subscript to the pointer value (i.e. address of zeroth element)
and the expression preceded with an indirection operator.
As pointer declaration does not allocate memory to store the objects it points at,
therefore, memory is allocated at run time known as dynamic memory allocation. The
library routine malloc can be used for this purpose.
1. Refer to section 7.4. The data type included in the pointer declaration, refers to the
type of data stored at the address which we will be storing in our pointer.
2. (i) Compile-time Error : Lvalue Required. Means that the left side of an
assignment operator must be an addressable expression that include a variable
or an indirection through a pointer. 175
Functions, Structures,
Pointers and (ii) Multiplication of a pointer variable with a constant is invalid.
File Handling in C
3. (i) Refer section 7.4
(ii) Refer section 7.4
(iii) This means pointers can be of type void but can’t be de-referenced without
explicit casting. This is because the compiler can’t determine the size of the
object the pointer points to.
1 (i) True.
(ii) True.
(iii) False.
(iv) True.
(v) True.
(vi) True.
(ii) Address of the first element of the last row of array temp i.e. address of
element 20.2.
(iii) Will give you 0. To get the value of the last element of the first array i.e. the
correct syntax would be *(*(temp+0)+1).
(iv) Address of the last element of last row of array temp i.e. of 40.8.
(v) Displays the value 47.8 i.e., second element of last row of array temp.
(vi) Displays the value 20.2 i.e., first element of last row of array temp.
176
File Handling
UNIT 8 FILE HANDLING
Structure
8.0 Introduction
8.1 Objectives
8.2 File Handling in C Using File Pointers
8.2.1 Open a file using the function fopen()
8.2.2 Close a file using the function fclose()
8.3 Input and Output using file pointers
8.3.1 Character Input and Output in Files
8.3.2 String Input / Output Functions
8.3.3 Formatted Input / Output Functions
8.3.4 Block Input / Output Functions
8.4 Sequential Vs Random Access Files
8.5 Positioning the File Pointer
8.6 The Unbufferred I/O - The UNIX like File Routines
8.7 Summary
8.8 Solutions / Answers
8.9 Further Readings
8.0 INTRODUCTION
The examples we have seen so far in the previous units deal with standard input and
output. When data is stored using variables, the data is lost when the program exits
unless something is done to save it. This unit discusses methods of working with files,
and a data structure to store data. C views file simply as a sequential stream of bytes.
Each file ends either with an end-of-file marker or at a specified byte number recorded
in a system maintained, administrative data structure. C supports two types of files
called binary files and text files.
The difference between these two files is in terms of storage. In text files, everything
is stored in terms of text i.e. even if we store an integer 54; it will be stored as a 3-byte
string - “54\0”. In a text file certain character translations may occur. For example a
newline(\n) character may be converted to a carriage return, linefeed pair. This is what
Turbo C does. Therefore, there may not be one to one relationship between the
characters that are read or written and those in the external device. A binary file
contains data that was written in the same format used to store internally in main
memory.
For example, the integer value 1245 will be stored in 2 bytes depending on the
machine while it will require 5 bytes in a text file. The fact that a numeric value is in a
standard length makes binary files easier to handle. No special string to numeric
conversions is necessary.
The disk I/O in C is accomplished through the use of library functions. The ANSI
standard, which is followed by TURBO C, defines one complete set of I/O functions.
But since originally C was written for the UNIX operating system, UNIX standard
defines a second system of routines that handles I/O operations. The first method,
defined by both standards, is called a buffered file system. The second is the
unbuffered file system.
In this unit, we will first discuss buffered file functions and then the unbuffered file
functions in the following sections.
177
Functions, Structures, 8.1 OBJECTIVES
Pointers and
File Handling in C
After going through this unit you will be able to:
As already mentioned in the above section, a sequential stream of bytes ending with
an end-of-file marker is what is called a file. When the file is opened the stream is
associated with the file. By default, three files and their streams are automatically
opened when program execution begins - the standard input, standard output, and
the standard error. Streams provide communication channels between files and
programs.
For example, the standard input stream enables a program to read data from the
keyboard, and the standard output stream enables to write data on the screen.
Opening a file returns a pointer to a FILE structure (defined in <stdio.h>) that
contains information, such as size, current file pointer position, type of file etc., to
perform operations on the file. This structure also contains an integer called a file
descriptor which is an index into the table maintained by the operating system namely,
the open file table. Each element of this table contains a block called file control block
(FCB) used by the operating system to administer a particular file.
The standard input, standard output and the standard error are manipulated using file
pointers stdin, stdout and stderr. The set of functions which we are now going to
discuss come under the category of buffered file system. This file system is referred to
as buffered because, the routines maintain all the disk buffers required for reading /
writing automatically.
To access any file, we need to declare a pointer to FILE structure and then associate it
with the particular file. This pointer is referred as a file pointer and it is declared as
follows:
FILE *fp;
Once a file pointer variables has been declared, the next step is to open a file. The
fopen() function opens a stream for use and links a file with that stream. This function
returns a file pointer, described in the previous section. The syntax is as follows:
where mode is a string, containing the desired open status. The filename must be a
string of characters that provide a valid file name for the operating system and may
include a path specification. The legal mode strings are shown below in the table 12.1:
178
File Handling
Table 8.1: Legal values to the fopen() mode parameter
MODE MEANING
The following code fragment explains how to open a file for reading.
Code Fragment 1
#include <stdio.h>
main()
{
FILE *fp;
if ((fp=fopen(“file1.dat”, “r”))==NULL)
{
printf(“FILE DOES NOT EXIST\n”);
exit(0);
}
}
The value returned by the fopen() function is a file pointer. If any error occurs while
opening the file, the value of this pointer is NULL, a constant declared in <stdio.h>.
Always check for this possibility as shown in the above example.
This function flushes any unwritten data for stream, discards any unread buffered
input, frees any automatically allocated buffer, and then closes the stream. The return
value is 0 if the file is closed successfully or a constant EOF, an end-of file marker, if
an error occurred. This constant is also defined in <stdio.h>. If the function fclose() is
not called explicitly, the operating system normally will close the file when the
program execution terminates.
Once the file is closed, it cannot be used further. If required it can be opened in same
or another mode.
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
After opening the file, the next thing needed is the way to read or write the file. There
are several functions and macros defined in <stdio.h> header file for reading and
writing the file. These functions can be categorized according to the form and type of
data read or written on to a file. These functions are classified as:
getc()
putc()
getc() is used to read a character from a file and putc() is used to write a character to a
file. Their syntax is as follows:
The file pointer indicates the file to read from or write to. The character ch is formally
called an integer in putc() function but only the low order byte is used. On success
putc() returns a character(in integer form) written or EOF on failure. Similarly getc()
returns an integer but only the low order byte is used. It returns EOF when end-of-file
is reached. getc() and putc() are defined in <stdio.h> as macros not functions.
To check the end of file, C includes the function feof() whose prototype is:
It returns 1 if end of file has been reached or 0 if not. The following code fragment
explains the use of these functions.
Example 8.1
#include <stdio.h>
main()
{
FILE *fp1;
FILE *fp2;
int ch;
if((fp1=fopen(“f1.dat”,”r”)) == NULL)
{
printf(“Error opening input file\n”);
exit(0);
}
if((fp2=fopen(“f2.dat”,”w”)) == NULL)
{
181
Functions, Structures, printf(“Error opening output file\n”);
Pointers and exit(0);
File Handling in C }
while (!feof(fp1))
{
ch=getc(fp1);
putc(ch,fp2);
}
fclose(fp1);
fclose(fp2);
}
OUTPUT
If the file ”f1.dat” is not present, then the output would be:
Error opening input file
If the disk is full, then the output would be:
Error opening output file
If there is no error, then “f2.dat” would contain whatever is present in “f1.dat” after
the execution of the program, if “f2.dat” was not empty earlier, then its contents
would be overwritten.
If we want to read a whole line in the file then each time we will need to call character
input function, instead C provides some string input/output functions with the help of
which we can read/write a set of characters at one time. These are defined in the
standard library and are discussed below:
fgets()
fputs()
These functions are used to read and write strings. Their syntax is:
The integer parameter in fgets() is used to indicate that at most num-1 characters are to
be read, terminating at end-of-file or end-of-line. The end-of-line character will be
placed in the string str before the string terminator, if it is read. If end-of-file is
encountered as the first character, EOF is returned, otherwise str is returned. The
fputs() function returns a non-negative number or EOF if unsuccessful.
Example 8.2
Write a program read a file and count the number of lines in the file, assuming that a
line can contain at most 80 characters.
/*Program to read a file and count the number of lines in the file */
#include<stdio.h>
#include<conio.h>
#include<process.h>
void main()
{
FILE *fp;
182
int cnt=0; File Handling
char str[80];
if ((fp=fopen("lines.dat","r"))== NULL)
{ printf("File does not exist\n");
exit(0);
}
/* read the file till end of file is encountered */
while(!(feof(fp)))
{ fgets(str,80,fp); /*reads at most 80 characters in str */
cnt++; /* increment the counter after reading a line */
}
}/* print the number of lines */
printf(“The number of lines in the file is :%d\n”,cnt);
fclose(fp);
}
OUTPUT
Let us assume that the contents of the file “lines.dat” are as follows:
This is C programming.
I love C programming.
These functions are used for formatted input and output. These are identical to scanf()
and printf() except that the first argument is a file pointer that specifies the file to be
read or written, the second argument is the format string. The syntax for these
functions is:
Both these functions return an integer indicating the number of bytes actually read or
written.
183
Functions, Structures, Example 8.3
Pointers and
File Handling in C Write a program to read formatted data (account number, name and balance) from a
file and print the information of clients with zero balance, in formatted manner on the
screen.
#include<stdio.h>
main()
{
int account;
char name[30];
double bal;
FILE *fp;
if((fp=fopen("bank.dat","r"))== NULL)
printf("FILE not present \n");
else
do{
fscanf(fp,"%d%s%lf",&account,name,&bal);
if(!feof(fp))
{
if(bal==0)
printf("%d %s %lf\n",account,name,bal);
}
}while(!feof(fp));
}
OUTPUT
This program opens a file “bank.dat” in the read mode if it exists, reads the records
and prints the information (account number, name and balance) of the zero balance
records.
103 Swathi 0
105 Udit 0
Block Input / Output functions read/write a block (specific number of bytes from/to a
file. A block can be a record, a set of records or an array. These functions are also
defined in standard library and are described below.
fread()
fwrite()
184
These two functions allow reading and writing of blocks of data. Their syntax is: File Handling
In case of fread(), buf is the pointer to a memory area that receives the data from the
file and in fwrite(), it is the pointer to the information to be written to the file.
num_bytes specifies the number of bytes to be read or written. These functions are
quite helpful in case of binary files. Generally these functions are used to read or write
array of records from or to a file. The use of the above functions is shown in the
following program.
Example 8.4
Write a program using fread() and fwrite() to create a file of records and then read and
print the same file.
void main()
{
struct stud
{
char name[30];
int age;
int roll_no;
}s[30],st;
int i;
FILE *fp;
/* writing to a file*/
fwrite(s,sizeof(struct stud),30,fp);
fclose(fp);
#include<stdio.h>
#include<process.h>
#include<conio.h>
main()
{
FILE * fp1, * fp2;
double a,b,c;
fp1=fopen(“file1”, “w”);
fp2=fopen(“file2”, “w”);
fp1=fopen(“file1”, “r”);
fp2=fopen(“file2”,“r”);
fclose(fp1);
fclose(fp2);
}
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
……………………………………………………………………………………
186
File Handling
8.4 SEQUENTIAL Vs RANDOM ACCESS FILES
We have seen in section 12.0 that C supports two type of files – text and binary files,
also two types of file systems – buffered and unbuffered file system. We can also
differentiate in terms of the type of file access as Sequential access files and random
access files. Sequential access files allow reading the data from the file in sequential
manner which means that data can only be read in sequence. All the above examples
that we have considered till now in this unit are performing sequential access.
Random access files allow reading data from any location in the file. To achieve this
purpose, C defines a set of functions to manipulate the position of the file pointer. We
will discuss these functions in the following sections.
To support random access files, C requires a function with the help of which the file
pointer can be positioned at any random location in the file. Such a function defined in
the standard library is discussed below:
The function fseek() is used to set the file position. Its prototype is:
The first argument is the pointer to a file. The second argument is the number of bytes
to move the file pointer, counting from zero. This argument can be positive, negative
or zero depending on the desired movement. The third parameter is a flag indicating
from where in the file to compute the offset. It can have three values:
These three constants are defined in <stdio.h>. If successful fseek() returns zero.
Another function rewind() is used to reset the file position to the beginning of the file.
Its prototype is:
fseek(fp,0,SEEK_SET);
Another function ftell() is used to tell the position of the file pointer. Its prototype is:
Example 8.5
Write a program to search a record in an already created file and update it. Use the
same file as created in the previous example.
#include<stdio.h>
187
Functions, Structures, #include<conio.h>
Pointers and #include<stdio.h>
File Handling in C #include<process.h>
#include<string.h>
void main()
{
int r,found;
struct stud
{
char name[30];
int age;
int roll_no;
}st;
FILE *fp;
/* open the file in read/write mode */
if((fp=fopen("f1.dat","r+b"))==NULL)
{ printf("Error while opening the file \n");
exit(0);
}
OUTPUT
Let the roll_no of the record to be updated be 106. Now since this roll_no is not
present the output would be:
188
If the roll_no to be searched is 103, then if the new name is Sham, the output would File Handling
be the file with the contents:
Geeta 18 101
Leena 17 102
Sham 23 103
Lokesh 21 104
Amit 19 105
The buffered I/O system uses buffered input and output, that is, the operating system
handles the details of data retrieval and storage, the system stores data temporarily
(buffers it) in order to optimize file system access. The buffered I/O functions are
handled directly as system calls without buffering by the operating system. That is
why they are also known as low level functions. This is referred to as unbuffered I/O
system because the programmer must provide and maintain all disk buffers, the
routines do not do it automatically.
The low level functions are defined in the header file <io.h>.
These functions do not use file pointer of type FILE to access a particular file, but
they use directly the file descriptors, as explained earlier, of type integer. They are
also called handles.
Mode:
The access parameter is used in UNIX environment for providing the access to
particular users and is just included here for compatibility and can be set to zero.
open() function returns –1 on failure. It is used as:
Code fragment 2
int fd;
if ((fd=open(filename,mode,0)) == -1)
{ printf(“cannot open file\n”);
exit(1); }
If the file does not exist, open() the function will not create it. For this, the function
creat() is used which will create new files and re-write old ones. The prototype is:
189
Functions, Structures, It returns a file descriptor; if successful else it returns –1. It is not an error to create an
Pointers and already existing file, the function will just truncate its length to zero. The access
File Handling in C parameter is used to provide permissions to the users in the UNIX environment.
The function close() is used to close a file. The prototype is:
The functions read() and write() are used to read from and write to a file. Their
prototypes are:
The first parameter is the file descriptor returned by open(), the second parameter
holds the data which must be typecast to the format needed by the program, the third
parameter indicates the number of bytes to transferred. The return value tells how
many bytes are actually transferred. If this value is –1, then an error must have
occurred.
Example 8.6
Write a program to copy one file to another to illustrate the use of the above functions.
The program should expect two command line arguments indicating the name of the
file to be copied and the name of the file to be created.
main()
{
arr buf;
name fname, sname;
int fd1,fd2,size;
open(argv[2],O_WRONLY);
size=read(fd1,buf,80); /* read till end of file */
190
File Handling
while (size>0)
{ write(fd2,buf,80);
size=read(fd1,buf,80);
}
close(fd1);
close(fd2);
}
OUTPUT
If the number of arguments given on the command line is not correct then output
would be:
One file is opened in the read mode, and another file is opened in the write mode. The
output would be as follows is the file to be read is not present (let the file be f1.dat):
The output would be as follows if the disk is full and the file cannot be created (let the
output file be f2.dat):
lseek()
The function lseek() is provided to move to the specific position in a file. Its prototype
is:
This function is exactly the same as fseek() except that the file descriptor is used
instead of the file pointer.
Using the above defined functions, it is possible to write any kind of program dealing
with files.
2. Write a proper C statement with proper arguments that would be called to move the
file pointer back by 2 bytes.
……………………………………………………………………………………
……………………………………………………………………………………
2. Text files and binary files differ in terms of storage. In text files everything is
stored in terms of text while binary files stores exact memory image of the data i.e.
in text files 154 would take 3 bytes of storage while in binary files it will take 2
bytes as required by an integer.
2. The advantage of using these functions is that they are used for block read/write,
which means we can read or write a large set of data at one time thus increasing
the speed.
3. fscanf() and fprintf() functions are used for formatted input and output from a file.
APPENDIX-A
The ASCII (American Standard Code for Information Interchange) character set
defines 128 characters (0 to 127 decimal, 0 to FF hexadecimal, and 0 to 177 octal).
This character set is a subset of many other character sets with 256 characters,
including the ANSI character set of MS Windows, the Roman-8 character set of HP
systems, and the IBM PC Extended Character Set of DOS, and the ISO Latin-1
character set used by Web browsers. They are not the same as the EBCDIC character
set used on IBM mainframes. The first 32 values are non-printing control characters,
such as Return and Line feed. You generate these characters on the keyboard by
holding down the Control key while you strike another key. For example, Bell is value
7, Control plus G, often shown in documents as ^G. Notice that 7 is 64 less than the
value of G (71); the Control key subtracts 64 from the value of the keys that it
modifies. The table shown below gives the list of the control and printing characters.
196