PPS_Unit_III_Notes_After_Loops
PPS_Unit_III_Notes_After_Loops
PPS_Unit_III_Notes_After_Loops
Array
Types of Array
We can use arrays to represent not only simple lists of values but also tables of data in
two, or more dimensions. Following are the types of an array:
1. One-dimensional arrays
2. Two-dimensional arrays
3. Multidimensional arrays
One-Dimensional Arrays
A list in which the elements are accessible by the variable name assigned to the list and
its subscript is known as a one-dimensional array.
Like any other variable, arrays must be declared before they are used so that the compiler
can allocate space for them in memory. The general form of array declaration is:
Type var_name [ size ];
The Type specifies the type of element that will be contained in the array and size
indicates the maximum number of elements that can be stored inside the array. For
example:
int list [10] ;
declares the list as an array to contain a maximum of 10 integer.
The C language treats character string simply as arrays of characters. For example:
char name [15];
declares the name as a character array (string) variable that can hold a maximum of 15
characters.
We can initialize the elements of arrays in the same way as the ordinary variables when
they are declared. For example:
int list [10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; or
int list [ ] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
char name [15] = {‘B’, ‘h’, ‘a’, ‘g’, ‘I’, ‘r’, ‘a’, ‘t’, ‘h’, ‘\0’ }; or
char name [ ] = “Bhagirath”;
The values to the array elements can also be assigned as follows:
list[ 0] = 10;
list [1] = 20;
list [2] = 30;
Two-Dimensional Array
The two-dimensional (2-D) array is also called a matrix. C allows to define table (matrix) of
items by using two-dimensional arrays. Each dimension of the array is indexed from zero
to its maximum size minus one. Two-dimensional arrays are declared as follows:
Type table [2][3];
We think of this table as a matrix consisting of two rows and three columns.
Memory Layout
The subscripts in the definition of a two-dimensional array represent rows and columns.
This format maps the way that data elements are laid out in the memory. The elements of
all arrays are stored contiguously in increasing memory location, essentially in a single
list. If we consider the memory as a row by bytes, with the lowest address on the left and
the highest address on the right, a simple array will be stored in memory with the first
element at the left end and the last element at the right end. Similarly, a two-dimensional
array is stored “row-wise”, starting from the first row and ending with the last row, treating
each row like a simple array.
Multi-Dimensional Arrays
C allows arrays of three or more dimensions. The exact limit is determined by the
compiler. The general form of a multi-dimensional array is:
Type arr_name[s1][s2][s3];
Where s1, s2 and s3 are the size of the dimension. For example:
int report[2][2][3];
An array created at compile time by specifying size in the source code has a fixed size
and cannot be modified at run time. The process of allocating memory at compile time is
known as static memory allocation and the arrays that receive static memory allocation
are called static arrays.
In C it is possible to allocate memory to arrays at run time. This feature is known as
dynamic memory allocation and the array created at run time are called dynamic
arrays. Dynamic arrays are created using pointer variables and memory management
functions malloc, calloc and realloc.
String-Handling Functions
The C library supports a large number of string-handling functions that can be used to
carry out many of the string manipulations. Following are the most commonly used string-
handling functions:
strlen() Function
This function counts and returns the number of characters in a string. It takes the form:
len = strlen(str);
Where len is an integer variable, which receives the value of the length of the string str.
The argument may be a string constant. For example:
printf( “Total characters = %d”, strlen(“Bhagirath”) );
will print “Total characters = 9”.
strcpy() Function
The strcpy function works almost like a string-assignment operator. It takes the following
form:
strcpy( str1, str2);
and assigns the contents of str2 to str1. str2 may be a character array variable or a string
constant. For example, the statement
strcpy(name, “Bhagirath”);
will assign the string “Bhagirath” to the string variable name.
strcat() Function
The strcat function joins two strings together. It takes the following form:
strcat (str1, str2);
str1 and str2 are character arrays. When the function strcat is executed, str2 is
appended to str1. The string at str2 remains unchanged. For example:
strcpy(name, “Bhagirath”);
strcat(name, “Singh”);
strcmp() Function
The strcmp function compares two strings identified by the arguments and has a value 0 if
they are equal. It they are not, it has the numeric difference between the first nonmatching
characters in the strings. It takes the form:
strcmp (str1, str2 );
str1 and str2 may be string variables or string constants. Examples are:
strcmp(name1, name2);
strcmp(name, “Bhagirath”);
User-Defined Functions
If a program is divided into functional parts, then each part may be independently coded
and later combined into a single unit. These independently coded programs are called
subprograms that are much easier to understand, debug, and test. In C, such
subprograms are referred to as ‘functions’. This ‘division’ approach clearly results in a
number of advantages.
It facilitates top-down modular programming.
The length of a source program can be reduced by using functions.
It is easy to locate and isolate a faulty function for further investigations.
A function may be used by many other programs.
Modular Programming
In order to make use of a user-defined function, we need to establish three elements that
are related to functions.
1. Function declaration
2. Function definition
3. Function call
The function definition is an independent program module that is specially written to
implement the requirements of the function. In order to use this function we need to invoke
it at a required place in the program. This is known as the function call. The program that
calls the function is referred to as the calling program or calling function. The calling
program should declare any function that is to be used later in the program. This is known
as the function declaration or function prototype.
Definition of Functions
A function definition, also known as function implementation shall include the following
elements:
Function name
Return type
List of parameters
Local variable declarations
Function statements
Return statement
Category of Functions
A function, depending on whether arguments are present or not and whether a value is
returned or not, may belong to one of the following categories:
1. Functions with NO arguments and NO return values.
2. Functions WITH arguments and NO return values.
3. Functions NO arguments and WITH return values.
4. Functions WITH arguments and WITH return values.
5. Functions that return multiple values.
Recursion
When a called function in turn calls another function a process of ‘chaining’ occurs.
Recursion is a special case of this process, where a function calls itself. For example:
main()
{
printf( “main() is called recursively” )
main();
}
Recursive functions can be effectively used to solve problems where solution is expressed
in terms of successively applying the same solution to subsets of the problem. For
example, following the C function to generate the nth term of Fibonacci series:
int fibo( int n )
{
if ( n <=0 )
{ printf (“Series cannot be generated”);
return -111; //error state
}
else if ( n == 1 || n == 2)
return 1;
else
return ( fibo(n – 1 ) + fibo( n – 2 ) );
}
Like the values of simple variables, it is also possible to pass the values of an array to a
function. To pass a one-dimensional array to a called function it is sufficient to list the
name of the array, without any subscripts, and the size of the array as arguments. For
example, the call
maximum ( arr, n );
will pass the whole array arr to the called function. The maximum function header might
look like:
int maximum ( int arr[ ], int size );
The function maximum is defined to take two arguments, the array name and the size of
the array to specify the number of elements in the array.
In C, the name of the array represents the address of its first element. By passing the
array name, we are, in fact, passing the address of the array to the called function. The
array in the called function now refers to the same array stored in the memory. Therefore,
any changes in the array in the called function will be reflected in the original array.
Like simple arrays, we can also pass multi-dimensional arrays to functions. The approach
is similar to the one we did with one-dimensional arrays. The rules are simple.
1. The function must be called by passing only the array name.
2. In the function definition, we must indicate that the array has two-dimensions by
including two sets of brackets.
3. The size of the second dimension must be specified.
4. The prototype declaration should be similar to the function header.
The strings are treated a character arrays in C and therefore the rules for passing strings
to function are very similar to those for passing arrays to functions. Basic rules are:
1. The string to be passed must be declared as a formal argument of the function
when it id defined. Example:
void show ( char str[ ] )
{
//body of function
}
2. The function prototype must show that the argument is a string. For example:
void show( char str[ ] );
3. A call to the function must have a string array name without subscripts as its actual
argument. For example:
show( name );
where name is a properly declared string array in the calling function.
The parameters specified in the function call are known as actual parameters and those
specified in the function declaration are known as formal parameters. The scope of formal
parameters is limited to its function only.
Parameter passing is a mechanism for communication of data and information between
the calling function (caller) and the called function (callee). It can be achieved either by
passing the value or address of the variable. C supports the following two types of
parameter passing schemes:
1. Pass By Value
2. Pass By Address (Pointer)
Pass By Value
Pass-by-value mechanism does not change the contents of the argument variable in the
calling function, even if they are changed in the called function.
Example: Swap integer values by pass by value.
void swap (int x, int y) int main()
{ {
int t; int a, b;
t = x; printf(“Enter two numbers: ”);
x = y; scanf((%d%d”,&a, &b);
y = t; swap ( a, b );
printf(“After swaping in swap fun”); printf(“\nAfter calling swap function”);
printf(“\nx = %d y = %d”, x, y); printf(“\n a = %d b = %d”, a, b);
} }
Pass By Address
In Pass-by-Address mechanism, instead of passing the value, the address of the variable
is passed in the function. The de-referencing operator ( * ) is used to access the variable
in the called function.
Example: Swap integer values by pass by address.
void swap (int * x, int * y) int main()
{ {
int t; int a, b;
t = * x; printf(“Enter two numbers: ”);
x = * y; scanf((%d%d”,&a, &b);
y = * t; swap ( &a, &b );
printf(“After swaping in swap fun”); printf(“\nAfter calling swap function”);
printf(“\nx = %d y = %d”, * x, * y); printf(“\n a = %d b = %d”, a, b);
} }
Storage Classes
(The Scope, Visibility, and Lifetime of Variables)
In C all variables have a data type and also have a storage class. A variable’s storage
class tells us the following things about the variable:
Where would the variable be stored.
What would be the default initial value of the variable.
What would be the scope of the variable, i.e., to which statements the value of the
variable would be available.
What would be the life of the variable, i.e., how long would the variable exist.
Storage Default
Storage Scope Life
Class Value
Local to the block in Till the control remains
auto Memory Garbage which variable is within the block in which the
defined. variable is defined.
Local to the block in Till the control remains
register CPU Register Garbage which variable is within the block in which the
defined. variable is defined.
Local to the block in Value of the variable
static Memory Zero which variable is persists between different
defined. function calls.
As long as the program’s
extern Memory Zero Global execution doesn’t come to
an end.
Multifile Programs
In real-life programming environment, we may use more than one source files which may
be compiled separately and linked later to form an executable object code. This approach
is very useful because any change in one file done not affect other files thus eliminating
the need for recompilation of the entire program.
Multifile source files can share a variable provided it is declared as an external variable
appropriately. Variables that are shared by two or more files are global variables and
therefore we must declare them accordingly in one file and then explicitly define them with
extern in other files.
C supports a constructed data type known as structure, a mechanism for packing data of
different types. A structure is a convenient tool for handling a group of logically related
data items. Structure help to organize complex data in a more meaningful way.
Defining a Structure
Unlike arrays, structures must be defined first for their format that may be used later to
declare structure variables. For example:
struct record
{
int rollno;
char name[20];
float per;
};
struct record student1, student2;
The keyword struct declares a structure to hold the details of three data fields, namely
rollno, name and per. These fields are called structure elements or members. Each
member may belong to a different type of data. record is the name of the structure and is
called the structure tag.
Student1 and student2 are the variable of type struct record.
The link between a member and a variable is established using the member operator ‘.’
Which is also known as ‘dot operator’. For example:
student1.roll = 201;
strcpy(student1.name, “Bhagirath”);
We can also use scanf function to give the values through the keyboard.
Structure Initialization
Like any other data type, a structure variable can be initialized at compile time like:
struct record
{
int rollno;
char name[20];
float per;
};
struct record student1 = { 201, “Bhagirath”, 88.0 };
Arrays of Structures
There are three methods by which the values of a structure can be transferred from one
function to another:
1. The first method is to pass each member of the structure as an actual argument.
2. The second method involves passing of a copy of the entire structure.
3. The third method employs passing address of a structure to a function.
The general format of sending a copy of a structure to the called function is:
Function_name ( structure_variable );
When a structure is used as an argument to a function, the entire structure is passed
using the call by value method. When using a structure as a parameter, remember that the
type of the argument must match the type of the parameter.
structure which contain a member field that point to the same structure type are called
self referential structures. Each structure consist of two fields, one containing the
item, and the other containing the address of the next item (a pointer to the next item).
For example:
struct node
{
int code;
struct node *next;
};
Such a structure is also called dynamic data structure. Using self-referential structure,
a list can grow or shrink in size during the execution of a program. This list does not
waste memory space. It uses the memory that is just needed for the list at any point of
time.
Union
Union are a concept borrowed from structures and therefore follow the same syntax as
structures. However, there is major distinction between them in terms of storage. In
structures, each member has its own storage location, whereas all the members of a
union use the same location. This implies that, although a union may contain many
members of different types, it can handle only one member at a time. Like structures, a
union can be declared using the keyword union as follows:
union item
{
char c;
int m;
float x;
} code;
This declares a variable code of type union item. The union contains three members,
each with a different data type. However, we can use only one of them at a time. The
compiler allocates a piece of storage that is large enough to hold the largest variable
type in the union.
Key
Structure Union
Difference
The keyword struct is used to The keyword union is used to
keyword
define a structure. define a union.
When a variable is When a variable is associated
associated with a structure, with a union, the compiler
the compiler allocates the allocates the memory by
Size memory for each member. considering the size of the largest
The size of structure is memory. So, size of union is
greater than or equal to the equal to the size of largest
sum of sizes of its members. member.
Each member within a
Memory allocated is shared by
Memory structure is assigned unique
individual members of union.
storage area of location.
Altering the value of a Altering the value of any of the
Value
member will not affect other member will alter other member
Altering
members of the structure. values.
Accessing Individual member can be Only one member can be
Members accessed at a time. accessed at a time.
Initialization Several members of a Only the first member of a union
of Members structure can initialize once. can be initialized.
The enumerated data type gives us an opportunity to invent our own data type and
define what values the variable of this data type can take. This can help in making the
program listings more readable.
enum dept
{
mca = 21, mba = 11, btech = 10, bca = 30
};
enum dept s1,s2,s3;
Now we can give values to these variables.
s1 = mca;
s2 = bca;
Internally, the compiler treats the enumerator as integers. Each value on the list of
permissible values corresponds to an integer, starting with 0. This way of assigning
numbers can be overridden by the programmer by initializing the enumerators to
different integer values.
Pointers
A pointer is a derived data type in C. It is built from one of the fundamental data types
available in C. Pointers contain memory addresses as their values. Since these memory
addresses are the locations in the computer memory where program instructions and
data are stored, pointers can be used to access and manipulate data stored in the
memory.
Pointers are used frequently in C, as they offer a number of benefits to the
programmers. They include:
Pointers can be used to return multiple values from a function via function
arguments.
Pointers permit references to functions and thereby facilitating passing of
functions as arguments to other functions.
The use of pointer arrays to character strings results in saving of data storage
space in memory.
Pointers allow C to support dynamic memory management.
Pointers provide an efficient tool for manipulating dynamic data structures such
as structures, linked lists, queues, stacks and trees.
Since pointer variables contain addresses that belong to a separate data type, they
must be declared as pointer before we use them. The declaration of a pointer variable
takes the following form:
Data_type * p_name;
This tells the compiler three things about the variable p_name.
1. The asterisk (*) tells that the variable p_name is a pointer variable.
2. p_name needs a memory location.
3. p_name points to a variable of type Data_type.
For example:
int *ptr;
declares the variable ptr as a pointer variable that points to an integer data type.
Once a pointer has been assigned the address of a variable, we can access the value
of the variable using the operator * (asterisk), usually known as the indirection operator.
Another name for the indirection operator is the dereferencing operator.
int num, *ptr, val;
num = 25;
ptr = #
val = *ptr;
Pointers to an Array
When an array is declared, the compiler allocates a base address and sufficient amount
of storage to contain all the elements of the array in contiguous memory locations.
Suppose we declare an array num as follows:
int num[50] = { 10, 20, 30, 40, 50 };
if we declare ptr as an integer pointer, then we can make the pointer ptr to point to the
array num by the following assignment:
ptr = num; or ptr = &num[0];
now we can access every value of num using ptr++ to move from one element to
another.
Pointers can be used to manipulate two-dimensional array as well. For example:
int v[2][3]; is a two-dimensional array,
int *ptr;
if we declare ptr as an int pointer with the initial address of &v[0][0], then
v[i][j] is equivalent to *(ptr+4 * i + j );
C supports a method to create strings using pointer variable of type char. Example
char *name = “Bhagirath”;
This creates a string for the literal and then stores its address in the pointer variable
name. Like in one-dimensional arrays, we can use a pointer to access the individual
characters in a string.
Array of Pointers
Pointers to Functions
A function, like a variable, has a type and an address location in the memory. It is
therefore, possible to declare a pointer to a function, which can then be used as an
argument in another function. A pointer to a function is declared as follows:
type (*funptr) ( ) ;
This tells the compiler that funptr is a pointer to a function, which return type value. The
parentheses around *funptr are necessary.
We can make a function pointer to point to a specific function by simply assigning the
name of the function to the pointer. For example:
int sum ( int, int ); //function prototype
int (*ptr) (); //pointer to function
ptr = sum; //assign the name of the function to the pointer
(*ptr) (10, 20); //function call
void Pointer
A void pointer is a pointer that has no associated data type with it. A void pointer can
hold address of any type and can be type casted to any type.
int n = 10;
char ch = ‘w’;
void *ptr = &n; //void pointer holds address of int n.
ptr = &ch; //void pointer holds address of char ch.
We know that the name of an array stands for the address of its zeroth element. The
same thing is true of the names of arrays of structure variables. Suppose students is an
array variable of struct type. The name students represents the address of its zeroth
element.
struct record
{
int rollno;
char name[30];
float per;
} students[5], *ptr;
ptr = students;
The pointer ptr will now point to students[0]. Its members can be accessed using the
following notation:
ptr -> rollno;
ptr ->name;
ptr -> per;
The symbol -> is called the arrow operator (also known as member selection operator).
We could also use the notation:
(*ptr).rollno;
File Management in C
A computer system stores programs and data in secondary storage in the form of files.
Storing programs and data permanently in main memory is not preferred due to the
following reasons:
Main memory is usually too small to permanently store all the needed programs
and data.
Main memory is a volatile storage device, which loses its contents when power is
turned off.
It is therefore necessary to have a more flexible approach where data can be stored on
the disks and read whenever necessary, without destroying the data. This method
employs the concept of files to store data. A file is a place on the disk where a group of
related data is stored.
To perform file operations in C, the important file handling functions that are available in
the C library are:
Function
Operation
Name
fopen() Creates a new file or Open an existing file for use.
fclose() Closes a file which has been opened for use.
getc() or fgetc() Reads a character from a file.
putc() or fputc() Writes a character to a file.
getw() Reads an integer from a file.
putw() Writes an integer to a file.
fprintf() Writes a set of data values to a file.
fscanf() Reads a set of data values from a file.
fseek() Sets the position to a desired point in the file.
Gives the current position in the file (in terms of bytes from the
ftell()
start).
rewind() Sets the position to the beginning of the file.
Data structure of a file is defined as FILE in the library of standard I/O function
definitions. When we open a file, we must specify what we want to do with the file. For
example, we may write data to the file or read the already existing data. Following is the
general format for declaring and opening a file:
FILE *fptr;
fptr = fopwn (“filename”, “mode”);
The first statement declares the variable fptr as a ‘pointer to the data type FILE’. The
second statement specifies the purpose of opening this file. Mode can be one the
following:
r open the file for reading only.
w open the file for writing only.
a open the file for appending (or adding) data to it.
Closing a File
A file must be closed as soon as all operations on it have been completed. This ensures
that all outstanding information associated with the file is flushed out from the buffers
and all links to the file are broken. It also prevents any accidental misuse of the file. The
I/O library supports a function to do this. It takes the following form:
fclose (file_pointer);
This would close the file associated with the FILE pointer file_pointer.
The simplest file I/O function are getc and putc. These functions handle one character
at a time.
putc ( ch, fptr );
writes the character contained in the character variable ch to the file associated with
FILE pointer fptr.
ch = getc ( fptr );
would read a character from the file whose file pointer is fptr.
The getw and putw are integer-oriented function. They are used to read and write
integer values. The general forms of getw and putw are as follows:
putw ( int_num , fptr );
int_num = getw ( fptr );
The functions fprintf and fscanf perform I/O operations that are identical to the familiar
printf anf scanf functions, except that they work on files. The first argument of these
functions is a file pointer which specifies the file to be used. General form of fprintf is:
fprintf ( fptr, “control string” , list);
where fptr is a file pointer associated with a file that has been opened for writing. The
control string contains output specifications for the items in the list.
The general format of fscanf is:
fscanf ( fptr, “control string”, list);
This statement would cause the reading of the items in the list from the file specified by
fptr, according to the specifications contained in the control string.
It is possible that an error may occur during I/O operations on a file. Typical error
situations include the following:
Trying to read beyond the end-of-file mark.
Device overflow.
Trying to use a file that has not been opened.
Trying to perform an operation on a file, when the file is opened for another type
of operation.
Opening a file with an invalid filename.
Attempting to write to a write-protected file.
We have two status-inquiry library function, feof and ferror that can help us detect I/O
errors in the files.
The feof function can be used to test for an end of file condition. It takes a FILE pointer
as its only argument and returns a nonzero integer value if all of the data from the
specified file has been read, and returns zero otherwise.
if ( feof ( fptr ) )
printf(“End of file”);
The ferror function reports the status of the file indicated. It also takes a FILE pointer as
its argument and returns a nonzero integer if an error has been detected up to that
point, during processing. It returns zero otherwise.
if ( ferror( fptr ) != 0 )
printf (“Error occurred”);
Whenever a file is opened using fopen function, a file pointer is returned. If the file
cannot be opened for some reason, then the function returns a NULL pointer. This
facility can be used to test whether a file has been opened or not.
if ( fptr == NULL )
printf (“File opening Error”);
There are occasions, however, when we are interested in accessing only a particular
part of a file and not in reading the other parts. This can be achieved with the help of the
functions fseek, ftell, and rewind available in the I/O library.
ftell takes a file pointer and return a number of type long, that corresponds to the
current position. It takes the following form:
pos = ftell ( fptr );
rewind takes a file pointer and resets the position to the start of the file.
rewind ( fptr );
fseek function is used to move the file position to a desired location within the file. It
takes the following form:
fseek ( fptr, offset, position );
Here fptr is a pointer to the file concerned, offset specifies the number of positions
(bytes) to be moved from the location specified by position. The position can take one
of the following three values:
0 for beginning of file
1 for current position
2 for end of file