0% found this document useful (0 votes)
16 views99 pages

C Programming AllClasses-Outline-99-197

The document discusses different types of storage classes in C programming language including automatic, global, static and external variables. It explains the concept of storage classes and visibility of variables and how variables of different storage classes differ in terms of scope and lifetime.

Uploaded by

SrinivasaRao
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
16 views99 pages

C Programming AllClasses-Outline-99-197

The document discusses different types of storage classes in C programming language including automatic, global, static and external variables. It explains the concept of storage classes and visibility of variables and how variables of different storage classes differ in terms of scope and lifetime.

Uploaded by

SrinivasaRao
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 99

Programming in C Unit 1

}
Self Assessment Questions
12. By modularizing the problem into different sub problems. Each sub
problem can be implemented as a _________ .
13. The main purpose of function is to save typing time. (True/False)

5.6 Summary
A function is a self-contained program segment that carries out some specific,
well-defined task. When you find that a program is hard to manage, it's often
because it has not been designed and broken up into functions cleanly. A
function is a “black box'' that we've locked part of our program into. The idea
behind a function is that it compartmentalizes part of the program. The function
main() is must in every C program. The function prototype is nothing but the
function declaration. Recursion is a process by which a function calls itself
repeatedly, until some specified condition has been met.

5.7 Terminal Questions


1. What is the significance of the keyword ‘void’?
2. What is the difference between function declaration and function definition?
3. Write a recursive function to find sum of even numbers from 2 to 10.
4. Write a recursive definition to find gcd of two numbers.
5. Write a recursive definition to find nth fibonacci number. The Fibonacci
series forms a sequence of numbers in which each number is equal to the
sum of the previous two numbers. In other words,
Fi=Fi-1 + Fi-2
where Fi refers to the ith Fibonacci number. The first two Fibonacci numbers
are 0 and 1, i.e, F1=0, F2=1;
6. What is the output of the following program ?
#include<stdio.h>
main()
{
int m, count;
int fun(int count);
for(count=1;count<=10;count++) {
m=fun(count);

Manipal University Jaipur Page No.: 99


Programming in C Unit 1

printf(“%d”, m);
}
}
int fun(int n)
{
int x;
x= n*n;
return x;
}
5.8 Answers for Self Assessment Questions
1. False
2. extern.
3. formal, actual
4. comma.
5. Function declaration
6. False
7. header
8. double fun(double, double);
9. Recursion.
10. True
11. 15
12. function
13. False

5.9 Answers for Terminal Questions


1. ‘void’ is the keyword used to specify that the function doesn’t return any
value. It can also be used to specify the absence of arguments.
2. Function declaration is a direction to the compiler that what type of data is
returned by the function, the function name and about the arguments
where as the function definition is actually writing the body of the function
along with the function header.
3. #include<stdio.h> main()
{
int n=10;
int fun(int n);
printf(“%d”, fun(n));

Manipal University Jaipur Page No.: 100


Programming in C Unit 1

}
int fun(int n)
{
if(n>0) return (n+fun(n-2));
}
4. gcd(m,n)= { m or n if m=n
GCD(m, m-n) if m>n GCD(n,m) if m<n }
5. fib(i)= { 0 if i=1
1 if i=2
fib(i-1)+fib(i-2) otherwise}
6. Square of the integers from 1 to 10 is displayed.

5.10 Exercises
1. Suppose function F1 calls function F2 within a C program. Does the order
of function definitions make any difference? Explain.
2. When a program containing recursive function calls is executed, how are
the local variables within the recursive function interpreted?
3. Express the following algebraic formula in a recursive form:
Y = (Xi+X2+...+Xn)
4. Write a function that will allow a floating point number to be raised to an
integer power.
5. Write a function to swap two numbers using pass by value technique.
What is the drawback of the function?

Manipal University Jaipur Page No.: 101


Programming in C Unit 1

Unit 6 Storage Classes


Structure:
6.1 Introduction
Objectives
6.2 Storage Classes and Visibility
6.3 Automatic or local variables
6.4 Global variables
6.5 Static variables
6.6 External variables
6.7 Summary
6.8 Terminal Questions
6.9 Answers for Self Assessment Questions
6.10 Answers for Terminal Questions
6.11 Exercises

6.1 Introduction
In the previous unit, you studied about functions. You found out that how
functions can be used to break the large problems into small problems and
then solve it. You studied how functions can be repeatedly called and used
again and again. In this unit, you will study about the types of storage classes
that are used in C. You will study how these storage classes are useful in
making the C language a very powerful computing language.
Variables are channels of communication within a program. You set a variable
to a value at one point in a program, and at another point (or points) you read
the value out again. The two points may be in adjoining statements, or they
may be in widely separated parts of the program. How long does a variable
last? How widely separated can the setting and fetching parts of the program
be, and how long after a variable is set does it persist? Depending on the
variable and how you're using it, you might want different answers to these
questions. For example, in some situations it may be desirable to introduce
certain “global” variables that are recognized throughout the entire program (or
within major portions of the program, e.g. two or more functions). Such
variables are defined differently than the usual “local” variables, which are
recognized only within a single function.
We will also consider the issue of static variables which can retain their values,

Manipal University Jaipur Page No.: 102


Programming in C Unit 1

so that the function can be reentered later and the computation resumed.
Finally, we may be required to develop a large, multifunction program in terms
of several independent files, with few functions defined within each file. In such
programs, the individual functions can be defined and accessed locally within
a single file, or globally within multiple files.
Objectives:
After studying this unit, you should be able to:
• implement the concept of storage classes and visibility of variables
• explain the difference between automatic variables, global variables, static
variables and external variables.
• compile and execute a program made up of more than one source files.

6.2 Storage Classes and Visibility


There are two ways to categorize variables: by data type, and by storage class.
Data type refers to the type of information represented by a variable, for
example, integer number, floating-point number, character etc. Storage class
refers to the persistence of a variable and its scope within the program, that is,
the portion of the program over which the variable is recognized.
The following types of storage-class specifications in C are discussed in this
unit: global, automatic or local, static, and extern. The exact procedure for
establishing a storage class for a variable depends upon the particular storage
class, and the manner in which the program is organized, (i.e. single file vs.
multiple file).
The visibility of a variable determines how much of the rest of the program can
access that variable. You can arrange that a variable is visible only within one
part of one function, or in one function, or in one source file, or anywhere in the
program.
Why would you want to limit the visibility of a variable? For maximum flexibility,
wouldn't it be handy if all variables were potentially visible everywhere? As it
happens, that arrangement would be too flexible: everywhere in a program,
you would have to keep track of the names of all the variables declared
anywhere else in the program, so that you didn't accidentally re-use one.
Whenever a variable had the wrong value by mistake, you'd have to search
the entire program for the bug, because any statement in the entire program

Manipal University Jaipur Page No.: 103


Programming in C Unit 1

could potentially have modified that variable. You would constantly be stepping
all over yourself by using a common variable name like i in two parts of your
program, and having one snippet of code accidentally overwrite the values
being used by another part of the code.
Self Assessment Questions
1. The visibility of a variable determines how much of the rest of the program
can access that variable. (True/False)
2. class refers to the persistence of a variable and its scope
within the program, that is, the portion of the program over which the
variable is recognized.
3. Visibility provides security for your data used in a program. (True/False)

6.3 Automatic or local variables


A variable declared within the braces {} of a function is visible only within that
function; variables declared within functions are called local variables. Their
scope is confined to that function. You can use the keyword auto to declare
automatic variables, but, however it is optional. If another function somewhere
else declares a local variable with the same name, it's a different variable
entirely, and the two don't clash with each other. If an automatic variable is not
initialized in some manner, however, its initial value will be unpredictable and
contains some garbage value.
Program 6.1: Program to find factorial of a number
#include<stdio.h> main()
{
auto int n; /* Here the keyword auto is optional */
long int fact(int);
printf(“read the integer n:”);
scanf(“%d”, &n);
printf(“\nn!=%ld”, fact(n) );
}
long int fact(auto int n) /* n is local to the function fact() and auto is optional*/
{
auto int i; /* Here the keyword auto is optional */
auto long int factorial=1; /* Here the keyword auto is optional */
while(n>0) {
factorial=factorial*n;

Manipal University Jaipur Page No.: 104


Programming in C Unit 1

n=n-1;
}
return factorial;
}
An automatic variable doesn’t retain its value once control is transferred out of
its defining function. Therefore, any value assigned to an automatic variable
within a function will be lost once the function is exited.
Self Assessment Questions
4. The scope of an automatic variable is in _____________ in which it is
declared.
5. Does an automatic variable retain its value once control is transferred out
of its defining function? (Yes/No)
6. The key word auto is must in the declaration of automatic variables.
(True/False)

6.4 Global Variables


A variable declared outside of any function is a global variable, and it is
potentially visible anywhere within the program. You use global variables when
you do want to use the variable in any part of the program. When you declare
a global variable, you will usually give it a longer, more descriptive name (not
something generic like i) so that whenever you use it you will remember that
it's the same variable everywhere. The values stored in global variables
persist, for as long as the program does. (Of course, the values can in general
still be overwritten, so they don't necessarily persist forever.)
Program 6.2: Program to find average length of several lines of text
#include<stdio.h>
/* Declare global variables outside of all the functions*/
int sum=0; /* total number of characters */
int lines=0; /* total number of lines */
main()
{
int n; /* number of characters in given line */
float avg; /* average number of characters per line */
void linecount(void); /* function declaraction */
float cal_avg(void);
printf(“Enter the text below:\n”);

Manipal University Jaipur Page No.: 105


Programming in C Unit 1

while((n=linecount())>0) {
sum+=n;
++lines;
}

avg=cal_avg();
printf(“\nAverage number of characters per line: %5.2f”, avg);
}
void linecount(void)
{
/* read a line of text and count the number of characters */
char line[80];
int count=0;
while((line[count]=getchar())!=’\n’)
++count;
return count;
}
float cal_avg(void)
{
/* compute average and return*/ return (float)sum/lines;
}
In the above program the variables sum and lines are globally declared and
hence they could be used in both the functions main() and cal_avg()
Self Assessment Questions
7. The variables declared in the main() function are the global variables.
(True/False)
8. The global variables are more secured than the automatic variables in a
program. (True/False)

6.5 Static Variables


Static variables are defined within individual functions and therefore have the
same scope as automatic variables, i.e. they are local to the functions in which
they are declared. Unlike automatic variables, however, static variables retain
their values throughout the life of the program. As a result, if a function is exited
and then reentered later, the static variables defined within that function will

Manipal University Jaipur Page No.: 106


Programming in C Unit 1

retain their previous values. This feature allows functions to retain information
permanently throughout the execution of a program. Static variables can be
utilized within the function in the same manner as other variables. They cannot
be accessed outside of their defining function.
In order to declare a static variable the keyword static is used as shown below:
static int count;
You can define automatic or static variables having the same name as global
variables. In such situations the local variables will take precedence over the
global variables, though the values of global variables will be unaffected by any
manipulation of the local variables.
Initial values can be included in static variable declaration. The rules
associated with the initialization remain same as the initialization of automatic
or global variables. They are:
1. The initial values must be constants, not expressions.
2. The initial values are assigned to their respective variables at the beginning
of the program execution. The variables retain these values throughout the
life of the program, unless different values are assigned during the course
of computation.
3. Zeros will be assigned to all static variables whose declarations do not
include explicit initial values.
Program 6.3: Program to generate Fibonacci numbers.
#include<stdio.h>
main()
{
int count, n;
long int fib(int);
printf(“\n How many Fibonacci numbers?”);
scanf(“%d\n”, &n);
for(count=1;count<=n;count++)
{
printf(“\ni=%d F=%ld”, count, fib(count));
}
long int fib(int count)
{
/* calculate a Fibonacci number using the formula

Manipal University Jaipur Page No.: 107


Programming in C Unit 1

if i=1, F=0; if i=2, F=1, and F=F1+F2 for i>=3 */


static long int f1=0, f2=1; /* declaration of static variables */
long int f;
if (count==1)
f=0;
else if (count==2)
f=1;
else
f=f1+f2;
f2=f1;
f1=f; /* f1 and f2 retain their values between different calls of the
function*/
return f;
}
Self Assessment Questions
9. The scope of static variables and automatic variables is the same.
(True/False)
10. variables retain their values throughout the life of the
program. As a result, if a function is exited and then reentered later, the
static variables defined within that function will retain their previous
values.
11. By default, a static variable is initialized to _______.
6.6 External Variables
It is possible to split a function up into several source files, for easier
maintenance. When several source files are combined into one program the
compiler must have a way of correlating the variables which might be used to
communicate between the several source files. Furthermore, if a variable is
going to be useful for communication, there must be exactly one of it: you
wouldn't want one function in one source file to store a value in one variable
named externvar, and then have another function in another source file read
from a different variable named externvar. Therefore, a variable should have
exactly one defining instance, in one place in one source file. If the same
variable is to be used anywhere else (i.e. in some other source file or files), the
variable is declared in those other file(s) with an external declaration, which is
not a defining instance. The external declaration says the compiler that the
variable will be used in this source file but defined in some other source file.
Thus the compiler doesn’t allocate space for that variable with this source file.
Manipal University Jaipur Page No.: 108
Programming in C Unit 1

To make a variable as an external declaration, which is defined somewhere


else; you precede it with the keyword extern:
extern int j;
Program 6.4: Program to illustrate the concept of external variables.
Type and save the following program in a source file called externvariables.h
int principle=10000;
float rate=5.5;
int time=2;
float interest;
Type and save the following program in a separate source file called
demoexternvar.c
#include<stdio.h>
#include “extemvariables.h” /* the source file where the external variables are
defined should be included here.*/
main()
{
/* external declarations of the variables which are defined in
externvariables.h */
extern int principle;
extern float rate;
extern int time;
extern float interest;
/*compute interest*/
interest= principle*rate*ti me/100.0;
printf(“Interest=%f\n”, interest);
}
Compile demoexternvar.c and execute the program.
The concept of external storage class can be extended to functions also. A
source file can access a function defined in any other source file provided the
source file is included within the source file where you access that function.
Program 6.5: Program to illustrate the concept of external functions.
Type and save the following program in a file externfunction.h
void output(void)

Manipal University Jaipur Page No.: 109


Programming in C Unit 1

{
printf(“ Hi, Manipal!\n”);
return;
}
Type and save the following program in a separate source file called
demoexternfun.c
#include<stdio.h>
#include “ externfunction.h”
extern void output(void);
main()
{
output();
}
Compile and execute the above program and observe the result.
However, the keyword extern is optional in some C compilers.
Self Assessment Questions
12. The main purpose of using external variables is to access the same
variable in different _____________ files.
13. Compiler doesn’t allocate memory for an external variable where it is
accessed. (True/False)
14. Global variables and external variables have the same scope.
(True/False)
Example 6.1: Here is an example demonstrating almost everything we've seen
so far:
int globalvar = 1;
extern int anotherglobalvar;
static int privatevar;
f()
{
int localvar;
int localvar2 = 2;
static int persistentvar;
}
Here we have six variables, three declared outside and three declared inside

Manipal University Jaipur Page No.: 110


Programming in C Unit 1

of the function f().


globalvar is a global variable. The declaration we see is its defining instance
(it happens also to include an initial value). globalvar can be used anywhere
in this source file, and it could be used in other source files, too (as long as
corresponding external declarations are issued in those other source files).
anotherglobalvar is a second global variable. It is not defined here; the
defining instance for it (and its initialization) is somewhere else.
privatevar is a “private'' global variable. It can be used anywhere within this
source file, but functions in other source files cannot access it, even if they try
to issue external declarations for it. (If other source files try to declare a global
variable called ‘’privatevar'', they'll get their own; they won't be sharing this
one.) Since it has static duration and receives no explicit initialization,
privatevar will be initialized to 0.
localvar is a local variable within the function f(). It can be accessed only within
the function f(). (If any other part of the program declares a variable named
“localvar'', that variable will be distinct from the one we're looking at here.)
localvar is conceptually “created'' each time f() is called, and disappears when
f() returns. Any value which was stored in localvar last time f() was running
will be lost and will not be available next time f() is called. Furthermore, since
it has no explicit initializer, the value of localvar will in general be garbage
each time f() is called.
localvar2 is also local, and everything that we said about localvar applies to
it, except that since its declaration includes an explicit initializer, it will be
initialized to 2 each time f() is called.
Finally, persistentvar is again local to f(), but it does maintain its value
between calls to f(). It has static duration but no explicit initializer, so its initial
value will be 0.
The term declaration is a general one which encompasses defining instances
and external declarations; defining instances and external declarations are two
different kinds of declarations. Furthermore, either kind of declaration suffices
to inform the compiler of the name and type of a particular variable (or
function). If you have the defining instance of a global variable in a source file,
the rest of that source file can use that variable without having to issue any
external declarations. It's only in source files where the defining instance hasn't

Manipal University Jaipur Page No.: 111


Programming in C Unit 1

been seen that you need external declarations.


You will sometimes hear a defining instance referred to simply as a “definition,''
and you will sometimes hear an external declaration referred to simply as a
“declaration.'' These usages are mildly ambiguous, in that you can't tell out of
context whether a “declaration'' is a generic declaration (that might be a
defining instance or an external declaration) or whether it's an external
declaration that specifically is not a defining instance. Similarly, there are other
constructions that can be called “definitions'' in C, namely the definitions of
preprocessor macros, structures, and typedefs etc.
Program 6.6: Program to illustrate the hiding of variables in blocks
/* hiding.c -- variables in blocks */
#include <stdio.h> int main() {
int x = 30;
printf("x in outer block: %d\n", x);
{
int x = 77; /* new x, hides first x */ printf("x in inner block: %d\n", x); }
printf("x in outer block: %d\n", x); while (x++ < 33) {
int x = 100; /* new x, hides first x */ x++;
printf("x in while loop: %d\n", x);
}
return 0;
}
6.7 Summary
Variables are channels of communication within a program. Storage class
refers to the persistence of a variable and its scope within the program, that is,
the portion of the program over which the variable is recognized. The scope of
a local or automatic variable is confined to the function where it is defined. A
global variable is potentially visible anywhere within the program in which it is
defined. Static variables retain their values throughout the life of the program.
As a result, if a function is exited and then reentered later, the static variables
defined within that function will retain their previous values. The external
variable declaration says the compiler that the global variable will be used in
this source file but defined in some other source file.

6.8 Terminal Questions

Manipal University Jaipur Page No.: 112


Programming in C Unit 1

1. List some of the storage classes available in C.


2. What is the use of header file? Is the use of header file absolutely
necessary?
3. What is the difference between declaration and definition of function?
4. What is the significance of external declaration?
5. How can you justify that variables are channels of communication in a
program?

6.9 Answers to Self Assessment Questions


1. True
2. Storage
3. True
4. The function in which it is declared.
5. No
6. False
7. False
8. False
9. True
10. Static.
11. Zero
12. source
13. True
14. False

6.9 Answers for Terminal Questions


1. automatic, global, static, extern
2. Header files are used to define some variables and functions separately in
a library. Built-in header files are absolutely necessary if you want to
access the variables and functions defined in them.
3. Declaration is nothing but the prototype that contains the type of returned
data, name of the function and type of the arguments. But the definition
contains the function header and the body of the function.
4. The external declaration says the compiler that the variable will be used in
this source file but defined in some other source file.
5. You set a variable to a value at one point in a program, and at another

Manipal University Jaipur Page No.: 113


Programming in C Unit 1

point (or points) you read the value out again. Thus the transfer of
information from one point of the program to another is nothing but the
communication.
6.10 Exercises
1. Distinguish between the following
i. Global and local variables
ii. Automatic and static variables
iii. Global and extern variables
2. Write a program to count the number of times a function is called using
static variables.
3. Write a function prime that returns 1 if its argument is a prime number and
returns zero Otherwise.
4. Write a function that will round a floating point number to an indicated
decimal place. For example, the number 12.456 would yield the value 12.
46 when it is rounded off to two decimal places.
5. Write a program to illustrate the concept of extern variables.

Manipal University Jaipur Page No.: 114


Programming in C Unit 1

Unit 7 Arrays and Strings


Structure:
7.1 Introduction
Objectives
7.2 One Dimensional Arrays
Passing Arrays to Functions
7.3 Multidimensional Arrays
7.4 Strings
7.5 Summary
7.6 Terminal Questions
7.7 Answers for Self Assessment Questions
7.8 Answers for Terminal Questions
7.9 Exercises

7.1 Introduction
In the previous unit, you studied about the various types of storage classes
that are used in C. You studied how those storage classes are used in different
situations in C. In this unit, you will study about the arrays and strings. You will
learn how arrays and strings are formed and manipulated.
Many applications require processing of multiple data items that have common
characteristics. In such situations it is always convenient to place the data
items into an array, where they will share the same name. An array is a
collection of similar type of elements. All elements in the array are referred with
the array name. Since arrays hold a group of data, it is very easy to perform
looping and arithmetic operations on group of data. This chapter covers the
processing of both one-dimensional and two-dimensional arrays.
Objectives:
After studying this unit, you should be able to:
• declare, initialize and process one-dimensional and two-dimensional
arrays
• explain about strings and how to process them
• describe the library functions available in C to process strings
7.2 One Dimensional Arrays
So far, we've been declaring simple variables: the declaration int i;
declares a single variable, named i, of type int. It is also possible to declare an

Manipal University Jaipur Page No.: 115


Programming in C Unit 1

array of several elements. The declaration


int a[10];
declares an array, named a, consisting of ten elements, each of type int.
Simply speaking, an array is a variable that can hold more than one value. You
specify which of the several values you're referring to at any given time by
using a numeric subscript. (Arrays in programming are similar to vectors or
matrices in mathematics.) We can represent the array a above with a picture
like this:

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
In C, arrays are zero-based: the ten elements of a 10-element array are
numbered from 0 to 9. The subscript which specifies a single element of an
array is simply an integer expression in square brackets. The first element of
the array is a[0], the second element is a[1], etc. You can use these “array
subscript expressions'' anywhere you can use the name of a simple variable,
for example:
a[0] = 10;
a[1] = 20;
a[2] = a[0] + a[1];
Notice that the subscripted array references (i.e. expressions such as a[0] and
a[1]) can appear on either side of the assignment operator.
The subscript does not have to be a constant like 0 or 1; it can be any integral
expression. For example, it's common to loop over all elements of an array:
int i;
for(i = 0; i < 10; i = i + 1)
a[i] = 0;
This loop sets all ten elements of the array a to 0.
Arrays are a real convenience for many problems, but there is not a lot that C
will do with them for you automatically. In particular, you can neither set all
elements of an array at once nor assign one array to another; both of the
assignments
a = 0; /* WRONG */

Manipal University Jaipur Page No.: 116


Programming in C Unit 1

and
int b[10];
b = a; /* WRONG */
are illegal.
To set all of the elements of an array to some value, you must do so one by
one, as in the loop example above. To copy the contents of one array to
another, you must again do so one by one:
int b[10];

for(i = 0; i < 10; i = i + 1) b[i] = a[i];


Remember that for an array declared
int a[10];
there is no element a[10]; the topmost element is a[9]. This is one reason that
zero-based loops are also common in C. Note that the for loop
for(i = 0; i < 10; i = i + 1) ...
does just what you want in this case: it starts at 0, the number 10 suggests
(correctly) that it goes through 10 iterations, but the less-than comparison
means that the last trip through the loop has i set to 9. (The comparison i <= 9
would also work, but it would be less clear and therefore poorer style.)
In the little examples so far, we've always looped over all 10 elements of the
sample array a. It's common, however, to use an array that's bigger than
necessarily needed, and to use a second variable to keep track of how many
elements of the array are currently in use. For example, we might have an
integer variable
int na; /* number of elements of a[] in use */
Then, when we wanted to do something with a (such as print it out), the loop
would run from 0 to na, not 10 (or whatever a's size was):
for(i = 0; i < na; i = i + 1)
printf("%d\n", a[i]);
Naturally, we would have to ensure that na's value was always less than or
equal to the number of elements actually declared in a.
Arrays are not limited to type int; you can have arrays of char or double or

Manipal University Jaipur Page No.: 117


Programming in C Unit 1

any other type.


Here is a slightly larger example of the use of arrays. Suppose we want to
investigate the behavior of rolling a pair of dice. The total roll can be anywhere
from 2 to 12, and we want to count how often each roll comes up. We will use
an array to keep track of the counts: a[2] will count how many times we've
rolled 2, etc.
We'll simulate the roll of a die by calling C's random number generation
function, rand(). Each time you call rand(), it returns a different, pseudorandom
integer. The values that rand() returns typically span a large range, so we'll use
C's modulus (or “remainder'') operator % to produce random numbers in the
range we want. The expression rand() % 6 produces random numbers in the
range 0 to 5, and rand() % 6 + 1 produces random numbers in the range 1 to
6.
Program 7.1: Program to simulate the roll of a die
#include <stdio.h>
#include <stdlib.h> main()
{
int i;
int d1, d2;
int a[13]; /* uses [2..12] */

for(i = 2; i <= 12; i = i + 1)


a[i] = 0;

for(i = 0; i < 100; i = i + 1)


{
di = rand() % 6 + 1;
d2 = rand() % 6 + 1;
a[d1 + d2] = a[d1 + d2] + 1;
}

for(i = 2; i <= 12; i = i + 1)


printf("%d: %d\n", i, a[i]);

return 0;
}

Manipal University Jaipur Page No.: 118


Programming in C Unit 1

We include the header <stdlib.h> because it contains the necessary


declarations for the rand() function. We declare the array of size 13 so that its
highest element will be a[12]. (We're wasting a[0] and a[1]; this is no great
loss.) The variables d1 and d2 contain the rolls of the two individual dice; we
add them together to decide which cell of the array to increment, in the line
a[d1 + d2] = a[d1 + d2] + 1;
After 100 rolls, we print the array out. Typically, we'll see mostly 7's, and
relatively few 2's and 12's.
7.2.1 Passing Arrays to Functions
An array name can be used as an argument to a function, thus permitting the
entire array to be passed to the function. To pass an array to a function, the
array name must appear by itself, without brackets or subscripts, as an actual
argument within the function call. The corresponding formal argument is written
in the same manner, though it must be declared as an array within the formal
argument declarations. When declaring a one-dimensional array as a formal
argument, the array name is written with a pair of empty square brackets. The
size of the array is not specified within the formal argument declaration.

Program 7.2: The following program illustrates the passing of an array from
the main to a function. This program is used to find the average of n floating
point numbers.
#include<stdio.h>
main()
{
int n, i;
float avg;
float list[100];
float average(int, float[]); /* function prototype */
printf(“How many numbers:”);
scanf(“%d”,&n);
printf(“ Enter the numbers:”);
for(i=1;i<=n;i++)
scanf(“%f”, &list[i]);
avg=average(n, list); /* Here list and n are actual arguments */
printf(“Average=%f\n”, avg);

Manipal University Jaipur Page No.: 119


Programming in C Unit 1

}
float average(int a, float x[ ])
{
float avg;
float sum=0;
int i;
for(i=0;i<a;i++)
sum=sum+x[i];/* find sum of all the numbers */
avg=sum/a; /* find average */
return avg;
}

Self Assessment Questions


1. In C, an array subscript starts from _________
2. An array name is a pointer. (True/False)
3. Will there be a compilation error for the following program
segment?(Yes/No)
int a[5] = {1, 2, 3, 4, 5};
int b[5] = {5, 4, 3, 2, 1};
int c[5][5];

c=a+b;
7.3 Multidimensional Arrays
The C language allows arrays of any dimension to be defined. In this section,
we will take a look at two-dimensional arrays. One of the most natural
applications for a two-dimensional array arises in the case of a matrix. In C,
the two-dimensional matrix can be declared as follows:
int array[3][6];
Following is the way of declaring as well as initializing two-dimensional
arrays.
int array[3][6] = {
{4,5,6,7,8,9},
{1,5,6,8,2,4},
{0,4,4,3,1,1}
};
Such arrays are accessed like so:
array[1][4]= -2;
Manipal University Jaipur Page No.: 120
Programming in C Unit 1

if (array[2][1] > 0) {
printf ("Element [2][1] is %d", array[2][1]);
}
Remember that, like ordinary arrays, two-dimensional arrays are numbered
from 0. Therefore, the array above has elements from array[0][0] to
array[2][5].

Program 7.3: Program to add two matrices


#include <stdio.h> main()
{
int a[5][5], b[5][5], c[5][5];
int i, j, m, n;
printf(“Enter the order of the matrices:”);
scanf(“%d%d”, &m, &n);
printf(“ Enter the elements of A matrix: \n”);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf(“%d”, &a[i][j]);
printf(“Enter the elements of B matrix: \n”);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf(“%d”, &b[i][j]);
/* Add the matrices */ for(i=0;i<m;i++) for(j=0;j<n;j++) c[i][j] =
a[i][j]+b[i][j];
/* Print the sum */
printf(“The sum of matrices: \n”);
for(i=0;i<m;i++) { for(j=0;j<n;j++) printf(“%d\t”, c[i][j]); printf(“\n”);
}}
Multidimensional arrays are processed in the same manner as onedimensional
arrays, on an element-by-element basis. However, some care is required when
passing multidimensional arrays to a function. In particular, the formal
argument declarations within the function definition must include explicit size
specifications in all of the subscript positions except the first. These size
specifications must be consistent with the corresponding size specifications in
the calling program. The first subscript position may be written as an empty
pair of square brackets, as with a one-dimensional array. The corresponding

Manipal University Jaipur Page No.: 121


Programming in C Unit 1

function prototypes must be written in the same manner. But while calling the
function the array name may be passed as the actual argument as in the case
of one-dimensional arrays. E.g:
void process_array (int [][6]); /* function prototype */
void process_array (int array[][6])/*function definition */ {

}
Self Assessment Questions
4. In a two-dimensional matrix, the first subscript in the declaration specifies
number of _______________________ .
5. A two-dimensional array is considered as an array of one-dimensional
arrays. (True/False)
7.4 Strings
Strings in C are represented by arrays of characters. The end of the string is
marked with a special character, the null character, which is simply the
character with the value 0. (The null character has no relation except in name
to the null pointer. In the ASCII character set, the null character is named
NULL.) The null or string-terminating character is represented by another
character escape sequence, \0.
Because C has no built-in facilities for manipulating entire arrays (copying
them, comparing them, etc.), it also has very few built-in facilities for
manipulating strings.
In fact, C's only truly built-in string-handling is that it allows us to use string
constants (also called string literals) in our code. Whenever we write a string,
enclosed in double quotes, C automatically creates an array of characters for
us, containing that string, terminated by the \0 character. For example, we can
declare and define an array of characters, and initialize it with a string constant:
char string[ ] = "Hello, world!";
In this case, we can leave out the dimension of the array, since the compiler
can compute it for us based on the size of the initializer (14, including the
terminating \0). This is the only case where the compiler sizes a string array
for us, however; in other cases, it will be necessary that we decide how big the
arrays and other data structures we use to hold strings are.
To do anything else with strings, we must typically call functions. The C library

Manipal University Jaipur Page No.: 122


Programming in C Unit 1

contains a few basic string manipulation functions, and to learn more about
strings, we'll be looking at how these functions might be implemented.
Since C never lets us assign entire arrays, we use the strcpy function to copy
one string to another:
#include <string.h>
char string1[ ] = "Hello, world!";
char string2[20];
strcpy(string2, string1);
The destination string is strcpy's first argument, so that a call to strcpy mimics
an assignment expression (with the destination on the left-hand side). Notice
that we had to allocate string2 big enough to hold the string that would be
copied to it. Also, at the top of any source file where we're using the standard
library's string-handling functions (such as strcpy) we must include the line
#include <string.h>
which contains external declarations for these functions.
Since C won't let us compare entire arrays, either, we must call a function to
do that, too. The standard library's strcmp function compares two strings, and
returns 0 if they are identical, or a negative number if the first string is
alphabetically “less than'' the second string, or a positive number if the first
string is “greater.'' (Roughly speaking, what it means for one string to be “less
than'' another is that it would come first in a dictionary or telephone book,
although there are a few anomalies.) Here is an example:
char string3[] = "this is";
char string4[] = "a test";
if(strcmp(string3, string4) == 0) printf("strings are equal\n");
else printf("strings are different\n");
This code fragment will print “strings are different''. Notice that strcmp does
not return a Boolean, true/false, zero/nonzero answer, so it's not a good idea
to write something like
if(strcmp(string3, string4)) ...

because it will behave backwards from what you might reasonably expect.
(Nevertheless, if you start reading other people's code, you're likely to come
across conditionals like if(strcmp(a, b)) or even if(!strcmp(a, b)). The first does
something if the strings are unequal; the second does something if they're
Manipal University Jaipur Page No.: 123
Programming in C Unit 1

equal. You can read these more easily if you pretend for a moment that
strcmp's name were strdiff, instead.)
Another standard library function is strcat, which concatenates strings. It does
not concatenate two strings together and give you a third, new string; what it
really does is append one string onto the end of another. (If it gave you a new
string, it would have to allocate memory for it somewhere, and the standard
library string functions generally never do that for you automatically.) Here's an
example:
char string5[20] = "Hello, ";
char string6[] = "world!";
printf("%s\n", string5);
strcat(string5, string6);
printf("%s\n", string5);

The first call to printf prints “Hello, '', and the second one prints “Hello, world!'',
indicating that the contents of string6 have been tacked on to the end of string5.
Notice that we declared string5 with extra space, to make room for the
appended characters.
If you have a string and you want to know its length (perhaps so that you can
check whether it will fit in some other array you've allocated for it), you can call
strlen, which returns the length of the string (i.e. the number of characters in
it), not including the \0:
char string7[ ] = "abc";
int len = strlen(string7);
printf("%d\n", len);
Finally, you can print strings out with printf using the %s format specifier, as
we've been doing in these examples already (e.g. printf("%s\n", string5);).
Since a string is just an array of characters, all of the string-handling functions
we've just seen can be written quite simply, using no techniques more
complicated than the ones we already know. In fact, it's quite instructive to look
at how these functions might be implemented. Here is a version of strcpy:
mystrcpy(char dest[ ], char src[ ])
{
int i = 0;

Manipal University Jaipur Page No.: 124


Programming in C Unit 1

while(src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
}
We've called it mystrcpy instead of strcpy so that it won't clash with the version
that's already in the standard library. Its operation is simple: it looks at
characters in the src string one at a time, and as long as they're not \0, assigns
them, one by one, to the corresponding positions in the dest string. When it's
done, it terminates the dest string by appending a \0. (After exiting the while
loop, i is guaranteed to have a value one greater than the subscript of the last
character in src.) For comparison, here's a way of writing the same code, using
a for loop:
for(i = 0; src[i] != '\0'; i++)
dest[i] = src[i];
dest[i] = '\0';
Yet a third possibility is to move the test for the terminating \0 character out of
the for loop header and into the body of the loop, using an explicit if and break
statement, so that we can perform the test after the assignment and therefore
use the assignment inside the loop to copy the \0 to dest, too:
for(i = 0; ; i++)
{
dest[i] = src[i];
if(src[i] == '\0') break;
}
(There are in fact many, many ways to write strcpy. Many programmers like to
combine the assignment and test, using an expression like (dest[i] = src[i]) !=
'\0')

Here is a version of strcmp:


mystrcmp(char str1[ ], char str2[ ]) {
int i = 0;

while(1)

Manipal University Jaipur Page No.: 125


Programming in C Unit 1

{
if(str1[i] != str2[i])
return str1[i] - str2[i];
if(str1[i] == '\0' || str2[i] == '\0')

return 0;
i++; } }
Characters are compared one at a time. If two characters in one position differ,
the strings are different, and we are supposed to return a value less than zero
if the first string (str1) is alphabetically less than the second string. Since
characters in C are represented by their numeric character set values, and
since most reasonable character sets assign values to characters in
alphabetical order, we can simply subtract the two differing characters from
each other: the expression str1[i] - str2[i] will yield a negative result if the i'th
character of str1 is less than the corresponding character in str2. (As it turns
out, this will behave a bit strangely when comparing upper and lower-case
letters, but it's the traditional approach, which the standard versions of strcmp
tend to use.) If the characters are the same, we continue around the loop,
unless the characters we just compared were (both) \0, in which case we've
reached the end of both strings, and they were both equal. Notice that we used
what may at first appear to be an infinite loop--the controlling expression is the
constant 1, which is always true. What actually happens is that the loop runs
until one of the two return statements breaks out of it (and the entire function).
Note also that when one string is longer than the other, the first test will notice
this (because one string will contain a real character at the [i] location, while
the other will contain \0, and these are not equal) and the return value will be
computed by subtracting the real character's value from 0, or vice versa. (Thus
the shorter string will be treated as “less than'' the longer.)

Finally, here is a version of strlen:


int mystrlen(char str[ ])
{
int i;
for(i = 0; str[i] != '\0'; i++)
{}
return i;

Manipal University Jaipur Page No.: 126


Programming in C Unit 1

}
In this case, all we have to do is find the \0 that terminates the string, and it
turns out that the three control expressions of the for loop do all the work;
there's nothing left to do in the body. Therefore, we use an empty pair of braces
{ } as the loop body. Equivalently, we could use a null statement, which is
simply a semicolon:

for(i = 0; str[i] != '\0'; i++)

Everything we've looked at so far has come out of C's standard libraries. As
one last example, let's write a substr function, for extracting a substring out of
a larger string. We might call it like this:

char string8[ ] = "this is a test";


char string9[10];
substr(string9, string8, 5, 4);
printf("%s\n", string9);
The idea is that we'll extract a substring of length 4, starting at character 5 (0-
based) of string8, and copy the substring to string9. Just as with strcpy, it's our
responsibility to declare the destination string (string9) big enough. Here is an
implementation of substr. Not surprisingly, it's quite similar to strcpy:
substr(char dest[ ], char src[ ], int offset, int len)
{
int i;
for(i = 0; i < len && src[offset + i] != '\0'; i++) dest[i] = src[i + offset];
dest[i] = '\0';
}
If you compare this code to the code for mystrcpy, you'll see that the only
differences are that characters are fetched from src[offset + i] instead of src[i],
and that the loop stops when len characters have been copied (or when the
src string runs out of characters, whichever comes first).
When working with strings, it's important to keep firmly in mind the differences
between characters and strings. We must also occasionally remember the way
characters are represented, and about the relation between character values

Manipal University Jaipur Page No.: 127


Programming in C Unit 1

and integers.
As we have had several occasions to mention, a character is represented
internally as a small integer, with a value depending on the character set in
use. For example, we might find that 'A' had the value 65, that 'a' had the value
97 and that '+' had the value 43. (These are, in fact, the values in the ASCII
character set, which most computers use. However, you don't need to learn
these values, because the vast majority of the time, you use character
constants to refer to characters, and the compiler worries about the values for
you. Using character constants in preference to raw numeric values also
makes your programs more portable.)
As we may also have mentioned, there is a big difference between a character
and a string, even a string which contains only one character (other than the
\0). For example, 'A' is not the same as "A". To drive home this point, let's
illustrate it with a few examples.
If you have a string:
char string[ ] = "hello, world!";
you can modify its first character by saying
string[0] = 'H';
(Of course, there's nothing magic about the first character; you can modify any
character in the string in this way. Be aware, though, that it is not always safe
to modify strings in-place like this) Since you're replacing a character, you want
a character constant, 'H'. It would not be right to write
string[0] = "H"; /* WRONG */
because "H" is a string (an array of characters), not a single character. (The
destination of the assignment, string[0], is a char, but the right-hand side is a
string; these types don't match.)
On the other hand, when you need a string, you must use a string. To print a
single newline, you could call
printf("\n");
It would not be correct to call
printf('\n'); /* WRONG */
printf always wants a string as its first argument. (As one final example, putchar

Manipal University Jaipur Page No.: 128


Programming in C Unit 1

wants a single character, so putchar('\n') would be correct, and putchar("\n")


would be incorrect.)
We must also remember the difference between strings and integers. If we
treat the character '1' as an integer, perhaps by saying
int i = '1';
we will probably not get the value 1 in i; we'll get the value of the character '1'
in the machine's character set. (In ASCII, it's 49.) When we do need to find the
numeric value of a digit character (or to go the other way, to get the digit
character with a particular value) we can make use of the fact that, in any
character set used by C, the values for the digit characters, whatever they are,
are contiguous. In other words, no matter what values '0' and '1' have, '1' - '0'
will be 1 (and, obviously, '0' - '0' will be 0). So, for a variable c holding some
digit character, the expression
c - '0'
gives us its value. (Similarly, for an integer value i, i + '0' gives us the
corresponding digit character, as long as 0 <= i <= 9.)
Just as the character '1' is not the integer 1, the string "123" is not the integer
123. When we have a string of digits, we can convert it to the corresponding
integer by calling the standard function atoi:
char string[] = "123";
int i = atoi(string);
int j = atoi("456");
Self Assessment Questions:
6. Will there be a compilation error for the following program? (Yes/No). char
str1[10];
str1=”Hello, world”;
printf(“%s”, str1);
7. The library function used to copy one string to another is

8. The library function atoi can be used for any string. (True/False)
7.5 Summary
An array is a variable that can hold more than one value. In C, arrays are zero-
based. An array name can be used as an argument to a function, thus

Manipal University Jaipur Page No.: 129


Programming in C Unit 1

permitting the entire array to be passed to the function. The C language allows
arrays of any dimension to be defined. One of the most natural applications for
a two-dimensional array arises in the case of a matrix. Strings in C are
represented by arrays of characters. C has built in library functions to perform
some operations on strings.

7.6 Terminal Questions


1. Write a program for 10 times summation of square of a number.
2. How many elements can the array in the following declaration
accommodate?
int a[3][4][5];
3. Is the following array declaration and initialization correct?
int a[2][2]={1,2,3,4};
4. When you pass an array as a parameter to a function, the entire array is
copied and is available to function. Justify whether this statement is true or
false.
5. Write a Program that uses loops for array processing.

7.7 Answers for Self Assessment Questions


1. 0
2. True
3. Yes
4. rows
5. true
6. Compilation error
7. strcpy
8. false

7.8 Answers for Terminal Questions


1. #include<stdio.h> main()
{
int i=0, sum=0, x;
printf(‘Enter a number:”);
scanf(“%d”, &x);
while(i<10)
{
sum+=x*x;
Manipal University Jaipur Page No.: 130
Programming in C Unit 1

i++;
}
printf(“Sum=%d”, sum);
}
2. 60
3. Yes, It is correct.
4. Statement is False.
5. // loops for array processing
#include <stdio.h>
#define SIZE 10
#define PAR 72
int main(void)
{
int index, score[SIZE];
int sum = 0;
float average;
printf("Enter %d golf scores:\n", SIZE);
for (index = 0; index < SIZE; index++)
scanf("%d", &score[index]); */read in the ten scores printf("The
scores read in are as follows:\n");
for (index = 0; index < SIZE; index++)
printf("%5d", score[index]); */verify input
printf("\n");
for (index = 0; index < SIZE; index++)
sum += score[index]; */add them up
average = (float) sum / SIZE; */ time-honored method
printf("Sum of scores = %d, average = %.2f\n", sum, average);
printf("That's a handicap of %.0f.\n", average - PAR);
return 0;
}
7.9 Exercises
1. Write a program to count the number of vowels and consonants in a given
string.
2. Write a program to arrange a list of numbers in ascending order.

Manipal University Jaipur Page No.: 131


Programming in C Unit 1

3. Write a program to multiply two matrices.


4. Write a program to rewrite a given string in the alphabetical order.
5. Write a program to transpose a given matrix.

Manipal University Jaipur Page No.: 132


Programming in C Unit 1

Unit 8 Pointers - I
Structure:
8.1 Introduction
Objectives
8.2 Basics of Pointers
8.3 Pointers and One-dimensional Arrays
Pointer Arithmetic
Pointer Subtraction and Comparison
Similarities between Pointers and One-dimensional Arrays
8.4 Summary
8.5 Terminal Questions
8.6 Answers to Self AssessmentQuestions
8.7 Answers to TerminalQuestions
8.8 Exercises

8.1 Introduction
In the previous unit, you studied about the arrays and strings. You studied how
the arrays and strings are declared and manipulated in making C a more easy
and powerful programming language. In this unit, you will study about pointer
which is another useful topic that makes C a most powerful programming
language. You will study about the basics of pointer and pointer arithmetic.
A pointer is a variable that points at, or refers to, another variable. That is, if
we have a pointer variable of type “pointer to int, “it might point to the int
variable i, or to any one of the locations of the int array a. Given a pointer
variable, we can ask questions like, “what’s the value of the variable that this
pointer points to?”.
Why would we want to have a variable that refers to another variable? Why not
just use that other variable directly? Pointers are used frequently in C, as they
have number of useful applications. For example, pointers can be used to pass
information back and forth between a function and its reference point. In
particular, pointers provide a way to return multiple data items from a function
via function arguments. Pointers also permit references to other functions to
be specified as arguments to a given function. This has the effect of passing
functions as arguments to the given function.
Pointers are also closely associated with the arrays and therefore provide an

Manipal University Jaipur Page No.: 133


Programming in C Unit 1

alternate way to access individual array elements. Pointers make the program
efficient when we use pointers for accessing the individual array elements. In
this unit, you will study about the basics of pointers and its usage in one
dimensional array.
Objectives:
After studying this unit, you should be able to:
• implement pointers in your program
• write a program related to arrays and using a pointer with it
• solve and illustrate the use of pointer arithmetics in C
• point out the similarities between pointers and one dimensional arrays

8.2 Basics of Pointers


A pointer is a variable which contains the address in memory of another
variable. We can have a pointer to any variable type. Before studying pointers,
you should mind certain symbols that are frequently used in implementing the
pointers. We use the symbol & that gives the “address of a variable” and is
known as the unary or monadic operator. We use other symbol * that gives
the “contents of an object pointed to by a pointer” and we call it the indirection
or dereference operator.
The first things to do with pointers are to declare a pointer variable, set it to
point somewhere, and finally manipulate the value that it points to. A simple
pointer declaration has the following general format:
datatype *variablename
where datatype represents the type of the data to which the pointer
variablename points to. In simple terms, the variablename holds the address
of the value of type datatype.
For example, int *ip;
This declaration looks like our earlier declarations, with one obvious difference:
that is the asterisk. The asterisk means that ip, the variable we're declaring, is
not of type int, but rather of type pointer-to-int. (Another way of looking at it is
that *ip, which as we'll see is the value pointed to by ip, will be an int.)
We may think of setting a pointer variable to point to another variable as a two-
step process: first we generate a pointer to that other variable, and then we
assign this new pointer to the pointer variable. We can say (but we have to be

Manipal University Jaipur Page No.: 134


Programming in C Unit 1

careful when we're saying it) that a pointer variable has a value, and that its
value is “pointer to that other variable”. This will make more sense when we
see how to generate pointer values.
Pointers (that is, pointer values) are generated with the “address-of” operator
&, which we can also think of as the “pointer-to” operator. We demonstrate this
by declaring (and initializing) an int variable i, and then setting ip to point to it:
int i = 5;
ip = &i;
The assignment expression ip = &i; contains both parts of the “two-step
process”: &i generates a pointer to i, and the assignment operator assigns the
new pointer to (that is, places it “in”) the variable ip. Now ip “points to” i, which
we can illustrate with this picture:

i is a variable of type int, so the value in its box is a number, 5. ip is a variable


of type pointer-to-int, so the “value” in its box is an arrow pointing at another
box. Referring once again back to the “two-step process” for setting a pointer
variable: the & operator draws us the arrowhead pointing at i's box, and the
assignment operator =, with the pointer variable ip on its left, anchors the other
end of the arrow in ip's box.
We discover the value pointed to by a pointer using the “contents-of” operator,
*. Placed in front of a pointer, the * operator accesses the value pointed to by
that pointer. In other words, if ip is a pointer, then the expression *ip gives us
whatever it is that's in the variable or location pointed to by ip. For example, we
could write something like
printf("%d\n", *ip);
which would print 5, since ip points to i, and i is (at the moment) 5.
(You may wonder how the asterisk * can be the pointer contents-of operator
when it is also the multiplication operator. There is no ambiguity here: it is the
multiplication operator when it sits between two variables, and it is the
contents-of operator when it sits in front of a single variable. The situation is
analogous to the minus sign: between two variables or expressions it's the
Manipal University Jaipur Page No.: 135
Programming in C Unit 1

subtraction operator, but in front of a single operator or expression it's the


negation operator. Technical terms you may hear for these distinct roles are
unary and binary: a binary operator applies to two operands, usually on either
side of it, while a unary operator applies to a single operand.)
The contents-of operator * does not merely fetch values through pointers; it
can also set values through pointers. We can write something like
* ip = 7;
which means “set whatever ip points to 7.” Again, the * tells us to go to the
location pointed to by ip, but this time, the location isn't the one to fetch from -
- we're on the left-hand sign of an assignment operator, so *ip tells us the
location to store to. (The situation is no different from array subscripting
expressions such as a[3] which we've already seen appearing on both sides of
assignments.)
The result of the assignment *ip = 7 is that i's value is changed to 7, and the
picture changes to:

If we called printf("%d\n", *ip) again, it would now print 7.


At this point, you may be wonder, if we wanted to set i to 7, why didn't we do it
directly? We'll begin to explore that next, but first let's notice the difference
between changing a pointer (that is, changing what variable it points to) and
changing the value at the location it points to. When we wrote *ip = 7, we
changed the value pointed to by ip, but if we declare another variable j:
int j = 3;
and write
ip = &j;
we've changed ip itself. The picture now looks like this:

Manipal University Jaipur Page No.: 136


Programming in C Unit 1

We have to be careful when we say that a pointer assignment changes “what


the pointer points to.” Our earlier assignment
* ip = 7;
changed the value pointed to by ip, but this more recent assignment
ip = &j;
has changed what variable ip points to. It's true that “what ip points to” has
changed, but this time, it has changed for a different reason. Neither i (which
is still 7) nor j (which is still 3) has changed. (What has changed is ip's value.)
If we again call
printf("%d\n", *ip);
this time it will print 3.
We can also assign pointer values to other pointer variables. If we declare a
second pointer variable:
int *ip2;
then we can say
ip2 = ip;
Now ip2 points where ip does; we've essentially made a “copy” of the arrow:

Now, if we set ip to point back to i again: ip = &i;


the two arrows point to different places:

We can now see that the two assignments

Manipal University Jaipur Page No.: 137


Programming in C Unit 1

ip2 = ip;
and
* ip2 = *ip;
do two very different things. The first would make ip2 again point to where ip
points (in other words, back to i again). The second would store, at the location
pointed to by ip2, a copy of the value pointed to by ip; in other words (if ip and
ip2 still point to i and j respectively) it would set j to i's value, or 7.
It's important to keep very clear in your mind the distinction between a pointer
and what it points to. You can't mix them. You can't “set ip to 5” by writing
something like
ip = 5; /* WRONG */
5 is an integer, but ip is a pointer. You probably wanted to “set the value pointed
to by ip to 5,” which you express by writing
* ip = 5;
Similarly, you can't “see what ip is” by writing
printf("%d\n", ip); /* WRONG */
Again, ip is a pointer-to-int, but %d expects an int. To print what ip points to,
use
printf("%d\n", *ip);
Finally, a few more notes about pointer declarations. The * in a pointer
declaration is related to, but different from, the contents-of operator *. After we
declare a pointer variable
int *ip;
the expression
ip = &i
sets what ip points to (that is, which location it points to), while the expression
* ip = 5
sets the value of the location pointed to by ip. On the other hand, if we declare
a pointer variable and include an initializer:
int *ip3 = &i;

Manipal University Jaipur Page No.: 138


Programming in C Unit 1

we're setting the initial value for ip3, which is where ip3 will point, so that initial
value is a pointer. (In other words, the * in the declaration int *ip3 = &i; is not
the contents-of operator, it's the indicator that ip3 is a pointer.)
If you have a pointer declaration containing an initialization, and you ever have
occasion to break it up into a simple declaration and a conventional
assignment, do it like this:
int *ip3;
ip3 = &i;
Don't write
int *ip3;
* ip3 = &i;
or you'll be trying to mix pointer and the value to which it points
Also, when we write int *ip;
although the asterisk affects ip's type, it goes with the identifier name ip, not
with the type int on the left. To declare two pointers at once, the declaration
looks like
int *ip1, *ip2;
Some people write pointer declarations like this:
int* ip;
This works for one pointer, because C essentially ignores whitespace. But if
you ever write
int* ip1, ip2; /* PROBABLY WRONG */
it will declare one pointer-to-int ip1 and one plain int ip2, which is probably not
what you meant.
What is all of this good for? If it was just for changing variables like i from 5 to
7, it would not be good for much. What it's good for, among other things, is
when for various reasons we don't know exactly which variable we want to
change.
Program 8.1: A simple program to illustrate the relationship between
two integer variables, their corresponding addresses and their
associated pointers.
#include<stdio.h>
main()
Manipal University Jaipur Page No.: 139
Programming in C Unit 1

{
int x=5;
int y;
int *px; /* pointer to an integer */
int *py; /* pointer to an integer */
px=&x; /* assign address of x to px */
y=*px; /* assign value of x to y */
py=&y; /* assign address of y to py */
printf(“\nx=%d &x=%u px=%u *px=%d”, x, &x, px, *px); printf(“\ny=%d
&y=%u py=%u *py=%d”, y, &y, py, *py);
}
Execute this program and observe the result.

Self Assessment Questions


1. Dereference operator is also known as __________________ .
2. Pointer is a variable containing address of another variable. (True/False)
3. State whether the following statements are correct: (Correct/Incorrect) int
a, b;
b=&a;
4. The contents-of operator * does not merely fetch values through pointers;
it can also set values through pointers. (True/False)

8.3 Pointers and One-dimensional Arrays


Pointers do not have to point to single variables. They can also point at the
cells of an array. For example, we can write
int *ip;
int a[10];
ip = &a[3];
and we would end up with ip pointing at the fourth cell of the array a (remember,
arrays are 0-based, so a[0] is the first location). We could illustrate the situation
like this:

Manipal University Jaipur Page No.: 140


Programming in C Unit 1

We'd use this ip just like the one in the previous section: *ip gives us what ip
points to, which in this case will be the value in a[3].
8.3.1 Pointer Arithmetic
Once we have a pointer pointing into an array, we can start doing pointer
arithmetic. Given that ip is a pointer to a[3], we can add 1 to ip:
ip + 1
What does it mean to add one to a pointer? In C, it gives a pointer to the cell
one farther on, which in this case is a[4]. To make this clear, let's assign this
new pointer to another pointer variable:
ip2 = ip + 1;
Now the picture looks like this:

If we now do
* ip2 = 4;
we've set a[4] to 4. But it's not necessary to assign a new pointer value to a
pointer variable in order to use it; we could also compute a new pointer value
and use it immediately:
* (ip + 1) = 5;
In this last example, we've changed a[4] again, setting it to 5. The
parentheses are needed because the unary “contents of'' operator * has
higher precedence (i.e., binds more tightly than) the addition operator. If we
wrote *ip + 1, without the parentheses, we'd be fetching the value pointed to
by ip, and adding 1 to that value. The expression *(ip + 1), on the other hand,
accesses the value one past the one pointed to by ip.
Given that we can add 1 to a pointer, it's not surprising that we can add and
subtract other numbers as well. If ip still points to a[3], then
* (ip + 3) = 7;
sets a[6] to 7, and

Manipal University Jaipur Page No.: 141


Programming in C Unit 1

* (ip - 2) = 4;
sets a[1] to 4.
Up above, we added 1 to ip and assigned the new pointer to ip2, but there's
no reason we can't add one to a pointer, and change the same pointer:
* p = ip + 1;
Now ip points one past where it used to (to a[4], if we hadn't changed it in the
meantime). The shortcuts work for pointers, too: we could also increment a
pointer using
* p += 1;
or
ip++;
Of course, pointers are not limited to ints. It's quite common to use pointers to
other types, especially char.
Example 8.1: Here is a program segment to compare two strings, character
by character using pointers.
char *p1 = &str1[0], *p2 = &str2[0];
while(1)
{
if(*p1 != *p2)
return *p1 - *p2;
if(*p1 == '\0' || *p2 == '\0')
return 0;
p1++;
p2++; }
The auto increment operator ++ (like its companion, --) makes it easy to do two
things at once. We've seen idioms like a[i++] which accesses a[i] and
simultaneously increments i, leaving it referencing the next cell of the array a.
We can do the same thing with pointers: an expression like *ip++ lets us access
what ip points to, while simultaneously incrementing ip so that it points to the
next element. The preincrement form works, too: *++ip increments ip, then
accesses what it points to. Similarly, we can use notations like *ip-- and *--ip.

Example 8.2: Here is a program segment to copy a string to another using

Manipal University Jaipur Page No.: 142


Programming in C Unit 1

pointer:
char *dp = &dest[0], *sp = &src[0];

while(*sp != '\0')
*dp++ = *sp++;
*dp = '\0';
(One question that comes up is whether the expression *p++ increments p or
what it points to. The answer is that it increments p. To increment what p points
to, you can use (*p)++.)

When you're doing pointer arithmetic, you have to remember how big the array
the pointer points into is, so that you don't ever point outside it. If the array a
has 10 elements, you can't access a[50] or a[-1] or even a[10] (remember, the
valid subscripts for a 10-element array run from 0 to 9). Similarly, if a has 10
elements and ip points to a[3], you can't compute or access ip + 10 or ip - 5.
(There is one special case: you can, in this case, compute, but not access, a
pointer to the nonexistent element just beyond the end of the array, which in
this case is &a[10]. This becomes useful when you're doing pointer
comparisons, which we'll look at next.)

Program 8.2: Program to illustrate the relationship between an array and


pointer.
#include<stdio.h>
main()
{
int a[10];
int i;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
for(i=0;i<10;i++)
printf(“\ni=%d a[i]=%d *(a+i)=%d &a[i]=%u a+i=%u”, i, a[i], *(a+i), &a[i], a+i); }
Execute this program and observe the result.
8.3.2 Pointer Subtraction and Comparison
As we've seen, you can add an integer to a pointer to get a new pointer,
pointing somewhere beyond the original (as long as it is in the same array).
For example, you might write

Manipal University Jaipur Page No.: 143


Programming in C Unit 1

ip2 = ip1 + 3;

Applying a little algebra, you might wonder whether


ip2 - ip1 = 3

and the answer is, yes. When you subtract two pointers, as long as they point
into the same array, the result is the number of elements separating them. You
can also ask (again, as long as they point into the same array) whether one
pointer is greater or less than another: one pointer is “greater than” another if
it points beyond where the other one points. You can also compare pointers
for equality and inequality: two pointers are equal if they point to the same
variable or to the same cell in an array, and are (obviously) unequal if they
don't. (When testing for equality or inequality, the two pointers do not have to
point into the same array.)
One common use of pointer comparisons is when copying arrays using
pointers.

Example 8.3: Here is a code fragment which copies 10 elements from array1
to array2, using pointers. It uses an end pointer, endptr, to keep track of
when it should stop copying.
int array1[10], array2[10];
int *ip1, *ip2 = &array2[0];
int *endptr = &array1[10];

for(ip1 = &array1[0]; ip1 < endptr; ip1++)


*ip2++ = *ip1;
As we mentioned, there is no element array1[10], but it is legal to compute a
pointer to this (nonexistent) element, as long as we only use it in pointer
comparisons like this (that is, as long as we never try to fetch or store the value
that it points to.)

Prorgam 8.3: In the following program, two different pointer variables


point to the first and the last element of an integer array.
#include<stdio.h> main() {
int *px, *py;
int a[5]={1, 2, 3, 4, 5};
px=&a[0];
py=&a[4];
Manipal University Jaipur Page No.: 144
Programming in C Unit 1

printf(“px=%u py=%u”, px, py); printf(“\n\n py-px=%u”, py-px);

}
Execute this program and observe the result.
8.3.3 Similarities between Pointers and One-dimensional Arrays
There are a number of similarities between arrays and pointers in C. If you
have an array
int a[10];
you can refer to a[0], a[1], a[2], etc., or to a[i] where i is an int. If you declare a
pointer variable ip and set it to point to the beginning of an array:
int *ip = &a[0];
you can refer to *ip, *(ip+1), *(ip+2), etc., or to *(ip+i) where i is an int.
There are also differences, of course. You cannot assign two arrays; the code
int a[10], b[10];
a = b; /* WRONG */
is illegal. As we've seen, though, you can assign two pointer variables:
int *ip1, *ip2;
ip1 = &a[0];
ip2 = ip1;
Pointer assignment is straightforward; the pointer on the left is simply made to
point wherever the pointer on the right does. We haven't copied the data
pointed to (there's still just one copy, in the same place); we've just made two
pointers point to that one place.
The similarities between arrays and pointers end up being quite useful, and in
fact C builds on the similarities, leading to what is called “the equivalence of
arrays and pointers in C.'' When we speak of this “equivalence'' we do not
mean that arrays and pointers are the same thing (they are in fact quite
different), but rather that they can be used in related ways, and that certain
operations may be used between them.
The first such operation is that it is possible to (apparently) assign an array to
a pointer:
int a[10];
int *ip;
ip = a;

Manipal University Jaipur Page No.: 145


Programming in C Unit 1

What can this mean? In that last assignment ip = a, C defines the result of this
assignment to be that ip receives a pointer to the first element of a. In other
words, it is as if you had written
ip = &a[0];
The second facet of the equivalence is that you can use the “array subscripting''
notation [i] on pointers, too. If you write ip[3]
it is just as if you had written
*(ip + 3)
So when you have a pointer that points to a block of memory, such as an array
or a part of an array, you can treat that pointer “as if'' it were an array, using
the convenient [i] notation. In other words, at the beginning of this section when
we talked about *ip, *(ip+1), *(ip+2), and *(ip+i), we could have written ip[0],
ip[1], ip[2], and ip[i]. As we'll see, this can be quite useful (or at least
convenient).
The third facet of the equivalence (which is actually a more general version of
the first one we mentioned) is that whenever you mention the name of an array
in a context where the “value'' of the array would be needed, C automatically
generates a pointer to the first element of the array, as if you had written
&array[0]. When you write something like
int a[10];
int *ip;
ip = a + 3;
it is as if you had written ip = &a[0] + 3;
which (and you might like to convince yourself of this) gives the same result as
if you had written
ip = &a[3];
For example, if the character array
char string[100];
contains some string, here is another way to find its length:
int len;
char *p;
for(p = string; *p != '\0'; p++)
;
Manipal University Jaipur Page No.: 146
Programming in C Unit 1

len = p - string;
After the loop, p points to the '\0' terminating the string. The expression p -
string is equivalent to p - &string[0], and gives the length of the string. (Of
course, we could also call strlen; in fact here we've essentially written another
implementation of strlen.)
Self Assessment Questions
5. You can perform any type of arithmetic operation on pointers. (True or
False)
6. For an int array a[10], If you declare a pointer variable ip then you can set
it to point to the beginning of an array by assigning: int *ip =

7. One common use of pointer comparisons is when copying arrays using


pointers. (True/False)
8. To increment what p points to, you can use the expression _________.

8.4 Summary
A pointer is a variable that points at, or refers to, another variable. The general
format of a simple pointer declaration is: datatype *variablename. We discover
the value pointed to by a pointer using the “contents-of” operator, *. Pointers
are very useful when you want to refer to some other variable by pointing at it.
Pointers not only point to single variables but can also point at the cells of an
array. Pointers are also closely associated with the arrays and therefore
provide an alternate way to access individual array elements. Once we have a
pointer pointing into an array, we can do some pointer arithmetic-add a
constant to a variable or subtract a constant from a pointer, or you can subtract
two pointers. There are similarities between pointers and one dimension arrays
in some aspects although they are entirely different concepts and there are
differences also in other aspects.

8.5 Terminal Questions


1. How do you declare a pointer to a floating point quantity and a double
precision quantity? Illustrate it.
2. What is the significance of the following declaration? Explain with an
example.
int *p(int a)

Manipal University Jaipur Page No.: 147


Programming in C Unit 1

3. What is the significance of the following declaration? Explain with an


example.
int (*p) (int a)
4. Illustrate with an example how you use pointer arithmetic.

Manipal University Jaipur Page No.: 148


Programming in C Unit 1

8.6 Answers to Self Assessment Questions


1. indirection operator.
2. True
3. Incorrect
4. True
5. False
6. &a[0];
7. True
8. (*p)++.)

8.7 Answers to Terminal Questions


1. We declare a pointer to a floating point quantity and double precision
quantity as follows:
float *fptr;
double *dptr;
(Refer section 8. 2 and 8.3 for more details)
2. int *p(int a) defines the function that accepts an integer argument and
returns a pointer to an integer. (Refer section 8. 2 and 8.3 for more details)
3. int (*p) (int a) indicates a pointer to a function that accepts an integer
argument and returns an integer. (Refer section 8. 2 and 8.3 for more
details)
4. You can apply addition, subtraction or comparison with pointers. (Refer
section 8. 2 and 8.3 for more details)

8.8 Exercise
1. Write a program that uses the pointer arithmetic.
2. Write a program that can accept any 5 data and sort it in ascending order
using pointers.
3. With the help of pointers, write a program that uses functions to swap the
data.
4. What are the various operators that are used when implementing a pointer
in a program? Explain with an example.
Unit 9 Pointers - II
Structure:
9.1 Introduction

Manipal University Jaipur Page No.: 149


Programming in C Unit 1

Objectives
9.2 Null pointers
9.3 Pointers as FunctionArguments
9.4 Pointers and Strings
9.5 Pointers and two-dimensionalarrays
Arrays of Pointers
9.6 Summary
9.7 Terminal Questions
9.8 Answers to Self Assessment Questions
9.9 Answers for TerminalQuestions
9.10 Exercises

9.1 Introduction
In the previous unit, you read about the basics of pointers. A pointer is a
variable that points at, or refers to, another variable. Pointers are very useful
when you want to refer to some other variable by pointing at it. Pointers not
only point to single variables but can also point at the cells of an array. Pointers
provide a convenient way to represent multidimensional arrays, allowing a
single multidimensional array to be replaced by a lowerdimensional array of
pointers. This feature permits a collection of strings to be represented within a
single array, even though the individual strings may differ in length.
In this unit, you will read about null pointers and how pointers can be used to
manipulate a string along with the usage of pointers in two dimensional arrays.
You will also read about arrays of pointers briefly.
Objectives:
After studying this unit, you should be able to:
• explain a null pointer
• use pointers as function arguments ?
• manipulate strings by the help of pointers
• explain arrays of pointers
9.2 Null Pointers
We said that the value of a pointer variable is a pointer to some other variable.
There is one other value a pointer may have: it may be set to a null pointer. A
null pointer is a special pointer value that is known not to point anywhere. What
this means that no other valid pointer, to any other variable or array cell or

Manipal University Jaipur Page No.: 150


Programming in C Unit 1

anything else, will ever compare equal to a null pointer.


The most straightforward way to “get'' a null pointer in your program is by using
the predefined constant NULL, which is defined for you by several standard
header files, including <stdio.h>, <stdlib.h>, and <string.h>. To initialize a
pointer to a null pointer, you might use code like
#include <stdio.h>
int *ip = NULL;
and to test it for a null pointer before inspecting the value pointed to, you might
use code like
if(ip != NULL)
printf("%d\n", *ip);
It is also possible to refer to the null pointer by using a constant 0, and you will
see some code that sets null pointers by simply doing
int *ip = 0;
(In fact, NULL is a preprocessor macro which typically has the value, or
replacement text, 0.)
Furthermore, since the definition of “true'' in C is a value that is not equal to 0,
you will see code that tests for non-null pointers with abbreviated code like
if(ip)
printf("%d\n", *ip);
This has the same meaning as our previous example; if(ip) is equivalent to if(ip
!= 0) and to if(ip != NULL).
All of these uses are legal, and although the use of the constant NULL is
recommended for clarity, you will come across the other forms, so you should
be able to recognize them.
You can use a null pointer as a placeholder to remind yourself (or, more
importantly, to help your program remember) that a pointer variable does not
point anywhere at the moment and that you should not use the “contents of''
operator on it (that is, you should not try to inspect what it points to, since it
doesn't point to anything). A function that returns pointer values can return a
null pointer when it is unable to perform its task. (A null pointer used in this way

Manipal University Jaipur Page No.: 151


Programming in C Unit 1

is analogous to the EOF value that functions like getchar return.)


As an example, let us write our own version of the standard library function
strstr, which looks for one string within another, returning a pointer to the string
if it can, or a null pointer if it cannot.
Example 9.1: Here is the function, using the obvious brute-force algorithm: at
every character of the input string, the code checks for a match there of the
pattern string:
#include <stddef.h>

char *mystrstr(char input[], char pat[]) {


char *start, *p1, *p2;
for(start = &input[0]; *start != '\0'; start++)
{ /* for each position in input string... */
pl = pat; /* prepare to check for pattern string there */
p2 = start;
while(*p1 != '\0')
{
if(*p1 != *p2) /* characters differ */
break;
p1++;
p2++;
}
if(*p1 == '\0') /* found match */
return start;
}
return NULL;
}
The start pointer steps over each character position in the input string. At each
character, the inner loop checks for a match there, by using p1 to step over the
pattern string (pat), and p2 to step over the input string (starting at start). We
compare successive characters until either (a) we reach the end of the pattern
string (*p1 == '\0'), or (b) we find two characters which differ. When we're done
with the inner loop, if we reached the end of the pattern string (*p1 == '\0'), it
means that all preceding characters matched, and we found a complete match

Manipal University Jaipur Page No.: 152


Programming in C Unit 1

for the pattern starting at start, so we return start. Otherwise, we go around the
outer loop again, to try another starting position. If we run out of those (if *start
== '\0'), without finding a match, we return a null pointer.
Notice that the function is declared as returning (and does in fact return) a
pointer-to-char.
In general, C does not initialize pointers to null for you, and it never tests
pointers to see if they are null before using them. If one of the pointers in your
programs points somewhere some of the time but not all of the time, an
excellent convention to use is to set it to a null pointer when it doesn't point
anywhere valid, and to test to see if it's a null pointer before using it. But you
must use explicit code to set it to NULL, and to test it against NULL. (In other
words, just setting an unused pointer variable to NULL doesn't guarantee
safety; you also have to check for the null value before using the pointer.) On
the other hand, if you know that a particular pointer variable is always valid,
you don't have to insert a paranoid test against NULL before using it.
Self Assessment Questions
1. A _____ is a special pointer value that is known not to point anywhere.
2. A function that returns ___________ values can return a null pointer
when it is unable to perform its task.
3. In general, C does not initialize pointers to null for you, and it never tests
pointers to see if they are null before using them. (True/False)

9.3 Pointers as Function Arguments


Earlier, we learned that functions in C receive copies of their arguments. (This
means that C uses call by value; it means that a function can modify its
arguments without modifying the value in the caller.)
Consider the following function to swap two integers
void swap(int x, int y)
{
int temp;
temp=x;
x=y;
y=temp;
return;
}
The problem with this function is that since C uses call by value technique of

Manipal University Jaipur Page No.: 153


Programming in C Unit 1

parameter passing, the caller can not get the changes done in the function.
This can be achieved using pointers as illustrated in the following program.
Program 9.2: Program to swap two integers using pointers
#include<stdio.h>
main()
{
int a, b;
void swap(int *a, int *b);
printf(“ Read the integers:”);
scanf(“%d%d”, &a, &b);
swap(&a, &b); /* call by reference or call by address*/
printf(“ \nAfter swapping:a=%d b=%d”, a, b);
}
void swap(int *x, int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
return;
}
Execute this program and observe the result.
Because of the use of call by reference, the changes made in the function
swap() are also available in the main().
9.4 Pointers and Strings
Because of the similarity of arrays and pointers, it is extremely common to refer
to and manipulate strings as character pointers, or char *'s. It is so common, in
fact, that it is easy to forget that strings are arrays, and to imagine that they're
represented by pointers. (Actually, in the case of strings, it may not even matter
that much if the distinction gets a little blurred; there's certainly nothing wrong
with referring to a character pointer, suitably initialized, as a ’’string.'') Let's look
at a few of the implications:
Any function that manipulates a string will actually accept it as a char *
argument. The caller may pass an array containing a string, but the function
will receive a pointer to the array's (string's) first element (character).
The %s format in printf expects a character pointer.
Manipal University Jaipur Page No.: 154
Programming in C Unit 1

Although you have to use strcpy to copy a string from one array to another,
you can use simple pointer assignment to assign a string to a pointer. The
string being assigned might either be in an array or pointed to by another
pointer. In other words, given
char string[] = "Hello, world!";
char *p1, *p2;
both
p1 = string and
p2 = p1
are legal. (Remember, though, that when you assign a pointer, you're making
a copy of the pointer but not of the data it points to. In the first example, p1
ends up pointing to the string in string. In the second example, p2 ends up
pointing to the same string as p1. In any case, after a pointer assignment, if
you ever change the string (or other data) pointed to, the change is “visible'' to
both pointers.
Many programs manipulate strings exclusively using character pointers, never
explicitly declaring any actual arrays. As long as these programs are careful to
allocate appropriate memory for the strings, they're perfectly valid and correct.
When you start working heavily with strings, however, you have to be aware of
one subtle fact.
When you initialize a character array with a string constant:
char string[] = "Hello, world!";
you end up with an array containing the string, and you can modify the array's
contents to your heart's content:
string[0] = 'J';
However, it's possible to use string constants (the formal term is string literals)
at other places in your code. Since they're arrays, the compiler generates
pointers to their first elements when they're used in expressions, as usual. That
is, if you say
char *p1 = "Hello";
int len = strlen("world");
it's almost as if you'd said
char internal_string_1[] = "Hello";
Manipal University Jaipur Page No.: 155
Programming in C Unit 1

char internal_string_2[] = "world";


char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);
Here, the arrays named internal_string_1 and internal_string_2 are supposed
to suggest the fact that the compiler is actually generating little temporary
arrays every time you use a string constant in your code. However, the subtle
fact is that the arrays which are “behind'' the string constants are not
necessarily modifiable. In particular, the compiler may store them in read-only-
memory. Therefore, if you write
char *p3 = "Hello, world!";
p3[0] = 'J';
your program may crash, because it may try to store a value (in this case, the
character 'J') into nonwritable memory.
The moral is that whenever you're building or modifying strings, you have to
make sure that the memory you're building or modifying them in is writable.
That memory should either be an array you've allocated, or some memory
which you've dynamically allocated. Make sure that no part of your program
will ever try to modify a string which is actually one of the unnamed, unwritable
arrays which the compiler generated for you in response to one of your string
constants. (The only exception is array initialization, because if you write to
such an array, you're writing to the array, not to the string literal which you used
to initialize the array.)
Example 9.3: Breaking a Line into “Words''
First, break lines into a series of whitespace-separated words. To do this, we
will use an array of pointers to char, which we can also think of as an “array of
strings,'' since a string is an array of char, and a pointer-to-char can easily point
at a string. Here is the declaration of such an array:
char *words[10];
This is the first complicated C declaration we've seen: it says that words is an
array of 10 pointers to char. We're going to write a function, getwords, which
we can call like this:
int nwords;
nwords = getwords(line, words, 10);

Manipal University Jaipur Page No.: 156


Programming in C Unit 1

where line is the line we're breaking into words, words is the array to be filled
in with the (pointers to the) words, and nwords (the return value from getwords)
is the number of words which the function finds. (As with getline, we tell the
function the size of the array so that if the line should happen to contain more
words than that, it won't overflow the array).
Here is the definition of the getwords function. It finds the beginning of each
word, places a pointer to it in the array, finds the end of that word (which is
signified by at least one whitespace character) and terminates the word by
placing a '\0' character after it. (The '\0' character will overwrite the first
whitespace character following the word.) Note that the original input string is
therefore modified by getwords: if you were to try to print the input line after
calling getwords, it would appear to contain only its first word (because of the
first inserted '\0').
#include <stddef.h>
#include <ctype.h>
getwords(char *line, char *words[], int maxwords) {
char *p = line;
int nwords = 0;

while(1)
{
while(isspace(*p)) p++;

if(*p == '\0') return nwords;


words[nwords++] = p;

while(!isspace(*p) && *p != '\0') p++;

if(*p == '\0')
return nwords;

*p++ = '\0';

if(nwords >= maxwords) return nwords;


}

Manipal University Jaipur Page No.: 157


Programming in C Unit 1

}
Each time through the outer while loop, the function tries to find another word.
First it skips over whitespace (which might be leading spaces on the line, or
the space(s) separating this word from the previous one). The isspace function
is new: it's in the standard library, declared in the header file <ctype.h>, and it
returns nonzero (“true'') if the character you hand it is a space character (a
space or a tab, or any other whitespace character there might happen to be).
When the function finds a non-whitespace character, it has found the beginning
of another word, so it places the pointer to that character in the next cell of the
words array. Then it steps through the word, looking at nonwhitespace
characters, until it finds another whitespace character, or the \0 at the end of
the line. If it finds the \0, it's done with the entire line; otherwise, it changes the
whitespace character to a \0, to terminate the word it's just found, and
continues. (If it's found as many words as will fit in the words array, it returns
prematurely.)
Each time it finds a word, the function increments the number of words
(nwords) it has found. Since arrays in C start at [0], the number of words the
function has found so far is also the index of the cell in the words array where
the next word should be stored. The function actually assigns the next word
and increments nwords in one expression:
words[nwords++] = p;
You should convince yourself that this arrangement works, and that (in this
case) the preincrement form
words[++nwords] = p; /* WRONG */
would not behave as desired.
When the function is done (when it finds the \0 terminating the input line, or
when it runs out of cells in the words array) it returns the number of words it
has found.
Here is a complete example of calling getwords:
char line[] = "this is a test";
int i;
nwords = getwords(line, words, 10);

Manipal University Jaipur Page No.: 158


Programming in C Unit 1

for(i = 0; i < nwords; i++) printf("%s\n", words[i]);

Self Assessment Questions


4. An array of characters is called as ________ .
5. You can represent an array of strings using pointers by using an array of
___________ to character.
6. A string must always be terminated with a _________ character.

9.5 Pointers and two-dimensional arrays


Since a one-dimensional array can be represented in terms of pointer (the
array name) and an offset (the subscript), it is reasonable to expect that a two-
dimensional array can also be represented with an equivalent pointer notation.
A two-dimensional array is actually a collection of one-dimensional arrays.
Therefore we can define a two dimensional array as a pointer to a group of
contiguous one-dimensional arrays. A two-dimensional array declaration can
be written as:
data-type (*ptr)[expression]
where data-type is the type of array elements and expression is the positive-
valued integer expression that indicates the number of columns in each row of
the two-dimensional array.
Example 9.5: Suppose that x is a two-dimensional integer array having 10
rows and 20 columns. We can declare x as
int (*x)[20];
In this case, x is defined to be a pointer to a group of contiguous, one-
dimensional, 20-element integer arrays. Thus x points to the first 20-element
array, which is actually the first row(row 0) of the original two-dimensional
array. Similarly, (x+1) points to the second 20-element array, which is the
second row(row 1) of the original two-dimensional array and so on.
Arrays of pointers
A two-dimensional array can also be expressed in terms of an array of pointers
rather than as a pointer to a group of contiguous arrays. Each element in the
array is a pointer to a separate row in the two-dimensional array. In general
terms, a two-dimensional array can be defined as a onedimensional array of
pointers by writing:
data-type *ptr[expression]
Manipal University Jaipur Page No.: 159
Programming in C Unit 1

where data-type is the type of array elements and expression is the positive-
valued integer expression that indicates the number of rows.
Example 9.6: Suppose that x is a two-dimensional array having 10 rows and
20 columns, we can define x as a one-dimensional array of pointers by writing
int *x[10];
Hence, x[0] points to the beginning of the first row, x[1] points to the beginning
of the second row and so on.
An individual array element, such as x[2][4] can be accessed
by writing
*(x[2]+4)
In this expression, x[2] is a pointer to the first element in row 2, so that (x[2]+5)
points to element 4(actually, the fifth element) within row 2. The element of this
pointer, *(x[2]+4), therefore refers to x[2][4].

Self Assessment Questions


7. We can define a two dimensional array as a pointer to a group of
contiguous ________ dimensional arrays.
8. A two-dimensional array can also be expressed in terms of an of
pointers rather than as a pointer to a group of contiguous arrays.

9.6 Summary
A pointer is a variable that represents the location of a data item, such as a
variable or an array element. A pointer may be set to a null pointer. A null
pointer is a special pointer value that is known not to point anywhere. Passing
pointers as arguments to functions is called pass by reference. Because of the
similarity of arrays and pointers, it is extremely common to refer to and
manipulate strings as character pointers. We can define a two dimensional
array as a pointer to a group of contiguous one-dimensional arrays. A two-
dimensional array can also be expressed in terms of an array of pointers rather
than as a pointer to a group of contiguous arrays.

9.7 Terminal Questions


1. Explain what a null pointer is. Illustrate it with an example.
2. How can you use pointers as function arguments? Illustrate it with an
example.

Manipal University Jaipur Page No.: 160


Programming in C Unit 1

3. Distinguish between pass by value and pass by reference with the help of
an example.
4. How can you manipulate strings using character pointers? Illustrate it with
the help of an example.
9.8 Answers to Self Assessment Questions
1. null pointer
2. pointer
3. True
4. string
5. pointers
6. null
7. one
8. array

9.9 Answers to Terminal Questions


1. A null pointer is a special pointer value that is known not to point anywhere
and is implemented by using the predefined constant NULL, which is
defined by several standard header files, including <stdio.h>, <stdlib.h>,
and <string.h>. (Refer to section 9.2 for more details)
2. (Refer to section 9.2 for more details)
3. In pass by value technique, the actual value is passed to the function
whereas in pass by reference, the address is passed to the function.
4. You can use the pointer to the string considering string as an array and use
(string's) first element i.e. character. The %s format in printf expects a
character pointer. (Refer to section 9.4 and 9.5 for more details)

9.10 Exercises
1. Write a program to find the number of characters in a string using pointers.
2. Write a program to multiply two matrices using pointers.
3. Suppose a formal argument within a function definition is a pointer to
another function. How is the formal argument declared? Within the formal
argument declaration, to what does the data type refer?
4. Write a program to concatenate two strings.
5. Write a function to sort an array of numbers using pointers.

Manipal University Jaipur Page No.: 161


Programming in C Unit 1

Unit 10 Structures and Unions


Structure:
10.1 Introduction
Objectives
10.2 Basics of Structures
10.3 Structures and Functions
10.4 Arrays of Structures
10.5 Pointers to Structures
10.6 Self-referential Structures
10.7 Unions
10.8 Summary
10.9 Terminal Questions
10.10 Answers to Self Assessment Questions
10.11 Answers to Terminal Questions
10.12 Exercises

10.1 Introduction
In the previous units, you studied about the pointers as a most powerful tool in
C programming language. It is due to the pointer only that makes C as the most
beautiful language. In this unit, you will study another useful ways of making
the program easy and efficient. This unit will enable you to learn about the
structures and unions.
As we know an array is a data structure whose elements are all of the same
data type. We now turn our attention to the structure, which is a data structure
whose individual elements can differ in type. Thus, a single structure might
contain integer elements, floating-point elements and character elements.
Pointers, arrays and other structures can also be included as elements within
a structure.
This unit is concerned with the use of structures within a C program. We will
see how structures are defined, and how their individual members are
accessed and processed within a program.
Closely associated with the structure is the union, which also contains multiple
members. Unlike a structure, however, the members of a union share the same
storage area, even though the individual members may differ in type.

Manipal University Jaipur Page No.: 162


Programming in C Unit 1

Objectives:
After studying this unit, you should be able to:
• handle a group of logically related data items known as structures.
• declare an array of structures, each element of the array representing a
structure variable.
• pass structure as an argument to functions and return structure from
functions.
• refer to (i.e., point to) an incomplete type, including itself.
• handle a group of logically related data items in terms of unions.

10.2 Basics of Structures


C supports a constructed data type known as structure, which is a method for
packing data of different types. A structure is a convenient tool for handling a
group of logically related data items. Structures help to organize complex data
in a more meaningful way. It is a powerful concept that we may often need to
use in our program design.
Structure Definition: A Structure definition creates a format that may be used
to declare structure variables. For e.g., Consider a book database consisting
of book name, author, number of pages and price.
struct book_bank {
char title[20];
char author[15];
int pages;
float price;
};
The keyword struct declares a structure to hold the details of four fields,
namely title, author, pages and price. These fields are called structure
elements or members. Each member may belong to a different type of data.
book_bank is the name of the structure and is called the structure tag. The tag
name may be used subsequently to declare variables that have the tag’s
structure. Note that the above declaration has not declared any variables. It
simply describes a format called template to represent information as shown
below:
struct book_bank

a... array of 20 characters


}
title
Manipal University Jaipur Page No.: 163
Programming in C Unit 1

author array of 15 characters

pages integer

price float

We can declare structure variables using the tag name anywhere in the
program. e.g, the statement:
struct book_bank book1, book2, book3;
declares book1, book2 and book3 as variables of type book_bank.
Each one of these variables has four members as specified by the template.
The complete declaration might look like this:
struct book_bank
{
char title[20];
char author[15];
int pages;
float price;
};
struct book_bank book1, book2, book3;
It is also allowed to combine both the template declaration and variables
declaration in one statement.
struct book_bank
{
char title[20];
char author[15];
int pages;
float price;
} book1, book2, book3;
General format of a Structure Definition:
The general format of a structure definition is as follows: struct tag_name {
data_type member1;

Manipal University Jaipur Page No.: 164


Programming in C Unit 1

data_type member2;

};
In defining a structure you may note the following syntax:
1. The template is terminated with a semicolon.
2. While the entire declaration is considered as a statement, each member is
declared independently for its name and type in a separate statement
inside the template.
3. The tag name such as tag_name can be used to declare structure variables
of its type, later in the program.
Giving values to Members:
Structure members need to be linked to the structure variables in order to
make them meaningful members. The link between a member and a variable
is established using the member operator ‘.’ which is also known as ‘dot
operator’ or ‘period operator’.
Here is how we would assign values to the members of book1.
strcpy(book1.title,”BASIC”);
strcpy(book1.author,”Balagurusamy”);
book1.pages = 250;
book1.price = 28.50;
We can also give the values through the keyboard.
gets(book1.title);
gets(book1.author);
printf(“%d”,book1.pages);
printf(“%f”,book1.price);
Structure Initialization:

void main( )
{
struct st_record
{

Manipal University Jaipur Page No.: 165


Programming in C Unit 1

char name[20];
int weight;
float height;
};
static struct st_record studentl = {“Suresh”, 60, 180.75};
static struct st_record student2 = {“Umesh”, 53, 170.60}; }

Program 10.1: To print the date of joining of a person

#include<conio.h>
#include<stdio.h>
struct personal {
char name[30];
int day;
int month;
int year;
float salary;
};
void main()
{
struct personal p;
printf(“Enter the name:\n)";
gets(p.name);
printf(“Enter the day of joining:\n)";
scanf(“%d”,&p.day);
printf(“Enter the month of joining:\n");
scanf(“%d”,&p.month);
printf(“Enter the year of joining:\n)";
scanf(“%d”,&p.year);
printf(“Enter the salary:\n)";
scanf(“%f”, & p.salary);
printf(“\nName:",p.name);
printf("\nDate of joining:%d %d %d",p.day,p.month,p.year);

Manipal University Jaipur Page No.: 166


Programming in C Unit 1

printf(“Salary:",p.salary);
getch();
}
Comparison of structure variables
Two variables of same structure type can be compared in the same way as
ordinary variables. If person1 and person2 belong to the same structure, then
the following operations are valid:

Operation Meaning

person1 = person2 Assign person2 to person1


person1 == person2 Compare all members of person1 and
person2 and return 1 if they are equal, 0
otherwise.
person1 != person2 Return 1 if all the members are not equal, 0
otherwise

Program 10.2: To Compare structure variables


#include <stdio.h>
#include<conio.h>
struct stclass{
int number;
char name[20];
float marks;
};

void main()
{
int x;
static struct stclass studentl = {111,"Rao",72.50};
static struct stclass student2 = {222,"Reddy",67.00};
struct stclass student3;
student3 = student2;
x=((student3.number == student2.number) && (student3.marks ==
student2.marks))? 1:0;
if(x==1)

Manipal University Jaipur Page No.: 167


Programming in C Unit 1

{
printf("\nStudent2 and Student3 are same ");
printf(“ %d\t %s\t %f\t“,student3.number,student3.name,student3.marks);
} else { printf("\nStudent2 and student3 are different)";
}
getch();
}

Self Assessment Questions


1. A __________ is a convenient tool for handling a group of logically
related data items.
2. We can declare structure variables using the tag name anywhere in the
program. (True/False)
3. is a method for packing data of different types.
4. If person1 and person2 are variables of the same type structure then the
expression person1>person2 is valid. (True/False)
5. is a method for packing data of different types.
6. The link between a member and a variable is established using the
member operator _____________ .

10.3 Structures and Functions


We can write programs with structures by using modular programming. We can
write a function that returns the structure. While writing the function, you should
indicate the type of structure that is returned by the function. The return
statement should return the structure using a variable. It is possible to pass a
structure as an argument. We can modify a member of the structure by passing
the structure as an argument. The changes in the member made by the
function are retained in the called module. This is not against the principle of
call by value because we are not modifying the structure variable, but are
instead modifying the members of the structure.
Program 10.3: To illustrate the concept of structures and functions struct
student

{
name char[30];
marks float;

Manipal University Jaipur Page No.: 168


Programming in C Unit 1

};
main ( )
{
struct student studentl;
studentl = read_student ( );
print_student( studentl);
read_student_p(student1);
print_student (studentl);
}
struct student read_student( )
{
struct student student2;
gets(student2.name);
scanf("%d",&student2.marks);
return (student2);
}
void print_student (struct student student2)
{
printf( "name is %s\n", student2.name);
printf( "marks are%d\n", student2.marks);
}
void read_student_p(struct student student2)
{
gets(student2.name);
scanf("%d",&student2.marks);
}
Explanation
1. The function read_student reads values in structures and returns the
structure.
2. The function print_student takes the structure variable as input and prints
the content in the structure.
3. The function read_student_p reads the data in the structure similarly to
read_student. It takes the structure student as an argument and puts the
data in the structure. Since the data of a member of the structure is
modified, you need not pass the structure as a pointer even though
structure members are modified. Here you are not modifying the structure,
but you are modifying the structure members through the structure.

Manipal University Jaipur Page No.: 169


Programming in C Unit 1

Self Assessment Questions


7. We cannot write a function that returns the structure. (True/False)
8. We can modify a member of the structure by passing the structure as a

10.4 Arrays of Structures


We can use structures to describe the format of a number of related variables.
For example, in analyzing the marks obtained by a class of students, we may
use a template to describe student name and marks obtained in various
subjects and then declare all the students as structure variables. In such cases,
we may declare an array of structures, each element of the array representing
a structure variable. e.g, struct stclass student[100]; defines an array called
student, that consists of 100 elements. Each element is defined to be of the
type struct stclass. Consider the following declaration:
struct marks
{
int subjectl;
int subject2;
int subject3;
};

main( )
{
static struct marks student[3]={{45,68,81},{75,53,69},{57,36,71}};
}
This declares the student as an array of three elements student[0], student[1]
and student[2] and initializes their members as follows: student[0].subject1 =
45;
student[0].subject2 = 68;

student[2].subject3 = 71;
Program 10.4: To process employee details using structures
#include<conio.h>
#include<stdio.h>
struct employee
{
int empno;
Manipal University Jaipur Page No.: 170
Programming in C Unit 1

char name[30];
int basic;
int hra;
};
void main()
{
int i,j,n,net[50];
float avg;
employee e[50];
printf("\nEnter the number of employees:");
scanf(“%d”, &n);
printf(“\nEnter Empno.\tName\tBasic\tHra of each employee:\n");
for(i=0;i<n;i++)
{
scanf(“%d”,&e[i].empno);
gets(e[i].name);
scanf(“%d”,&e[i].basic);
scanf(%d”,&e[i].hra);
net[i]= e[i].basic+e[i].hra;
avg=avg+net[i];
}
avg=avg/n;
printf("\nEmpno.\tName\tNetpay\n");
for(i=0;i<n;i++)
{
if(net[i]>avg)
{
printf(e[i].empno\t)";
printf(e[i].name\t)";
printf(net[i]\n");
}
}
getch();
}
Program 10.5: To process student details using structures
#include<conio.h>
#include<stdio.h>
struct student
Manipal University Jaipur Page No.: 171
Programming in C Unit 1

{
int rollno;
char name[30];
int marks1;
int marks2;
int marks3;
};
void main()
{
int i,j,n,tot[50],t;
student s[50],temp;
printf("\nEnter the number of students:");
scanf(“%d”,&n);
printf("\nEnter Rollno.\tName\tMarks1\tMarks2\tMarks3 of each student:\n");
for(i=0;i<n;i++)
{
scanf(“%d”,&s[i].rollno);
gets(s[i].name);
scanf(“%d”,&s[i].marks1);
scanf(“%d”,&s[i].marks2);
scanf(“%d”,&s[i].marks3);
tot[i]= s[i].marks1+s[i].marks2+s[i].marks3;
}
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(tot[i]<tot[j])
{
temp=s[i];
s[i]=s[j];
s[j]=temp;
t=tot[i];
tot[i]=tot[j];
tot[j]=t;
}
}
}
Manipal University Jaipur Page No.: 172
Programming in C Unit 1

printf("\nRollno.\tName\tTotal marks in decreasing order of total marks is:\n");


for(i=0;i<n;i++)
{
printf(“%d\t”,s[i].rollno);
printf(“%s\t”,s[i].name);
printf(“%d\t”,s[i].tot);
} getch();
}

Self Assessment Questions


9. We can use structures to describe the format of a number of related
variables. (True/False)
10. You can declare an array of structures where each element is defined to
be of the type __________ .
10.5 Pointers to Structures
Pass by value may be very inefficient if the structure is large (i.e., has many
members). They have identical declaration syntax and member access, but
they serve a very different purpose. Defining pointer types is the same as for
variables of primitive types.
Example:
struct Point {
int x;
int y;
};
struct Rectangle {
struct Point topleft;
struct Point bottomright;
};
struct Point pt = { 50, 50 };
struct Point *pp;
pp = &pt;
(*pp).x = 100; /* pt.x is now 100. */

Notice the parentheses around the de referenced pointer.


(*pp).x = 100;
This is necessary to enforce correct precedence.

An alternative notation permits simpler pointer access to structure members.


Manipal University Jaipur Page No.: 173
Programming in C Unit 1

(*pp).x = 100;

pp->x = 100; /* equivalent */


Another example,
struct Rectangle rect, *pr = &rect;
rect.topleft.x = 50; /* equivalent operations */
(*pr).topleft.x = 50;
pr->topleft.x = 50;
Self Assessment Questions
11. The parentheses around the de referenced pointer is necessary to enforce
the correct ______________ .
12. An alternative notation other than dot, permits simpler pointer access to
structure members is ___________ .

10.6 Self-referential Structures


The ability to refer to (ie, point to) an incomplete type, including itself, is an
important property for constructing a variety of data-structures. For example:
linked-lists, binary trees, graphs, hash tables, and more.
Linked lists come in two basic varieties: singly linked and doubly linked.
We describe here a simple version of a singly linked list.
List consists of a set of nodes, where each node contains an item and a pointer
to another list node.
struct List {
int item;
struct List *next;
};
More about linked lists, you will study in the units to come.

10.7 Unions
Unions look similar to structures. They have identical declaration syntax and
member access, but they serve a very different purpose.
union Utype {
int ival;
float fval;
char *sval;
Manipal University Jaipur Page No.: 174
Programming in C Unit 1

};

union Utype x, y, z;
Accessing members of a union is via “.” member operator or, for pointers to
unions, the -> operator.
A union holds the value of one-variable at a time. The compiler allocates
storage for the biggest member of the union. The type retrieved from the union
must be the type most recently stored. Otherwise, the result is implementation
dependent.
union Utype x;
x.fval = 56.4; /* x holds type float. */
printf("%f\n", x.fval); /* OK. */
printf("%d\n", x.ival); /* Implementation dependent. */
Unions are used to store one of a set of different types. These are commonly
used to implement a “variant” array. (This is a form of generic programming.)
There are other uses also, but they are quite advanced (e.g., concern the
alignment properties of unions).
Self Assessment Questions
13. A _________ holds the value of one-variable at a time.
14. The compiler allocates storage for the smallest member of the union.
(True/False)

10.8 Summary
A structure is a convenient tool for handling a group of logically related data
items. Structure members need to be linked to the structure variables in order
to make them meaningful members. We can write programs with structures by
using modular programming. We can use structures to describe the format of
a number of related variables. Passing a pointer to a structure is generally
much more efficient than making a copy of the structure itself. The ability to
refer to (i.e., point to) an incomplete type, including itself, is an important
property for constructing a variety of data- structures.
Unions have identical declaration syntax and member access, but they serve
a very different purpose. A union holds the value of one-variable at a time. The
compiler allocates storage for the biggest member of the union.

Manipal University Jaipur Page No.: 175


Programming in C Unit 1

10.9 Terminal Questions


1. Write the output that will be generated by the following C program: typedef
struct
{
char *a;
char *b;
char *c;
} colors;
void main()
{
void fun( colors sample);
static colors sample = {“red”, “green”, “blue”};
printf( (“%s %s %s\n”, sample.a, sample.b,
sample.c);
fun(sample);
printf( (“%s %s %s\n”, sample.a, sample.b,
sample.c);
}

void fun (colors sample)


{
strcpy (sample.a=”cyon”);
strcpy (sample.b=”magenta”);
strcpy (sample.c=”yellow”);
printf(“%s %s %s\n”, sample.a, sample.b,
sample.c);
return;
}

2. Describe the output generated by the following program. Distinguish


between meaningful and meaningless output.
#include <stdio.h>
main()
{
union {
int i;
float f;
Manipal University Jaipur Page No.: 176
Programming in C Unit 1

double d;
} u;
printf(“%d\n”, sizeof(u));
u.i= 100;
printf(“%d %f %f\n”, u.i, u.f, u.d);
u.f=0.5;
printf(“%d %f %f\n”, u.i, u.f, u.d);
u.d = 0.0166667;
printf(“%d %f %f\n”, u.i, u.f, u.d); }

10.10 Answers to Self Assessment Questions


1. structure
2. true
3. Array
4. false
5. Structure
6. dot(.)
7. true
8. argument.
9. True
10. struct
11. precedence
12. ->
13. union
14. false

10.11 Answers to Terminal Questions


1. red green blue
cyan magenta yellow
red blue green
2. 8
100 0.000000 -0.000000
0 0.500000 -0.000000
-25098 391364288.000000 0.016667
The first line displays the size of the union (8 bytes, to accommodate double
data). In the second line, only the first value (100) is meaningful. In the third

Manipal University Jaipur Page No.: 177


Programming in C Unit 1

line, only the second value (0.500000) is meaningful. In the last line, only the
last value (0.016667) is meaningful.
10.12 Exercises
1. What is a structure? How does a structure differ from an array?
2. What is a member? What is the relationship between a member and a
structure?
3. Describe what is wrong in the following structure declaration: struct
{
int number;
float price;
}
main()
{

}
4. Describe Array of structures with an example program.
5. Define a structure called cricket that will describe the following information:
(1) player name (ii) team name (iii) batting average
Using cricket, declare an array player with 50 elements and write a
program to read the information about all the 50 players and print a team-
wise list containing names of players and print a team-wise list containing
names of players with their batting average.
6. How is a structure type pointer variable declared?
7. Write a program to find the number of characters in a string using
pointers.

Unit 11 The Preprocessor


Structure:
11.1 Introduction
Objectives
11.2 File Inclusion

Manipal University Jaipur Page No.: 178


Programming in C Unit 1

11.3 Macro Definition and Substitution


Macros with Arguments
Nesting of Macros
11.4 Conditional Compilation
11.5 Summary
11.6 Terminal Questions
11.7 Answers to Self AssessmentQuestions
11.8 Answers to Terminal Questions
11.9 Exercises

11.1 Introduction
In the previous unit, you studied about the structures and unions in C. You
studied how those structures and unions are used to bind similar types of data
structures. In this unit, you will study about a Preprocessor. Preprocessor is a
unique feature of C language. The C preprocessor provides several tools that
are unavailable in other high-level languages. Conceptually, the
“preprocessor'' is a translation phase that is applied to your source code before
the compiler proper gets its hands on it. (Once upon a time, the preprocessor
was a separate program, much as the compiler and linker may still be separate
programs today.) Generally, the preprocessor performs textual substitutions on
your source code, in three sorts of ways:
• File inclusion: inserting the contents of another file into your source file,
as if you had typed it all in there.
• Macro substitution: replacing instances of one piece of text with
another.
• Conditional compilation: Arranging that, depending on various
circumstances, certain parts of your source code are seen or not seen by
the compiler at all.
The next three sections will introduce these three preprocessing functions.
The syntax of the preprocessor is different from the syntax of the rest of C in
several respects. First of all, the preprocessor is “line based.'' Each of the
preprocessor directives we're going to learn about (all of which begin with the
# character) must begin at the beginning of a line, and each ends at the end of
the line. (The rest of C treats line ends as just another whitespace character,
and doesn't care how your program text is arranged into lines.) Secondly, the
preprocessor does not know about the structure of C -- about functions,

Manipal University Jaipur Page No.: 179


Programming in C Unit 1

statements, or expressions. It is possible to play strange tricks with the


preprocessor to turn something which does not look like C into C (or vice
versa). It's also possible to run into problems when a preprocessor substitution
does not do what you expected it to, because the preprocessor does not
respect the structure of C statements and expressions (but you expected it to).
For the simple uses of the preprocessor we'll be discussing, you shouldn't have
any of these problems, but you'll want to be careful before doing anything tricky
or outrageous with the preprocessor. (As it happens, playing tricky and
outrageous games with the preprocessor is considered sporting in some
circles, but it rapidly gets out of hand, and can lead to bewilderingly
impenetrable programs.)
Objectives:
After studying this unit, you should be able to:
• explain about a preprocessor
• include Files in the source program
• explain and implement Macro definition and substitution
• use parentheses in macro definitions

11.2 File Inclusion


A line of the form
#include <filename.h>
or
#include "filename.h"
causes the contents of the file filename.h to be read, parsed, and compiled at
that point. (After filename.h is processed, compilation continues on the line
following the #include line.) For example, suppose you got tired of retyping
external function prototypes such as
extern int getline(char [], int);
at the top of each source file. You could instead place the prototype in a header
file, perhaps getline.h, and then simply place
#include "getline.h"
at the top of each source file where you called getline. (You might not find it
worthwhile to create an entire header file for a single function, but if you had a
package of several related function, it might be very useful to place all of their
declarations in one header file.) As we may have mentioned, that's exactly
Manipal University Jaipur Page No.: 180
Programming in C Unit 1

what the Standard header files such as stdio.h are collections of declarations
(including external function prototype declarations) having to do with various
sets of Standard library functions. When you use #include to read in a header
file, you automatically get the prototypes and other declarations it contains, and
you should use header files, precisely so that you will get the prototypes and
other declarations they contain.
The difference between the <> and "" forms is where the preprocessor
searches for filename.h. As a general rule, it searches for files enclosed in <>
in central, standard directories, and it searches for files enclosed in "" in the
“current directory,'' or the directory containing the source file that's doing the
including. Therefore, "" is usually used for header files you've written, and <>
is usually used for headers which are provided for you (which someone else
has written).
The extension “.h'', by the way, simply stands for “header,'' and reflects the fact
that #include directives usually sit at the top (head) of your source files, and
contain global declarations and definitions which you would otherwise put
there. (That extension is not mandatory, you can theoretically name your own
header files anything you wish, but .h is traditional, and recommended.)
As we've already begun to see, the reason for putting something in a header
file, and then using #include to pull that header file into several different source
files, is when the something (whatever it is) must be declared or defined
consistently in all of the source files. If, instead of using a header file, you typed
the something in to each of the source files directly, and the something ever
changed, you'd have to edit all those source files, and if you missed one, your
program could fail in subtle (or serious) ways due to the mismatched
declarations (i.e. due to the incompatibility between the new declaration in one
source file and the old one in a source file you forgot to
change). Placing common declarations and definitions into header files means
that if they ever change, they only have to be changed in one place, which is a
much more workable system.
What should you put in header files?
• External declarations of global variables and functions. We said that a
global variable must have exactly one defining instance, but that it can
have external declarations in many places. We said that it was a grave
error to issue an external declaration in one place saying that a variable or
Manipal University Jaipur Page No.: 181
Programming in C Unit 1

function has one type, when the defining instance in some other place
actually defines it with another type. (If the two places are two source files,
separately compiled, the compiler will probably not even catch the
discrepancy.) If you put the external declarations in a header file, however,
and include the header wherever it's needed, the declarations are virtually
guaranteed to be consistent. It's a good idea to include the header in the
source file where the defining instance appears, too, so that the compiler
can check that the declaration and definition match. (That is, if you ever
change the type, you do still have to change it in two places: in the source
file where the defining instance occurs, and in the header file where the
external declaration appears. But at least you don't have to change it in an
arbitrary number of places, and, if you've set things up correctly, the
compiler can catch any remaining mistakes.)
• Preprocessor macro definitions (which we'll meet in the next section).
• Structure definitions
• Typedef declarations

However, there are a few things not to put in header files:


• Defining instances of global variables. If you put these in a header file, and
include the header file in more than one source file, the variable will end
up multi defined.
• Function bodies (which are also defining instances). You don't want to put
these in headers for the same reason -- it's likely that you'll end up with
multiple copies of the function and hence “multiply defined'' errors. People
sometimes put commonly-used functions in header files and then use
#include to bring them (once) into each program where they use that
function, or use #include to bring together the several source files making
up a program, but both of these are poor ideas. It's much better to learn
how to use your compiler or linker to combine together separately-compiled
object files.
Since header files typically contain only external declarations, and should not
contain function bodies, you have to understand just what does and doesn't
happen when you #include a header file. The header file may provide the
declarations for some functions, so that the compiler can generate correct code
when you call them (and so that it can make sure that you're calling them
correctly), but the header file does not give the compiler the functions

Manipal University Jaipur Page No.: 182


Programming in C Unit 1

themselves. The actual functions will be combined into your program at the
end of compilation, by the part of the compiler called the linker. The linker may
have to get the functions out of libraries, or you may have to tell the
compiler/linker where to find them. In particular, if you are trying to use a third-
party library containing some useful functions, the library will often come with
a header file describing those functions. Using the library is therefore a two-
step process: you must #include the header in the files where you call the
library functions, and you must tell the linker to read in the functions from the
library itself.
Self Assessment Questions:
1. # include is called _______ .
2. Nesting of included files is not allowed. (True/False)
3. Defining instances of global variables is not recommended in the header
files. (True/False)

4. .3 Macro Definition and Substitution


A preprocessor line of the form
#define name text
defines a macro with the given name, having as its value the given replacement
text. After that (for the rest of the current source file), wherever the
preprocessor sees that name, it will replace it with the replacement text. The
name follows the same rules as ordinary identifiers (it can contain only letters,
digits, and underscores, and may not begin with a digit). Since macros behave
quite differently from normal variables (or functions), it is customary to give
them names which are all capital letters (or at least which begin with a capital
letter). The replacement text can be absolutely anything- -it's not restricted to
numbers, or simple strings, or anything.
The most common use for macros is to propagate various constants around
and to make them more self-documenting. We've been saying things like
char line[100]; ...
getline(line, 100);
but this is neither readable nor reliable; it's not necessarily obvious what all
those 100's scattered around the program are, and if we ever decide that 100
is too small for the size of the array to hold lines, we'll have to remember to
change the number in two (or more) places. A much better solution is to use a

Manipal University Jaipur Page No.: 183


Programming in C Unit 1

macro:
#define MAXLINE 100
char line[MAXLINE];
...
getline(line, MAXLINE);
Now, if we ever want to change the size, we only have to do it in one place,
and it's more obvious what the words MAXLINE sprinkled through the program
mean than the magic numbers 100 did.
Since the replacement text of a preprocessor macro can be anything, it can
also be an expression, although you have to realize that, as always, the text is
substituted (and perhaps evaluated) later. No evaluation is performed when
the macro is defined. For example, suppose that you write something like
#define A 2
#define B 3
#define C A + B
(this is a pretty meaningless example, but the situation does come up in
practice). Then, later, suppose that you write
int x = C * 2;
If A, B, and C were ordinary variables, you'd expect x to end up with the value
10. But let's see what happens.
The preprocessor always substitutes text for macros exactly as you have
written it. So it first substitutes the replacement text for the macro C, resulting
in
int x = A + B * 2;
Then it substitutes the macros A and B, resulting in
int x = 2 + 3 * 2;
Only when the preprocessor is done doing all this substituting does the
compiler get into the act. But when it evaluates that expression (using the
normal precedence of multiplication over addition), it ends up initializing x with
the value 8!
To guard against this sort of problem, it is always a good idea to include explicit
parentheses in the definitions of macros which contain expressions. If we were
to define the macro C as

Manipal University Jaipur Page No.: 184


Programming in C Unit 1

#define C (A + B)
then the declaration of x would ultimately expand to
int x = (2 + 3) * 2;
and x would be initialized to 10, as we probably expected.
Notice that there does not have to be (and in fact there usually is not) a
semicolon at the end of a #define line. (This is just one of the ways that the
syntax of the preprocessor is different from the rest of C.) If you accidentally
type
#define MAXLINE 100; /* WRONG */
then when you later declare
char line[MAXLINE];
the preprocessor will expand it to
char line[100;]; /* WRONG */
which is a syntax error. This is what we mean when we say that the
preprocessor doesn't know much of anything about the syntax of C-- in this last
example, the value or replacement text for the macro MAXLINE was the 4
characters 1 0 0 ; , and that's exactly what the preprocessor substituted (even
though it didn't make any sense).
Simple macros like MAXLINE act sort of like little variables, whose values are
constant (or constant expressions). It's also possible to have macros which
look like little functions (that is, you invoke them with what looks like function
call syntax, and they expand to replacement text which is a function of the
actual arguments they are invoked with) but we won't be looking at these yet.
11.3.1 Macros with arguments
The preprocessor permits us to define more complex and more useful form of
replacements. It takes the form:
# define identifiedf1, f2, ..., fn) string
Notice that there is no space between the macro identifier and the left
parenthesis. The identifiers f1, f2, ., fn are the formal macro arguments that are
analogous to the formal arguments in a function definition.
There is a basic difference between the simple replacement discussed above
Manipal University Jaipur Page No.: 185
Programming in C Unit 1

and the replacement of macros with arguments. Subsequent occurrence of a


macro with arguments is known as a macro call. When a macro is called, the
preprocessor substitutes the string, replacing the formal parameters with actual
parameters.
A simple example of a macro with arguments is
# define CUBE(x) (x*x*x)
If the following statement appears later in the program volume=CUBE(side);
then the preprocessor would expand this statement to:
volume=(side*side*side);
Consider the following statement: volume=CUBE(a+b);
This would expand to:
volume=(a+b*a+b*a+b);
which would obviously not produce the correct results. This is because the
preprocessor performs a blind text substitution of the argument a+b in place of
x. This shortcoming can be corrected by using parentheses for each
occurrence of a formal argument in the string.
Example:
# define CUBE(x) ((x)*(x)*(x))
This would result in correct expansion of CUBE(a+b) as shown below:
volume=((a+b)*(a+b)*(a+b));
Some commonly used definitions are:
#define MAX(a,b) (((a) > (b))?(a):(b))
#define MIN(a,b) (((a) <(b))?(a):(b))
#define ABS(x) (((x) > 0)?(x):(-(x)))
11.3.2 Nesting of Macros
We can also use one macro in the definition of another macro. That is, macro
definitions may be nested. For instance, consider the following macro
definitions:
# define M 5
# define N M+1
#define SQUARE(x) ((x)*(x))
# define CUBE(x) (SQUARE(x)*(x))

Manipal University Jaipur Page No.: 186


Programming in C Unit 1

#define SIXTH(x) (CUBE(x)*CUBE(x))


Self Assessment Questions
4. The role of preprocessor in macro substitution is __________________
substitution according to the macro definition.
5. Macros and functions are synonyms. (True/False)
6. Nesting of macros is not allowed. (True/False)

11.4 Conditional Compilation


The last preprocessor directive we're going to look at is #ifdef. If you have the
sequence
#ifdef name
program text
#else
more program text
#endif
in your program, the code that gets compiled depends on whether a
preprocessor macro by that name is defined or not. If it is (that is, if there has
been a #define line for a macro called name), then “program text is compiled
and “more program text’’ is ignored. If the macro is not defined, “more program
text’’ is compiled and “program text’’ is ignored. This looks a lot like an if
statement, but it behaves completely differently: an if statement controls which
statements of your program are executed at run time, but #ifdef controls which
parts of your program actually get compiled.
Just as for the if statement, the #else in an #ifdef is optional. There is a
companion directive #ifndef, which compiles code if the macro is not defined
(although the “#else clause'' of an #ifndef directive will then be compiled if the
macro is defined). There is also an #if directive which compiles code depending
on whether a compile-time expression is true or false. (The expressions which
are allowed in an #if directive are somewhat restricted, however, so we won't
talk much about #if here.)
Conditional compilation is useful in two general classes of situations:
• You are trying to write a portable program, but the way you do something
is different depending on what compiler, operating system, or computer
you're using. You place different versions of your code, one for each
situation, between suitable #ifdef directives, and when you compile the

Manipal University Jaipur Page No.: 187


Programming in C Unit 1

program in a particular environment, you arrange to have the macro names


defined which select the variants you need in that environment. (For this
reason, compilers usually have ways of letting you define macros from the
invocation command line or in a configuration file, and many also predefine
certain macro names related to the operating system, processor, or
compiler in use. That way, you don't have to change the code to change
the #define lines each time you compile it in a different environment.)
For example, in ANSI C, the function to delete a file is remove. On older
Unix systems, however, the function was called unlink. So if filename is a
variable containing the name of a file you want to delete, and if you want
to be able to compile the program under these older Unix systems, you
might write
#ifdef unix
unlink(filename);
#else
remove(filename);
#endif
Then, you could place the line
#define unix
at the top of the file when compiling under an old Unix system. (Since all
you're using the macro unix for is to control the #ifdef, you don't need to
give it any replacement text at all. Any definition for a macro, even if the
replacement text is empty, causes an #ifdef to succeed.) (In fact, in this
example, you wouldn't even need to define the macro unix at all, because
C compilers on old Unix systems tend to predefine it for you, precisely so
you can make tests like these.)
• You want to compile several different versions of your program, with
different features present in the different versions. You bracket the code for
each feature with #ifdef directives, and (as for the previous case) arrange
to have the right macros defined or not to build the version you want to
build at any given time. This way, you can build the several different
versions from the same source code. (One common example is whether
you turn debugging statements on or off. You can bracket each debugging
printout with #ifdef DEBUG and #endif, and then turn on debugging only
when you need it.)

Manipal University Jaipur Page No.: 188


Programming in C Unit 1

For example, you might use lines like this:


#ifdef DEBUG
printf("x is %d\n", x);
#endif
to print out the value of the variable x at some point in your program to see
if it's what you expect. To enable debugging printouts, you insert the line
#define DEBUG
at the top of the file, and to turn them off, you delete that line, but the
debugging printouts quietly remain in your code, temporarily deactivated,
but ready to reactivate if you find yourself needing them again later. (Also,
instead of inserting and deleting the #define line, you might use a compiler
flag such as -DDEBUG to define the macro DEBUG from the compiler
invocating line.)
Conditional compilation can be very handy, but it can also get out of hand.
When large chunks of the program are completely different depending on,
say, what operating system the program is being compiled for, it's often
better to place the different versions in separate source files, and then only
use one of the files (corresponding to one of the versions) to build the
program on any given system. Also, if you are using an ANSI Standard
compiler and you are writing ANSI-compatible code, you usually won't need
so much conditional compilation, because the Standard specifies exactly
how the compiler must do certain things, and exactly which library functions
it much provide, so you don't have to work so hard to accommodate the old
variations among compilers and libraries.
Self Assessment Questions
7. In ANSI C, the function to delete a file is _________ .
8. On older Unix systems, the function was called ____________ .
9. You can use __________________ directive which compiles code
depending on whether a compile-time expression is true or false.

11.5 Summary
Preprocessor is a unique feature of C language. The C preprocessor provides
several tools that are unavailable in other high-level languages. The
preprocessor is a program that processes the source code before it passes
through the compiler. Macro substitution is a process where an identifier in a

Manipal University Jaipur Page No.: 189


Programming in C Unit 1

program is replaced by a predefined text. The preprocessor permits us to


define more complex and more useful form of replacements with macros with
arguments. Nesting of macros is also allowed to simplify the complex macro
definitions. An external file containing functions or macro definitions can be
included as a part of a program.

11.6 Terminal Questions


1. What is the difference between a macro call and a function call?
2. List some of the Compiler Control preprocessor directives.
3. Distinguish between the following macro definitions:
#include “filename” and #include <filename>
4. What is the preprocessor directive used to undefine a macro? Show with
an example.
5. Write a macro definition to find the square of a number. Explain it with the
help of an example.
11.7 Answers to Self Assessment Questions
1. Preprocessor directive
2. False
3. True
4. Text
5. False
6. False
7. remove
8. unlink.
9. #if

11.8 Answers to Terminal Questions


1. When a macro is called, the macro definition with string substitution will be
inserted in the place of call in the source program whereas in a function
call the execution control will transfer to the function.
2. #ifdef, #ifndef, #if, #else
3. Preprocessor searches for files enclosed in <> in central, standard
directories, and it searches for files enclosed in "" in the current directory.
4. #undef (Refer the entire unit for more details)
5. #define SQUARE(x) ((x)*(x)) (Refer the entire unit for more details)
Manipal University Jaipur Page No.: 190
Programming in C Unit 1

11.9 Exercises
1. Write a macro definition to find the largest of three numbers.
2. Write a macro definition to compare two numbers.
3. What are the advantages of using macro definitions in a program?
4. Define a macro, PRINT_VALUE which can be used to print two values of
arbitrary type.
5. Identify errors, if any, in the following macro definition.
#define ABS(x) (x>0)?(x):(-x)
Unit 12 Dynamic Memory Allocation and
Linked List
Structure:
12.1 Introduction
Objectives
12.2 Dynamic Memory Allocation
Allocating Memory with malloc
Allocating Memory with calloc
Freeing Memory
Reallocating Memory Blocks
12.3 Pointer Safety
12.4 The Concept of linked list
Inserting a node by using Recursive Programs
Sorting and Reversing a Linked List
Deleting the Specified Node in a Singly Linked List
12.5 Summary
12.6 Terminal Questions
12.7 Answers to Self Assessment Questions
12.8 Answers for TerminalQuestions
12.9 Exercises

12.1 Introduction
In the previous unit, you studied about the preprocessor in C. You studied that
the preprocessor is a program that processes the source code before it passes
through the compiler and hence it can be used to make C an easy and efficient
language. In this unit, you will study about the dynamic memory allocation
techniques. You will also study about the linked list that is another useful

Manipal University Jaipur Page No.: 191


Programming in C Unit 1

application using C.
You can use an array when you want to process data of the same data type
and you know the size of the data. Sometimes you may want to process the
data but you don't know what the size of the data is. An example of this is when
you are reading from a file or keyboard and you want to process the values. In
such a case, an array is not useful because you don't know what the dimension
of the array should be. C has the facility of dynamic memory allocation. Using
this, you can allocate the memory for your storage. The allocation is done at
runtime. When your work is over, you can deallocate the memory. The
allocation of memory is done using three functions: malloc, calloc, and realloc.
These functions return the pointers to void, so it can be typecast to any data
type, thus making the functions generic. These functions take the input as the
size of memory requirement.
Objectives:
After studying this unit, you should be able to:
• explain about the dynamic memory allocation
• implement dynamic memory allocation functions like -malloc, calloc and
realloc
• explain the concept of linked lists
• discuss the different operations on linked lists

12.2 Dynamic Memory Allocation


The process of allocating memory at run time is known as Dynamic Memory
Allocation. Although C does not inherently have this facility, there are four
library routines known as “Memory Management Functions” that can be used
for allocating and freeing memory during program execution. They are listed in
Table 12.1. These functions help us build complex application programs that
use the available memory intelligently.
Table 12.1: Functions used for Dynamic Memory allocations and its tasks
Function Tasks
malloc Allocates requested size of bytes and returns a pointer to the first
byte of the allocated space
calloc Allocates space for an array of elements, initializes them to zero
and then returns a pointer to the memory
free Frees previously allocated space
realloc Modifies the size of previously allocated space

Manipal University Jaipur Page No.: 192


Programming in C Unit 1

Figure 12.1 shows the conceptual view of storage of a C program in memory.


Local variables _____________
Free memory
Global variables C program instructions
Figure 12.1: storage of a C program- a conceptual view
The program instructions and global and static variables are stored in a region
known as permanent storage area and the local variables are stored in another
area called stack. The memory space that is located between these two
regions is available for dynamic allocation during execution of the program.
This free memory region is called heap. The size of the heap keeps changing
when program is executed due to creation and death of variables that are local
to functions and blocks. Therefore, it is possible to encounter memory
“overflow” during dynamic allocation process.
12.2.1 Allocating Memory with malloc
A problem with many simple programs, including in particular little teaching
programs such as we've been writing so far, is that they tend to use fixed- size
arrays which may or may not be big enough. We have an array of 100 ints for
the numbers which the user enters and wishes to find the average of them,
what if the user enters 101 numbers? We have an array of 100 chars which we
pass to getline to receive the user's input, what if the user types a line of 200
characters? If we're lucky, the relevant parts of the program check how much
of an array they've used, and print an error message or otherwise gracefully
abort before overflowing the array. If we're not so lucky, a program may sail off
the end of an array, overwriting other data and behaving quite badly. In either
case, the user doesn't get his job done. How can we avoid the restrictions of
fixed-size arrays?
The answers all involve the standard library function malloc. Very simply,
malloc returns a pointer to n bytes of memory which we can do anything we
want to with. If we didn't want to read a line of input into a fixed-size array, we
could use malloc, instead. It takes the following form:
ptr=(cast-type *)malloc(byte-size)
where ptr is a pointer of type cast-type. The malloc returns a pointer(of cast-
type) to an area of memory with size byte-size.
Here is an example
#include <stdlib.h>

Manipal University Jaipur Page No.: 193


Programming in C Unit 1

char *line;
int linelen = 100;
line = (char *)malloc(linelen);
/* incomplete -- malloc's return value not checked */ getline(line,
linelen);
malloc is declared in <stdlib.h>, so we #include that header in any program
that calls malloc. A “byte'' in C is, by definition, an amount of storage suitable
for storing one character, so the above invocation of malloc gives us exactly
as many chars as we ask for. We could illustrate the resulting pointer like this:

The 100 bytes of memory (not all of which are shown) pointed to by line are
those allocated by malloc. (They are brand-new memory, conceptually a bit
different from the memory which the compiler arranges to have allocated
automatically for our conventional variables. The 100 boxes in the figure don't
have a name next to them, because they're not storage for a variable we've
declared.)
As a second example, we might have occasion to allocate a piece of memory,
and to copy a string into it with strcpy:
char *p = (char *)malloc(15);
/* incomplete -- malloc's return value not checked */
strcpy(p, "Hello, world!");
When copying strings, remember that all strings have a terminating \0
character. If you use strlen to count the characters in a string for you, that count
will not include the trailing \0, so you must add one before calling malloc:
char *somestring, *copy;
...
copy = (char *)malloc(strlen(somestring) + 1); /* +1 for \0 */
/* incomplete -- malloc's return value not checked */ strcpy(copy,
somestring);
What if we're not allocating characters, but integers? If we want to allocate 100

Manipal University Jaipur Page No.: 194


Programming in C Unit 1

ints, how many bytes is that? If we know how big ints are on our machine (i.e.
depending on whether we're using a 16- or 32-bit machine) we could try to
compute it ourselves, but it's much safer and more portable to let C compute it
for us. C has a sizeof operator, which computes the size, in bytes, of a variable
or type. It's just what we need when calling malloc. To allocate space for 100
ints, we could call
int *ip =(int *)malloc(100 * sizeof(int));
The use of the sizeof operator tends to look like a function call, but it's really
an operator, and it does its work at compile time.
Since we can use array indexing syntax on pointers, we can treat a pointer
variable after a call to malloc almost exactly as if it were an array. In particular,
after the above call to malloc initializes ip to point at storage for 100 ints, we
can access ip[0], ip[1], ... up to ip[99]. This way, we can get the effect of an
array even if we don't know until run time how big the “array'' should be. (In a
later section we'll see how we might deal with the case where we're not even
sure at the point we begin using it how big an “array'' will eventually have to
be.)
Our examples so far have all had a significant omission: they have not checked
malloc's return value. Obviously, no real computer has an infinite amount of
memory available, so there is no guarantee that malloc will be able to give us
as much memory as we ask for. If we call malloc(100000000), or if we call
malloc(10) 10,000,000 times, we're probably going to run out of memory.
When malloc is unable to allocate the requested memory, it returns a null
pointer. A null pointer, remember, points definitively nowhere. It's a “not a
pointer'' marker; it's not a pointer you can use. Therefore, whenever you call
malloc, it's vital to check the returned pointer before using it! If you call malloc,
and it returns a null pointer, and you go off and use that null pointer as if it
pointed somewhere, your program probably won't last long. Instead, a program
should immediately check for a null pointer, and if it receives one, it should at
the very least print an error message and exit, or perhaps figure out some way
of proceeding without the memory it asked for. But it cannot go on to use the
null pointer it got back from malloc in any way, because that null pointer by
definition points nowhere. (“It cannot use a null pointer in any way'' means that
the program cannot use the * or [] operators on such a pointer value, or pass
it to any function that expects a valid pointer.)
Manipal University Jaipur Page No.: 195
Programming in C Unit 1

A call to malloc, with an error check, typically looks something like this:
int *ip = (int *)malloc(100 * sizeof(int));
if(ip == NULL)
{
printf("out of memory\n"); exit or return
}
After printing the error message, this code should return to its caller, or exit
from the program entirely; it cannot proceed with the code that would have
used ip.
Of course, in our examples so far, we've still limited ourselves to “fixed size''
regions of memory, because we've been calling malloc with fixed arguments
like 10 or 100. (Our call to getline is still limited to 100-character lines, or
whatever number we set the linelen variable to; our ip variable still points at
only 100 ints.) However, since the sizes are now values which can in principle
be determined at run-time, we've at least moved beyond having to recompile
the program (with a bigger array) to accommodate longer lines, and with a little
more work, we could arrange that the “arrays'' automatically grew to be as large
as required. (For example, we could write something like getline which could
read the longest input line actually seen).
12.2.2 Allocating memory with calloc
calloc is another memory allocation function that is normally used for
requesting memory space at run time for storing derived data types such as
arrays and structures. While malloc allocates a single block of storage space,
calloc allocates multiple blocks of storage, each of the same size, and then
sets all bytes to zero. The general form of calloc is:
ptr=(cast-type *)calloc(n, elem-size);
The above statement allocates contiguous space for n blocks, each of size
elem-size bytes. All bytes are initialized to zero and a pointer to the first byte
of the allocated region is returned. If there is not enough space, a NULL pointer
is returned.
Program 12.1 Program to illustrate the use of malloc and calloc
functions
#include <stdio.h>
#include <malloc.h>
Manipal University Jaipur Page No.: 196
Programming in C Unit 1

main()
{
int *base;
int i;
int cnt=0;
int sum=0;
printf("how many integers you have to store \n");
scanf("%d",&cnt);
base = (int *)malloc(cnt * sizeof(int));
printf("the base of allocation is %16lu \n",base);
if(!base)
printf("unable to allocate size \n");
else
{
for(int j=0;j<cnt;j++)
*(base+j)=5;
}
sum = 0;
for(int j=0;j<cnt;j++)
sum = sum + *(base+j);
printf("total sum is %d\n",sum);
free(base);
printf("the base of allocation is %16lu \n",base);
base = (int *)malloc(cnt * sizeof(int));
printf("the base of allocation is %16lu \n",base);
base = (int *)malloc(cnt * sizeof(int));
printf("the base of allocation is %16lu \n",base);
base = (int *)calloc(10,2);
printf("the base of allocation is %16lu \n",base);
}
12.2.3 Freeing Memory
Memory allocated with malloc lasts as long as you want it to. It does not
automatically disappear when a function returns, as automatic variables do,
but it does not have to remain for the entire duration of your program, either.
Just as you can use malloc to control exactly when and how much memory
you allocate, you can also control exactly when you deallocate it.
In fact, many programs use memory on a transient basis. They allocate some
Manipal University Jaipur Page No.: 197

You might also like