C - Notes FULL
C - Notes FULL
History of C
C was developed by a system programmer Dennis Ritchie in 1972, at American Telegraph
& Telecommunication (AT & T) Bell Laboratories in New Jersey USA. The C language is
often referred as middle level language because we can write high level as well as low
level programs through C.
Features of C
• C is a general purpose programming language. You can generate games, business
software, utilities, mathematical models, word processors, spreadsheets and other
kinds of software.
• C is a structured programming language. It uses structured statements such as
while, for loops in place of goto statement which cause bugs (error) in the program.
• System programming: C is used for system programming i.e. writing operating
system. The UNIX operating system is also rewritten from C. Major parts of
Windows, Linux, UNIX are still written in C because speed of execution is very fast
in C compare to other languages.
Structure of C program:
Documentation Section
Link Section (#include section)
Definition Section
Global Declaration Section
Main Function Section
{
Declaration Part
Execution Part
}
Subprogram Section (User Defined Function)
Function 1
Function 2
….
Function n
Preprocessor
A preprocessor is a program that processes our program before it is passed to the
compiler. Preprocessing is the first step of the language processing system. A
preprocessor mainly performs three tasks on the High Level Language code:
1. Removing comments
2. File inclusion
3. Macro expansion
C Tokens
Tokens are the smallest individual unit of a program. Each and every punctuation and
word that you come across in a C program is token. C programs are written using these
tokens and the syntax of the language. C has six types of tokens:
1. Keywords
2. Identifiers
3. Constants
4. Strings
5. Special symbols
6. Operators
Identifiers
Identifiers are the names given to variables, arrays, functions, pointers and structures.
These are user-defined names and consist of a sequence of letters and digits, with a letter
as a first character. Both uppercase and lowercase letters are permitted.
Variables
A variable is the name of a memory location that we use for storing data. We can change
the value of a variable and we can also reuse it multiple times. Each variable has a name,
data-type, size and the value it stores.
Rules for constructing variable name in C language are listed below:
• Variable name may be a combination of alphabets, digits or underscores.
• First character must be an alphabet or underscore.
• No commas or blank spaces are allowed in a variable name.
• No word, having a reserved meaning in C can be used for variable name.
• Lower and upper case letters are significant.
Constants
A constant in C refer to fixed values that does not change during the execution of a
program. There are four basic types of constants in C:
Character Constant
String Constant
Integer Constant
Real Constant
Integer Constant: An integer constant refers to a sequence of digits and has a numeric
value. There are three types of integers in C: decimal, octal and hexadecimal.
Decimal integers : 2, 45, -4 etc.
Octal integers : 020, -04 etc.
Hexadecimal integers : 0x4, -0x2B etc.
Real Constants: A number with a decimal point (fractional part) and an optional
preceding sign represents a real constant. A floating point number can also be
represented as exponential or scientific notation. For e.g. 0.0000987 can be written as
9.87*10-5 or 9.87e-05. Thus the general form is:
mantissa e exponent
So 9.87 is called mantissa and -05 is called as exponent.
Data Types
The way a value stored in a variable interpreted is known as its data type. In other words,
data type determines the type and size of data associated with variables. Every computer
language has its own set of data types it supports. A data type signifies two important
aspects:
1. Amount of space (size) to be reserved in the memory to store the data and
2. Nature (type) of data to be stored.
Data Types
Primitive/Primary/Basic Data Types Derived Data Types User Defined Data Types
- int - array - structure
- char - pointers - union
- float - typedef
- double - enum
- void
Sometimes the program requires only positive values. In such cases the data type can be
made unsigned. Thus the range of unsigned short int become 0 to 65535. Format specifier
for unsigned is %u. (unsigned short - %hu).
void type
The void type has no values. This is usually used to specify the type of functions. It can
also play the role of a generic type, meaning that it can represent any of the other
standard types.
typedef
C supports a feature known as ‘type definition’ that allows users to define an identifier that
would represent an existing data type. The user-defined data type identifier can later be
used to declare variables. It takes the general form:
typedef type identifier;
where type refers to an existing data type and ‘identifier’ refers to the ‘new’ name given to
the data type.
Operators
An operator is a symbol that operates on a value or a variable. An operator tells the
computer to perform certain mathematical or logical manipulations. For example: + is an
operator to perform addition.
Operators
Arithmetic operators
C provides all the basic arithmetic operators. The operators +, -, *, and / all work the same
way as they do in other languages. The % operator is known as modulus operator. It
produces the remainder after the division of two operands.
Operator Purpose
+ Addition
- Subtraction
* Multiplication
/ Division
% Remainder after integer division
Relational Operators
Relational operators is used to compare two operands. While the operands can be
variables, constants or expressions, the result is always either true or false.
Operator Meaning
== is equal to
!= not equal to
< less than
<= less than or equal to
> greater than
>= greater than or equal to
Logical Operators
More than one relational expression can be combined to form a single compound
relational expression using logical operators. A compound relation behaves identically
producing either true or false. C provide three logical operators:
Logical AND (&&) Logical OR (||) Logical NOT (!)
ex1 ex2 ex1&&ex2 ex1 ex2 ex1||ex2 exp !exp
0 0 0 0 0 0 0 1
1 0 0 1 0 1 1 0
0 1 0 0 1 1
1 1 1 1 1 1
Assignment Operators
Assignment operators are used to store the result of an expression to a variable. Note that
data type of both the sides should be either the same or compatible to each other.
Short Hand Assignment operator
x += 10; is equivalent to x = x + 10;
x -= 10; is equivalent to x = x - 10;
x *= 10; is equivalent to x = x * 10;
x /= 10; is equivalent to x = x / 10;
x %= 10; is equivalent to x = x % 10;
Conditional Operator
This is the only ternary type operator in C. This operator is a set of two operators (? and :)
which work together. Conditional operator always works with relational operators.
Syntax:
condition ? exp1 : exp2;
If condition is true then value returned will be exp1, otherwise the value returned will be
exp2.
Bitwise Operators
Bitwise operators are used for manipulation of data at bit level. These operators are used
for testing the bits, or shifting them right or left. Bitwise operators may not be applied to
float or double. A list of different bitwise operators are:
1. Bitwise Logical Operators
(i) Bitwise Logical AND (&)
(ii) Bitwise Logical OR (|)
(iii) Bitwise Logical XOR (^)
2. Bitwise Shift Operators
(i) Bitwise Left shift (<<)
(ii) Bitwise Right shift (>>)
6. Bitwise One’s complement (~)
Bitwise OR Operator
The truth table for the OR operator is:
op1 op2 op1|op2
0 0 0
1 0 1
0 1 1
1 1 1
Special Operators
C language also provides number of special operators which have no counter parts in
other languages.
1. comma operator
2. sizeof operator
3. pointer operators (& and *)
4. member selection operators (. and ->)
Comma Operator
This operator is generally used in the for loop. The expression separated by comma
operator are solved from left to right.
sizeof operator
The sizeof operator works on variables, constants and even on all the data types. It
returns the number of bytes the operand occupies in the memory.
Input means to provide the program with some data to be used in the program and output
means to display data on the screen or write the data to a printer or a file.
Reading, processing, and writing of data are the three essential functions of a computer
program. There are two methods of providing data to the program variable. One method is
to assign values to variables through the assignment statements, and another method is
to use the input function which can read data from a keyboard. C programming language
provides standard library functions to read any given input and display data on the
console.
if Statement
The if statement in C is used to perform the operations based on some specific condition.
The operations specified in if block are executed if and only if the given condition is true.
if ( expression )
{
//code to be executed
}
It allows the computer to evaluate the expression first and then, depending on whether the
value of the expression is true or false.
Entry
True
Condition
False
Simple if statement
The syntax of a simple if statement is
if ( expression )
{
Statements;
}
Stmt;
Entry
True
Condition
Statements
Stmt
Entry
False True
Condition
Statements2 Statements1
Stmt
{
printf("%d is even number", number);
}
else
{
printf("%d is odd number", number);
}
return 0;
}
Output:
enter a number:4
4 is even number
enter a number:5
5 is odd number
When a series of decisions are involved, we may have to use more than one if…else
statement in nested form as shown below:
if ( expression 1 )
{
if ( expression 2 )
{
Statement 1;
}
else
{
Statement 2;
}
}
else
{
Statement 3;
}
Stmt;
If the expression 1 is false, the statement 3 will be executed, otherwise it continues to
perform the second test. If the expression 2 is true, the statement 1 will be evaluated,
otherwise the statement 2 will be evaluated.
Example: Write a program to determine whether the input year is a leap year or not.
#include <stdio.h>
int main()
{
int year;
printf("Enter a year: ");
scanf("%d",&year);
if(year % 100 == 0)
{
if(year % 400 == 0)
printf("\nLeap Year");
else
break;
case '*': printf("%.2f * %.2f = %.2f",n1, n2, n1*n2);
break;
case '/': printf("%.2f / %.2f = %.2f",n1, n2, n1/n2);
break;
default: printf("Sorry!! Operator is not matched");
}
}
Conditional Operator ( ? : )
The C language has an unusual operator, useful for making two-way decisions. This
operator is a combination of ? and :, and takes three operands. This operator is known as
the conditional operator. The syntax of conditional operator is:
exp1 ? exp2 : exp3 ;
The exp1 is evaluated first. If the result is true, exp2 is evaluated otherwise exp3 is
evaluated and its value is returned. For example, the segment
if ( a > b )
max = a;
else
max = b;
can be written as
max = ( a > b ) ? a : b ;
Loops or iterations are used when we want to execute a statement or set of statement
many times. A program loop therefore consists of two segments, one known as the body
of the loop and the other known as the control statement (test condition). The control
statement tests certain conditions and then directs the repeated execution of the
statements contained in the body of the loop.
Depending on the position of the control statement in the loop, a control structure may be
classified either as the entry-controlled loop or as the exit-controlled loop.
Entry Entry
Loop
Body
True
Condition
False
The C language provides for three constructs for performing loop operations. They are:
1. The while statement
2. The do statement
3. The for statement
The do statement
The do is an exit controlled loop. On some occasions it might be necessary to execute the
body of the loop before the test is performed. Such situations can be handled with the help
of the do statement. This takes the form:
do
{
//code to be executed;
} while (condition );
On reaching the do statement, the program proceeds to evaluate the body of the loop
first. At the end of the loop, the condition in the while statement is evaluated. If the
condition is true, the program continues to evaluate the body of the loop again. This
process continues as long as the condition is true.
The for loop is another entry-controlled loop that provides a more concise loop control
structure. The general form of the for loop is:
for ( initialization ; condition ; increment/decrement/update )
{
//Loop Body
}
The execution of the for statement is as follows:
1. Initialization of the control variables is done first, using assignment statements.
2. The value of the control variable is tested using the condition. If the condition is
true, the loop body is executed, otherwise the loop is terminated.
3. After executing loop body, the control variable is incremented or decremented, and
new value of the control variable is again tested.
break: When a break statement is encountered inside a loop, the loop is immediately
exited and the program continues with the statement immediately following the loop.
When the loop are nested, the break would only exit from the loop containing it.
Example: Add only positive numbers, if negative value is entered then jump out from loop.
#include <stdio.h>
int main()
{
int i, n, sum = 0;
for ( i = 1; i <= 5; i++)
{
printf(“\nEnter number: ”);
scanf(“%d”, &n);
if ( n < 0)
break;
sum += n;
}
printf(“\nSum = %d”, sum);
return 0;
}
continue: The continue causes the loop to be continued with the next iteration after
skipping any statements in between.
Example: Add only positive numbers out of 5 inputted numbers.
#include <stdio.h>
int main()
{
int i, n, sum = 0;
for ( i = 1; i <= 5; i++)
{
printf(“\nEnter number: ”);
scanf(“%d”, &n);
if ( n < 0)
continue;
sum += n;
}
printf(“\nSum = %d”, sum);
return 0;
}
C supports the goto statement to branch unconditionally from one point to another in the
program. The goto requires a label in order to identify the place where the branch is to be
made. A label is any valid variable name, and must be followed by a colon. The label is
placed immediately before the statement where the control is to be transferred.
goto label;
….
label: statement;
return Statement
Return jump statement is usually used at the end of a function to end or terminate it with
or without a value. It takes the control from the calling function back to the main function
(main function itself can also have a return).
Nesting of Loops
Nesting of loops, that is, one loop statement within another loop statement, is allowed in
C. For example, two loops can be nested as follows:
#include <stdio.h>
int main()
{
int i, num, fact = 1;
printf(“Enter a number: “);
scanf(“%d”, &num);
for(i = 2; i <=num; i++)
{
fact = fact * i;
}
printf(“\nFactorial of %d = %d”,num, fact);
return 0;
}
1
22
333
4444
#include <stdio.h>
int main()
{
int line, i , j;
printf(“\nEnter number of lines: “);
scanf(“%d”, &line);
for( i = 1; i <= line; i++)
{
printf(“\n”);
for( j = 1; j <= i ; j++)
{
printf(“%d “, i );
}
}
return 0;
}
Array
An array is defined as the collection of similar type of data items stored at contiguous
memory locations. It is simply a grouping of like-type data. Arrays are the derived data type
in C language which can store the primitive type of data such as int, float, char, double etc.
In its simplest form, an array can be used to represent a list of numbers, or a list of names.
Properties of Array
Each element of an array is of same data type and carries the same size.
Array elements are accessed by using an integer index. Array index starts with 0 and
goes till size of array minus 1.
Elements of the array are stored at contiguous memory locations where the first
element is stored at the smallest memory location (base address).
Name of the array is also a constant pointer to the first element of the array.
Elements of the array can be randomly accessed since we can calculate the address
of each element of the array with the given base address and the size of the data
element.
Advantages of Array
Code Optimization: Less code to the access the data.
Ease of traversing: By using the loop, we can retrieve the elements of an array
easily.
Ease of sorting: To sort the elements of the array, we need a few lines of code only.
Random Access: We can access any element randomly using the 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 array_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] ;
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;
The values to the array elements can also be initialized at run time as follows:
for( i = 0; i < 5; i++)
{
scanf(%d”, &list[i] );
}
Example:
#include <stdio.h>
int main()
{
int arr[10], i;
printf(“Enter 10 numbers: “);
for( i = 0; i < 9; i++)
scanf(“%d”, &arr[i]);
printf(“\nElements of an Array are: \n”);
for( i = 0; i < 9; i++)
printf(“%d\t”, arr[i]);
return 0;
}
scanf(“%d”,&arr[i]);
printf(“\nEnter item to be search: ”);
scanf(“%d”,&item);
for( i = 0 ; i < n; i++)
{
if( arr[i] == item)
{
flag = 1;
break;
}
}
if( flag == 1)
printf(“\nitem is present at %d location”, i);
else
printf(“\nitem is not present in the array”);
return 0;
}
Two-Dimensional Array
The 2D array can be defined as an array of arrays. 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 arr_name [rows] [columns];
Example: int table[2][3];
We think of this table as a matrix consisting of two rows and three columns.
Example:
#include <stdio.h>
int main()
{
int i, j;
int arr[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };
printf(“\nArray elements are:\n”);
for ( i =0; i < 3; i++)
{
printf(“\n”);
for (j = 0; j < 3; j++)
{
printf(“%4d”, arr[i][j]);
}//end of inner loop
}//end of outer loop
return 0;
}
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”);
Pointers
A pointer is a variable which stores the address of another variable. 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. The purpose of pointer is to save memory
space and achieve faster execution time.
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.
Example:
#include <stdio.h>
void main()
{
int n = 10;
int *ptr;
ptr = &n;
printf(“Address of n = %p”, &n); //using address of operator of variable n
printf(“\nAddress of n = %p”, ptr); //using pointer
printf(“\nValue of n = %d”, *ptr); //using dereference operator
}
Pointer Arithmetic
There are only a few operations that are allowed to perform on pointers in C language.
The operations are slightly different from the ones that we generally use for mathematical
calculations. The operations are:
Increment/Decrement of a pointer (++ or --)
Addition of integer to a pointer ( + or +=)
Subtraction of integer to a pointer (- or -=)
Subtracting two pointers of the same type
Comparison of two pointers. (p == ptr or p == NULL)
Pointer arithmetic is meaningless unless performed on an array.
Void pointer (void *) is a pointer that points to some data location in storage, which doesn’t
have any specific type. Void refers to the type. Basically the type of data that is points to is
can be any. If we assign address of char data type to void pointer it will become char
pointer, if int data type then int pointer and so on. Any pointer type is convertible to a void
pointer hence it can point to any value.
Example:
#include <stdio.h>
void main()
{
int inum = 10;
float fnum = 2.2;
void* ptr; //void/generic pointer
ptr = &inum;
// (int*)ptr – does type casting of void
//*((int*)ptr) – dereferences the typecasted void pointer variable
printf("\nValue of inum = %d",*((int*)ptr));
ptr = &fnum; //void pointer is now float
printf("\nValue of fnum = %.2f",*((float*)ptr));
}
Output:
Value of inum = 10
Value of fnum = 2.20
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 );
Array of Pointers
An array of pointers would be a collection of addresses. The addresses present in it can
be addresses of isolated variables or addresses of array elements or any other
addresses. For example:
int *ptr[3]; //array of integer pointers
int a = 10, b = 20, c = 30;
Subject Teacher: Bhagirath Singh Chauhan # 9829275869 Page No.: 3
PCE Programming for Problem Solving 1FY3-06/2FY3-06
ptr[0] = &a;
ptr[1] = &b;
ptr[2] = &c;
One important use of pointers is in handling of a table of strings. Consider the following
array of strings:
char names[3][20];
This says that the name is a table containing three names, each with a maximum length
of 20 characters. We know that rarely the individual strings will be of equal length.
Therefore, instead of making each row a fixed number of characters, we can make it a
pointer to a string of varying length. For example,
char *names[3] = { “Bhagirath”, “Vedant”, “Suraj” };
declares names to be an array of three pointers to characters, each pointer pointing to a
particular name.
Disadvantages of Pointers
Pointers are a little complex to understand.
Pointers can lead to various errors such as segmentation faults or can access a
memory location which is not required at all.
If an incorrect value is provided to a pointer, it may cause memory corruption.
Pointers are also responsible for memory leakage.
Pointers are comparatively slower than that of the variables.
Programmers find it very difficult to work with the pointers; therefore it is
programmer’s responsibility to manipulate a pointer carefully.
The process of allocating memory during program execution is called dynamic memory
allocation. Dynamic Memory Allocation is manual allocation and freeing of memory
according to our programming needs.
C provides some functions to achieve these tasks. There are 4 library functions provided
by C defined under <stdlib.h> header file to facilitate dynamic memory allocation in C
programming. They are:
1. malloc()
2. calloc()
3. free()
4. realloc()
malloc() Function
malloc or ‘memory allocation’ function is used to allocate space in memory during
theexecution of the program.
malloc function does not initialize the memory allocated during execution. It carries
garbage value.
malloc function returns null pointer if it couldn't able to allocaterequested amount of
memory.
Syntax:
ptr = (castType*) malloc (size in bytes);
Example: Create a Dynamic array of n elements and print the sum of elements.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int size, i. *ptr, sum = 0;
printf(“\nEnter the size of an array: ”);
scanf(“%d”,&size);
ptr = (int*) malloc (size * sizeof(int) );
if(ptr == NULL)
{
printf(“\nNo memory available”);
exit(0);
}
printf(“\nEnter %d elements:”, size);
for(i =0; i < size ; i++)
{
scanf(“%d”, ptr+i);
sum = sum + *(ptr+i);
}
printf(“\nSum = %d”,sum);
free(ptr);
}
calloc() Function
realloc() Function
realloc function modifies the allocated memory size by malloc and calloc functions to
new size.
If enough space doesn't exist in the memory of the current block to extend, a new
block is allocated for the full size of reallocation, then copies the existing data to the
new block and then frees the old block.
free() Function
Dynamically allocated memory created with either calloc() or malloc() doesn't get
freed on their own.
free() function frees the allocated memory by malloc(), calloc(), realloc() functions.
User-Defined Functions
Function
Library Functions: The standard library functions are built-in functions in C programming.
Library functions are the inbuilt function in C that are grouped and placed at a common
place called the library. Such functions are used to perform some specific operations. For
example, printf() is a library function used to print on the console. The library functions are
created by the designers of compilers. All C standard library functions are defined inside
the different header files saved with the extension .h. We need to include these header
files in our program to make use of the library functions defined in such header files.
User-Defined Functions: A User-defined functions on the other hand, are those functions
which are defined by the user at the time of writing program. These functions are made for
code reusability and for saving time and space.
Modular Programming
In order to make use of a user-defined function, we need to establish three elements that
are related to functions.
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
List of parameters contains variables name along with their data types. These arguments
are kind of inputs for the function.
Return type can be of any data type such as char, int, short, float, double etc. A C function
may or may not return a value from the function. If you don’t have to return any value from
the function, use void for the return type.
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.
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 or Call by Value
2. Pass By Address/Pointer/Reference or Call by Reference
The value of the actual parameters is copied into the formal parameters.
We cannot modify the value of the actual parameter by the formal parameter.
In call by value, different memory is allocated for actual and formal parameters
since the value of the actual parameter is copied into the formal parameter.
The actual parameter is the argument which is used in the function call whereas
formal parameter is the argument which is used in the function definition.
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.
Recursion
Any function which calls itself is called recursive function, and such function calls are called
recursive calls. 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 ) );
}
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.
There are four storage classes in C:
1. Automatic storage class
2. Register storage class
3. Static storage class
4. External storage class
The visibility of the static global variable is limited to the file in which it has
declared.
The keyword used to define static variable is static.
Example:
#include <stdio.h>
void print(void);
int main()
{
int i;
for( i = 1; i <= 5; i++)
print();
return 0;
}
void print(void)
{
static int n = 1;
printf(“%4d”,n);
n++;
}
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.
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. There are two ways to
declare structure variable:
1. By struct keyword within main() function
2. By declaring a variable at the time of defining the structure.
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
We use structures to describe the format of a number of related variables. We may declare
an array of structures, each element of the array representing a structure variable.
struct record student[50];
student[0].rollno = 101;
strcpy ( student[0].name, “Bhagirath”);
defines an array called student, that consists of 50 elements. Each element is defined to
be of the type struct record and assign values to the members.
Example:
#include <stdio.h>
struct student
{
int rollno;
char name[20];
};
int main()
{
struct student stu[5];
int i;
for( i = 0; i < 5; i++)
{
printf(“\nEnter roll Number: “);
scanf(“%d”,&stu[i].rollno);
printf(“\nEnter name: “);
gets(stu[i].name);
}
for( i = 0; i < 5; i++)
{
printf(“\nRoll Number: %d”, stu[i].rollno);
printf(“\nName: %s“, stu[i].name);
}
return 0;
}
Structure Padding
Structure padding is a concept in C that adds the one or more empty bytes between the
memory addresses to align the data in memory. For example:
struct student
{
char ch1; //1 byte
char ch2; //1 byte
int num; //4 byte
} obj;
int main()
{
printf(“\nThe size of obj = %d bytes”, sizeof(obj) );
return 0;
}
Output:
The size of obj = 8 bytes //due to concept of structure padding.
Example:
#include <stdio.h>
#pragma pack(1)
struct number
{
int num;
char ch;
double d;
};
int main()
{
struct number obj;
printf("\nSize of obj = %d bytes",sizeof(obj));
return 0;
}
Output:
Size of obj = 13 bytes
Union
Like structures, union is a user defined data type. In union, all members share the same
memory 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.
Example: To illustrate difference between structure and union.
#include <stdio.h>
struct snumber
{
int num;
char ch;
double d;
}sobj;
union unumber
{
int num;
char ch;
double d;
}uobj;
int main()
{
printf("\nSize of sobj = %d bytes",sizeof(sobj));
printf("\nSize of uobj = %d bytes",sizeof(uobj));
return 0;
}
Output:
Size of sobj = 16 bytes
Size of uobj = 8 bytes
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.
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.
File handling enables us to create, update, read, and delete the files stored on the local
file system through our C program. The following operations can be performed on a file:
Creation of the new file
Opening an existing file
Reading from the file
Writing to the file
Deleting the file
To perform file operations in C, the important file handling functions that are available in
the C library are:
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 = fopen (“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:
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”);
Example: A program to print the file contents in uppercase.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
FILE *fp;
char ch;
fp = fopen("file.txt","r");
if(fp == NULL)
{
puts("File opening error.");
exit(1);
}
do
{
ch = fgetc(fp);
putchar(toupper(ch));
} while(ch != EOF);
return 0;
}
Example: A program to copy the contents of a file and write it in another file. (file
copy program).
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp1, *fp2;
char ch;
fp1 = fopen("file.txt", "r");
if (fp1 == NULL)
{
puts("File opening error.");
exit(1);
}
fp2 = fopen("output.txt", "w");
if (fp2 == NULL)
{
puts("File opening error.");
exit(1);
}
do
{
ch = fgetc(fp1);
fputc(ch, fp2);
} while (ch != EOF);
_fcloseall();
printf("\nThe contents of output.txt:\n");
fp1 = fopen("output.txt", "r");
do
{
ch = fgetc(fp1);
putchar(ch);
} while (ch != EOF);
fclose(fp1);
return 0;
}
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
Example:
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen("file3.c","r+");
fseek(fp,-1,2);
printf("\nTotal Characters in File: %d",ftell(fp));
printf("\nLast character is: %c",fgetc(fp));
fseek(fp,0,0);
printf("\nFirst character is: %c",fgetc(fp));
fseek(fp,4,1);
printf("\nSixth character is: %c",fgetc(fp));
rewind(fp);
printf("\nAgain! First character is: %c",fgetc(fp));
fclose (fp);
return 0;
}
The arguments passed from command line are called command line arguments. These
arguments are handled by main() function. Command line argument is a parameter
supplied to a program when the program is invoked. This parameter can be of any type.
In fact main can take two arguments called argc and argv and the information contained
in the command line is passed on to the program through these arguments, when main is
called up by the system.
The variable argc is an argument counter that counts the number of arguments on the
command line. The argv is an argument vector and represents an array of character
pointers that point to the command line arguments. In order to access the command line
arguments, we must declare the main function and its parameters as follows:
main ( int argc, char *argv[ ] )
{
…..
…..
}
The first parameter in the command line is always the program name and therefore
argv[0] always represents the program name.
Example:
#include <stdio.h>
void main(int argc, char *args[]) {
int i;
for(i = 0; i < argc; i++)
{
printf("\nArgument args[%d] is: %s",i,args[i]);
}
}
Example: Add two numbers using command line arguments.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char*args[])
{
int n1, n2, sum;
if(argc != 3)
{
printf("Arguments must be: \"programName value1 value2\"");
exit(1);
}
n1 = atoi(args[1]);
n2 = atoi(args[2]);
sum = n1 + n2;
printf("\nSum = %d",sum);
return 0;
}