Unit 2 Notes
Unit 2 Notes
Unit 2 Notes
Functions: declaration, definition & scope, recursion, call by value, call by reference.
Introduction
A function in C is a small “sub-program” that performs a particular task, and supports the
concept of modular programming design techniques. In modular programming the various
tasks that your overall program must accomplish are assigned to individual functions and the
main program basically calls these functions in a certain order.
Definition
A function is a self contained block of executable code that can be called from any other
function.
Arrow Means
→ Calling function with data (argument) if any
← Return to the next statement or execution with data if any
1. Don’t have to repeat the same block of code many times in your code. Make that
code block a function and call it when needed.
2. Easy to debug. Get one function working well then move on to the others.
3. Easy to modify and expand. Just add more functions to extend program capability.
4. For a large programming project, you will code only a small fraction of the
program.
1. Standard functions:
All standard functions, such as sqrt() , pow() , log() , sin() etc. are porvided in the library of the
functions. The standard functions are also called library functions or built in functions.
Predefined Functions are already created. Eg: printf() , scanf() , getch() , clrscr() etc.
User defined Functions which are created by the User according to his need.
fun. type
function fun.
header body
fun. name
fun type local
declaration
parameter
fun. name list
fun. stms.
formal terminatin
parameters returm stmt. g
semicolon
Important definitions:
1. Function definition:
a. Is also called as function implementation
b. Is an independent program module that is specifically written to implement the
requirements of the function.
2. Function call:
a. In order to use a function, we need to invoke it at a regular place in the program.
This is known as function call.
3. Calling function:
a. the program that calls the function is referred to as the calling function.
4. Function declaration/ prototype:
a. The calling program should declare any function that is to be used later in the
program. This is known as function declaration or function prototype.
1. Function definition
• function name
function • function return type
header • list of parameters
Function Body
{
// Local declarations
// statements
The function type specifies the type of value (like float or double) that the function is expected to
return to the program calling the function.
If the return type is not explicitly specified, C will assume that it is an integer type.
If the function is not returning anything, then we need to specify the return type as void.
The function name is any valid C identifier and therefore must follow the same rules of
formation as the other variable names in C.
The parameter list declares the variables that will receive the data sent by the calling program.
They serve as an input data to the function to carry out the specified task.
Since, they represent actual input values; they are often referred to as formal parameters.
[Parameters written at the time of function definition are known as formal parameters.]
For example
parameters arguments
1. The names given in the function 1. The values supplied in the function call are
definition are called Parameters called Arguments.
2. An object declared in a function definition 2.An expression in the comma separated list in a
or declaration. function call.
For example
#include <stdio.h>
void main(){
int num1,num2,sum;
scanf("%d %d",&num1,&num2);
printf("sum=%d",sum);
getch();
int add;
add=a+b;
The function body contains the declaration and statements necessary for performing the required
task.
If a function does not return any value, we can omit the return statement. In this case, return type
should be specified as void.
For example
Syntax :
1. Return;
2. Return(expression )
For example
Int p;
P=x*y;
Return(p); //
}
Function calls
A function can be called by simply using the name followed by a list of actual parameters, if any,
enclosed in parentheses.
It consists of 4 parts
1. Function type
2. Function name
3. Parameter list
4. Terminating semicolon [ only difference between declaration and definition syntax]
Syntax:
Advantages of prototype
1. It tells about the return type
2. It tells how many parameters there are, and what their types are.
3. If this prototype is provided, the compiler will catch the error in main (). If it is
omitted, then the error may go unnoticed.
Note:
1. If function definition is written after main then and then only we write prototype
declaration in global declaration section
2. If function definition is written above the main function then ,no need to write prototype
declaration
#include<stdio.h>
void displayMessage() {
printf("www.c4learn.com");
}
void main() {
displayMessage();
}
//Prototype Declaration
void displayMessage();
void main() {
displayMessage();
}
void displayMessage() {
printf("www.c4learn.com");
}
When we place the declaration above all the functions, the prototype is referred to as global
prototype.
When we place the declaration inside the main functions, the prototype is referred to as local
prototype.
For example
#include <stdio.h>
Void main()
Int n, sq;
Scanf (“%d”,&n);
}
Int square(int no) // passing of argument
Result= no * no;
#include <stdio.h>
int add(int a, int b); //function prototype(declaration)
int main(){
int num1,num2,sum;
printf("Enters two number to add\n");
scanf("%d %d",&num1,&num2);
sum=add(num1,num2); //function call
printf("sum=%d",sum);
return 0;
}
int add(int a,int b) //function declarator
{
/* Start of function definition. */
int add;
add=a+b;
return add; //return statement of function
/* End of function definition. */
}
e
lu
e
va
lu
va
rn
rn
tu
tu
re
re
o
No
N
1 2
No arguments 3 4
Arguments
The called Function does not receive any data from the calling Function and it does not return
any data back to the calling Function. Hence, there is no data transfer between the calling
Function and called Function.
Category 2: function with no arguments & with return value
The called Function does not receive any data from the calling Function but does send some
value to the calling function, then that the function falls in this category.
#include<stdio.h>
#include<conio.h>
void main()
{
float sum;
float total();
clrscr();
sum = total();
printf(" Sum = %f\n" , sum);
}
float total()
{
float a, b;
a = 5.0 ;
b = 15.0 ;
return(a+b);
}
Output:
Sum = 20.000000
Here the called Function receives the data from the calling function but the called function does
not return any value back to the calling function.
Types of arguments
For example
main()
For example
#include<stdio,h>
Main()
{
Int dat(int,int,int);
Int d,m,y;
Scanf (%d%d%d”,&d,&m,&y);
Dat(d,m,y);
Return 0;
Printf(“date = %d / %d / %d”,x,y,z);
In this category, two way communications takes place between the calling and called function i.e
a function returns a value and also arguments are passed to it.
For example
#include<stdio.h>
float calculate_area(int);
int main()
{
int radius;
float area;
printf("\nEnter the radius of the circle : ");
scanf("%d",&radius);
area = calculate_area(radius);
printf("\nArea of Circle : %f ",area);
return(0);
}
float calculate_area(int radius)
{
float areaOfCircle;
areaOfCircle = 3.14 * radius * radius;
return(areaOfCircle);
}
Output:
For example
#include <stdio.h>
Void display(int);
Void main()
Int i=20;
display(i) //20
}
display(i)
int k =35;
Printf (“\n %d”,j); //20
Printf (“\n %d”,k); //35
}
Output: j=20 k=35
In the above program, it is necessary to pass the value of the variable “i” to the display(), because
by default, the scope of a variable is local to the function in which it is defined.
Similarly , the variable k is local to the display() and hence it is not available to main().
Hence, when function is called by value method, it does not affect the actual arguments.
Changes made in the formal arguments are local to the block of the called function. Once control
returns back to the calling function, the changes made vanish.
Example 1
#include<stdio.h>
#include<conio.h>
Void display(int);
Void main()
Int i=7;
Clrscr();
I=i+3;
Display(i);
Printf (\n value of i in main() after calling display=%d”.i);
Getch();
Void display(int k)
Int k;
K=k+3;
Example 2
#include<stdio.h>
int main() {
int num1=50,num2=70;
interchange(num1,num2);
printf("\nNumber 1 : %d",num1);
printf("\nNumber 2 : %d",num2);
return(0);
}
Output :
Number 1 : 50
Number 2 : 70
2. Call by Reference/Pointer/Address:
#include<stdio.h>
int main() {
int num1=50,num2=70;
interchange(&num1,&num2);
printf("\nNumber 1 : %d",num1);
printf("\nNumber 2 : %d",num2);
return(0);
}
Output :
Number 1 : 70
Number 2 : 50
1. While passing parameter using call by address scheme, we are passing the actual
address of the variable to the called function.
2. Any updates made inside the called function will modify the original copy since we are
directly modifying the content of the exact memory location.
Pointer
Define pointers
A pointer is a special variable in C language meant just to store address of any other variable or
function. Pointer variables unlike ordinary variables cannot be operated with all the arithmetic
operations such as '*','%' operators.
It follows a special arithmetic called as pointer arithmetic.
int *ap;
int a = 5;
In the above two statements an integer a was declared and initialized to 5. A pointer to an integer
with name ap was declared.
ap=&a;
This operation would initialize the declared pointer to int. The pointer ap is now said to point to
a.
Similarly
Operations on a pointer:
· Dereferencing operator ' * ': This operator gives the value at the address pointed by the
pointer . For example after the above C statements if we give
printf("%d",*ap);
Disadvantages of pointers:
1. If sufficient memory is not available during runtime for the storage of pointers, the
program may crash.
#include <stdio.h>
void main ()
{
int var1;
char var2[10];
getch();
}
When the above code is compiled and executed, it produces result something as follows:
Next y gets assigned to the contents of ip. In this example ip currently points to memory location
100 -- the location of x. So y gets assigned to the values of x -- which is 1.
We have already seen that C is not too fussy about assigning values of different type. Thus it is
perfectly legal (although not all that common) to assign the current value of ip to x. The value of
ip at this instant is 100.
Void main( )
{
int i = 3 ;
int *j ;
j = &i ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nAddress of i = %u", j ) ;
printf ( "\nAddress of j = %u", &j ) ;
printf ( "\nValue of j = %u", j ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", *( &i ) ) ;
printf ( "\nValue of i = %d", *j ) ;
getch();
}
Address of i = 65524
Address of i = 65524
Address of j = 65522
Value of j = 65524
Value of i = 3
Value of i = 3
Value of i = 3
Void main( )
{
int i = 3, *j, **k ;
j = &i ;
k = &j ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nAddress of i = %u", j ) ;
printf ( "\nAddress of i = %u", *k ) ;
printf ( "\nAddress of j = %u", &j ) ;
printf ( "\nAddress of j = %u", k ) ;
printf ( "\nAddress of k = %u", &k ) ;
printf ( "\nValue of j = %u", j ) ;
printf ( "\nValue of k = %u", k ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", * ( &i ) ) ;
printf ( "\nValue of i = %d", *j ) ;
printf ( "\nValue of i = %d", **k ) ;
}
The output of the above program would be:
Address of i = 65524
Address of i = 65524
Address of i = 65524
Address of j = 65522
Address of j = 65522
Address of k = 65520
Value of j = 65524
Value of k = 65522
Value of i = 3
Value of i = 3
Value of i = 3
Value of i = 3
C Pointer to Pointer
In c language, a pointer can point to the address of another pointer which points to the address of
a value. Let's understand it by the diagram given below:
int **p2;
C pointer to pointer
Example 1
Let‟s suppose we have a pointer „p1′ that points to yet another pointer „p2′ that points to a
character „c‟. In memory, the three variables can be visualized as :
So we can see that in memory, pointer p1 holds the address of pointer p2. Pointer p2 holds the
address of character „c‟.
So „p2′ is pointer to character „c‟, while „p1′ is pointer to „p2′ or we can also say that „p2′ is a
pointer to pointer to character „c‟.
So we see that „p1′ is a double pointer (ie pointer to a pointer to a character) and hence the two
*s in declaration.
Now,
I think that should pretty much clear the concept, lets take a small example :
#include<stdio.h>
int main(void)
{
char **ptr = NULL;
char *p = NULL;
char c = 'd';
p = &c;
ptr = &p;
printf("\n c = [%c]\n",c);
printf("\n *p = [%c]\n",*p);
printf("\n **ptr = [%c]\n",**ptr);
return 0;
}
$ ./doubleptr
c = [d]
*p = [d]
**ptr = [d]
Example 2
Let's see an example where one pointer points to the address of another pointer.
As you can see in the above figure, p2 contains the address of p (fff2) and p contains the address
of number variable (fff4).
#include <stdio.h>
#include <conio.h>
void main(){
int number=50;
int *p;//pointer to int
int **p2;//pointer to pointer
clrscr();
p=&number;//stores the address of number variable
p2=&p;
getch();
}
Output
Address of number variable is fff4
Address of p variable is fff4
Value of *p variable is 50
Address of p2 variable is fff2
Value of **p variable is 50
The values of actual arguments are The addresses of actual arguments are
Substitution substituted in formal arguments which substituted in formal arguments which are
are ordinary variables. pointer variable.
Recursive function must have at least one terminating condition that can
be satisfied.
Example 1
Factorial
#include<stdio.h>
long factorial(int);
void main()
{
int n;
long f;
printf("Enter an integer to find factorial\n");
scanf("%d", &n);
if (n < 0)
printf("Negative integers are not allowed.\n");
else
{
f = factorial(n);
printf("%d! = %ld\n", n, f);
}
Getch();
}
long factorial(int n)
{
if (n == 0)
return 1;
else
return(n * factorial(n-1));
}
Termination test Terminates when a base case is recognized Terminates when the loop
continuation condition fails.
Condition for Infinite recursion occurs if the recursion step does Infinite loop occurs with iteration
infinite execution not reduce the problem in a manner that if the loop continuation test never
converges on the base case. becomes false.
Efficiency Recursive solutions are often less efficient in More efficient.
terms of both time and space.
UNIT 2- Part 2: Storage classes
The scope of a variable determines the region of the program in which it is known. An
identifier's "visibility" determines the portions of the program in which it can be
referenced—its "scope." An identifier is visible only in portions of a program
encompassed by its "scope," which may be limited to the file, function or block in which
it appears.
File scope: The variables and functions with file scope appear outside any block or list
of parameters and is accessible from any place in the translation unit after its
declaration.
Identifier names with file scope are often called "global" or "external." The scope of a
global identifier begins at the point of its definition or declaration and terminates at the
end of the translation unit. A function has file scope.
Function scope: A label is the only kind of identifier that has function scope. A label is
declared implicitly by its use in a statement. Label names must be unique within a
function however a label having the same name in two different functions is allowed.
Block scope: The variables with block scope appear inside a block or within the list of
formal parameter declarations in a function definition. It is visible only from the point of
its declaration or definition to the end of the block containing its declaration or definition.
Its scope is limited to that block and to any blocks nested in that block and ends at the
curly brace that closes the associated block. Such identifiers are sometimes called
"local variables."
Scope of variable:
Scope of variable i.e. in which function the value of the variable would be available.
The life of the variable i.e. how long would the variable exists.
Four storage classes in C:
-Storage: Memory
-Default initial value: Garbage value
-Scope: Local to the block in which defined
-Life: till the control remains within the block in which defined.
Example
1 #include<stdio.h>
2 void increment(void);
3
4 int main()
5 {
6 increment();
7 increment();
8 increment();
9 increment();
10 }
11
12 void increment(void)
13 {
14 auto int i = 0 ;
15 printf ( "%d \n", i ) ;
16 i++;
17 }
Output:
0
0
0
0
b. Register storage class:
The features of variables are as follows
Example
All looping program where a variable are frequently used, declare variable as register.
OUTPUT:-
10 8 6 4 2 0
-Storage: Memory
-Default initial value: Zero
-Scope: Local to the block in which defined
-Life: value of variable persists between different function calls.
Example 1
main()
{
add();
add();
add()
printf(“\n%d”,i);
i=i+1;
Output:
10
11
Example 2
1 //C static example
2 #include<stdio.h>
3 void increment(void);
4
5 int main()
6 {
7 increment();
8 increment();
9 increment();
10 increment();
11 }
12
13 void increment(void)
14 {
15 static int i = 0 ;
16 printf ( "%d \n", i ) ;
17 i++;
18 }
Output:
0
1
2
3
-Storage: Memory
-Default initial value: Zero
-Scope: global
-Life: As long as program execution does not come to an end.
Example
1 #include<stdio.h>
2 int x = 10 ;
3 int main( )
4 {
5 extern int y ;
6 printf ( "The value of x is %d \n", x ) ;
7 printf ( "The value of y is %d",y ) ;
8 }
9 int y = 50 ;
Output:
The value of x is 10
The value of y is 50
Summary
The C Preprocessor
Preprocessor directives are actually the instructions to the compiler itself. They are not
translated but are operated directly by the compiler. Note that preprocessor statements begin with
a #symbol, and are NOT terminated by a semicolon. Traditionally, preprocessor statements are
listed at the beginning of the source file. They are also termed as macros.
In simplistic terms, a C Preprocessor is just a text substitution tool and they instruct compiler to
do required pre-processing before actual compilation.
1. Inclusion of header files. These are files of declarations that can be substituted into your
program.
2. Macro expansion. We can define macros, which are abbreviations for arbitrary
fragments of C code, and then the C preprocessor will replace the macros with their
definitions throughout the program.
Advantages of preprocessor:
Example:
#include<stdio.h> #include<stdio.h>
#define TEN 10 void main()
void main() {
{ int a = 10;
int a = 10; if (a == 10)
if (a == TEN) {
{ printf("The value of a is 10");
printf("The value of a is 10"); }
} }
}
If we run the above example, in both cases we will get the output as "The value of a is 10".
The above explained macro is called as „Simple macro‟. There is another form of macro called
„Macros with Arguments‟.
Example:
Before preprocessing After preprocessing
#include<stdio.h> #include<stdio.h>
#define AREA (3.14 * a * a) void main()
void main() {
{ int ar = 3.14 * 10 * 10;
int ar = AREA(10); printf("Area = %f", ar);
printf("Area = %f", ar); }
}
If we run the above example, we will get the output as “AREA = 314.000000”.
In the above example, we have used macros with arguments. As we learnt, before compilation
process the Source code goes through preprocessing process. During preprocessing, the program
is scanned from top to bottom. Every occurrence of AREA(10) in the source code is replaced by
(3.14 * 10 * 10).
Predefined Macros
ANSI C defines a number of macros. Although each one is available for use in programming, the
predefined macros should not be directly modified.
Macro Description
Example:
#include <stdio.h>
main()
{
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
}
When the above code in a file test.c is compiled and executed, it produces the following result:
File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
Explanation:
The above program uses 5 macros in printf() statement.the program displays program file name,
system date, time, total lines of the program.
UNIT 2 PART 3: ARRAYS:
Arrays, pointers, array & pointer relationship, pointer arithmetic, dynamic memory allocation,
pointer to arrays, array of pointers, pointers to functions, array of pointers to functions
Arrays
An array is a container object that holds a fixed number of values of a single type. The length of
an array is established when the array is created. After creation, its length is fixed.
An array is a sequence of data item of homogeneous value (same type). We cannot have an array
of 10 indices storing 5 int and 5 float values.
Characteristics of array
1. An array is a collection of similar elements.
2. The first index of an array is zero, so the last element is 1 less than the size of array.
3. An array is also known as subscripted variable.
4. Before using an array, its type & dimension must be declared.
5. All the elements of an array share the same name; and they are distinguished from one
another with the help of an element number.
6. However big an array, its elements are always stored in contiguous memory locations.
Array Application
1.
Limitations of Array
1. Static Data
1. Deletion is not easy because the elements are stored in contiguous memory
location.
2. Like insertion operation, we have to delete element from the array and after
deletion empty space will be created and thus we need to fill the space by moving
elements up in the array.
5. Bound Checking
1. If we specify the size of array as „N‟ then we can access elements upto „N-1′ but
in C if we try to access elements after „N-1′ i.e Nth element or N+1th element
then we does not get any error message.
2. Process of Checking the extreme limit of array is called Bound Checking and C
does not perform Bound Checking.
3. If the array range exceeds then we will get garbage value as result.
6. Shortage of Memory
1. Array is Static data structure. Memory can be allocated at compile time only Thus
if after executing program we need more space for storing additional information
then we cannot allocate additional space at run time.
2. Shortage of Memory , if we don‟t know the size of memory in advance
Characteristics
1. Single or One Dimensional array is used to represent and store data in a linear form.
Syntax :
<data-type> <array_name> [size];
Example of Single Dimensional Array :
float x[8] = {16.0, 12.0, 6.0, 8.0, 2.5, 12.0, 14.0, -54.5}
Accessing Array Elements
An element is accessed by indexing the array name.
Arrayname[index]
For example:
The above statement will take 10th element from the array balance and assign the value to salary
variable.
#include <stdio.h>
void main ()
{
int count[ 10 ]; /* n is an array of 10 integers */
int i ,j, k=0;
getch();
}
When the above code is compiled and executed, it produces the following result:
Element[0] = 0
Element[1] = 1
Element[2] = 2
Element[3] = 3
Element[4] = 4
Element[5] = 5
Element[6] = 6
Element[7] = 7
Element[8] = 8
Element[9] = 9
When an array is declared, compiler allocates sufficient amount of memory to contain all the
elements of the array. Base address which gives location of the first element is also allocated by
the compiler.
int arr[5]={ 1, 2, 3, 4, 5 };
Assuming that the base address of arr is 1000 and each integer requires two byte, the five
elements will be stored as follows
Here variable arr will give the base address, which is a constant pointer pointing to the element,
arr[0]. Therefore arr is containing the address of arr[0] i.e 1000.
int *p;
p = arr;
or
p = &arr[0]; //both the statements are equivalent.
Now we can access every element of array arr using p++ to move from one element to another.
NOTE : You cannot decrement a pointer once incremented. p-- won't work.
Pointer Arithmetic in C
In C pointer holds address of a value, so there can be arithmetic operations on the pointer
variable. Following arithmetic operations are possible on pointer in C language:
Increment
Decrement
Addition
Subtraction
Comparison
Incrementing Pointer in C
Increment operation depends on the data type of the pointer variable. The formula of
incrementing pointer is given below:
32 bit
64 bit
1. #include <stdio.h>
2. void main(){
3. int number=50;
4. int *p;//pointer to int
5. p=&number;//stores the address of number variable
6.
7. printf("Address of p variable is %u \n",p);
8. p=p+1;
9. printf("After increment: Address of p variable is %u \n",p);
10. }
Output
Address of p variable is 3214864300
After increment: Address of p variable is 3214864304
Decrementing Pointer in C
Like increment, we can decrement a pointer variable. The formula of decrementing pointer is
given below:
32 bit
64 bit
1. #include <stdio.h>
2. void main(){
3. int number=50;
4. int *p;//pointer to int
5. p=&number;//stores the address of number variable
6.
7. printf("Address of p variable is %u \n",p);
8. p=p-1;
9. printf("After decrement: Address of p variable is %u \n",p);
10. }
Output
Address of p variable is 3214864300
After decrement: Address of p variable is 3214864296
C Pointer Addition
We can add a value to the pointer variable. The formula of adding value to pointer is given
below:
32 bit
64 bit
Let's see the example of adding value to pointer variable on 64 bit OS.
1. #include <stdio.h>
2. void main(){
3. int number=50;
4. int *p;//pointer to int
5. p=&number;//stores the address of number variable
6.
7. printf("Address of p variable is %u \n",p);
8. p=p+3; //adding 3 to pointer variable
9. printf("After adding 3: Address of p variable is %u \n",p);
10. }
Output
Address of p variable is 3214864300
After adding 3: Address of p variable is 3214864312
As you can see, address of p is 3214864300. But after adding 3 with p variable, it is 3214864312
i.e. 4*3=12 increment. Since we are using 64 bit OS, it increments 12. But if we were using 32
bit OS, it were incrementing to 6 only i.e. 2*3=6. As integer value occupies 2 byte memory in 32
bit OS.
C Pointer Subtraction
Like pointer addition, we can subtract a value from the pointer variable. The formula of
subtracting value from pointer variable is given below:
64 bit
Let's see the example of subtracting value from pointer variable on 64 bit OS.
1. #include <stdio.h>
2. void main(){
3. int number=50;
4. int *p;//pointer to int
5. p=&number;//stores the address of number variable
6.
7. printf("Address of p variable is %u \n",p);
8. p=p-3; //subtracting 3 from pointer variable
9. printf("After subtracting 3: Address of p variable is %u \n",p);
10. }
Output
Address of p variable is 3214864300
After subtracting 3: Address of p variable is 3214864288
You can see after subtracting 3 from pointer variable, it is 12 (4*3) less than the previous address
value.
Pointer to Array
As studied above, we can use a pointer to point to an Array, and then we can use that pointer to
access the array. Lets have an example,
int i;
int a[5] = {1, 2, 3, 4, 5};
int *p = a; // same as int*p = &a[0]
for (i=0; i<5; i++)
{
printf("%d", *p);
p++;
}
In the above program, the pointer *p will print all the values stored in the array one by one. We
can also use the Base address (a in above case) to act as pointer and print all the values.
1. array subscripting
2. pointer offset with the array name as a pointer
3. pointer subscripting
4. pointer / offset with a pointer
int *bptr=&b
Array of Pointers
Just like array of integers or characters, there can be array of pointers too.
<type> *<name>[<number-of-elements];
For example :
char *ptr[3];
#include<stdio.h>
int main(void)
{
char *p1 = "Himanshu";
char *p2 = "Arora";
char *p3 = "India";
char *arr[3];
arr[0] = p1;
arr[1] = p2;
arr[2] = p3;
In the above code, we took three pointers pointing to three strings. Then we declared an array
that can contain three pointers. We assigned the pointers „p1′, „p2′ and „p3′ to the 0,1 and 2 index
of array. Let‟s see the output :
$ ./arrayofptr
p1 = [Himanshu]
p2 = [Arora]
p3 = [India]
arr[0] = [Himanshu]
arr[1] = [Arora]
arr[2] = [India]
Pointers to functions
Every function defined in C language has a base address attached to it. This base address acts as
an entering point into that function. This address can be stored in a pointer known as a function
pointer.
For example :
The above line declares a function pointer „fptr‟ that can point to a function whose return type is
„void‟ and takes two integers as arguments.
#include<stdio.h>
func(2,3);
fptr(12,13);
getch();
}
In the above example, we defined a function „func‟ that takes two integers as inputs and returns
an integer. In the main() function, we declare a function pointer „fptr‟ and then assign value to it.
Note that, name of the function can be treated as starting address of the function so we can assign
the address of function to function pointer using function‟s name. Lets see the output :
$ ./fptr
a = 2
b = 3
a = 2
b = 3
So from the output we see that calling the function through function pointer produces the same
output as calling the function from its name.
Memory allocation
The process of allocating memory during program execution is called dynamic memory
allocation.
Dynamic memory allocation functions in C:
1. malloc()
2. calloc()
3. realloc()
4. free()
1. malloc() function in C:
malloc () function is used to allocate space in memory during the execution of the
program.
malloc () does not initialize the memory allocated during execution. It carries garbage
value.
malloc () function returns null pointer if it couldn‟t able to allocate requested amount of
memory.
int main()
{
char *mem_allocation;
/* memory is allocated dynamically */
mem_allocation = malloc( 20 * sizeof(char) );
if( mem_allocation== NULL )
{
printf("Couldn't able to allocate requested memory\n");
}
else
{
strcpy( mem_allocation,"fresh2refresh.com");
}
printf("Dynamically allocated memory content : " \
"%s\n", mem_allocation );
free(mem_allocation);
}
Output:
Dynamically allocated memory content : fresh2refresh.com
2. calloc() function in C:
calloc () function is also like malloc () function. But calloc () initializes the allocated
memory to zero. But, malloc() doesn‟t.
int main()
{
char *mem_allocation;
/* memory is allocated dynamically */
mem_allocation = calloc( 20, sizeof(char) );
if( mem_allocation== NULL )
{
printf("Couldn't able to allocate requested memory\n");
}
else
{
strcpy( mem_allocation,"fresh2refresh.com");
}
printf("Dynamically allocated memory content : " \
"%s\n", mem_allocation );
free(mem_allocation);
}
Output:
Dynamically allocated memory content : fresh2refresh.com
3. realloc() function in C:
realloc () function modifies the allocated memory size by malloc () and calloc ()
functions to new size.
If enough space doesn‟t exist in memory of current block to extend, new block is
allocated for the full size of reallocation, then copies the existing data to new block and
then frees the old block.
4. free() function in C:
free () function frees the allocated memory by malloc (), calloc (), realloc () functions and
returns the memory to the system.
int main()
{
char *mem_allocation;
/* memory is allocated dynamically */
mem_allocation = malloc( 20 * sizeof(char) );
if( mem_allocation == NULL )
{
printf("Couldn't able to allocate requested memory\n");
}
else
{
strcpy( mem_allocation,"fresh2refresh.com");
}
printf("Dynamically allocated memory content : " \
"%s\n", mem_allocation );
mem_allocation=realloc(mem_allocation,100*sizeof(char));
if( mem_allocation == NULL )
{
printf("Couldn't able to allocate requested memory\n");
}
else
{
strcpy( mem_allocation,"space is extended upto " \
"100 characters");
}
printf("Resized memory : %s\n", mem_allocation );
free(mem_allocation);
}
Output:
Dynamically allocated memory content : fresh2refresh.com
Resized memory : space is extended upto 100 characters
malloc () doesn‟t initializes the allocated calloc () initializes the allocated memory to
3
memory. It contains garbage values zero
#define
The #define directive can be used to set up symbolic replacements in the source. As with all
preprocessor operations, #define is extremely unintelligent -- it just does textual replacement
without understanding. #define statements are used as a crude way of establishing symbolic
constants.
Example:
Later code can use the symbols MAX or SEVEN_WORDS which will be replaced by the text to
the right of each symbol in its #define.
SUMMARY OF #define
The "#include" directive brings in text from different files during compilation. #include is a very
unintelligent and unstructured -- it just pastes in the text from the given file and continues
compiling. The #include directive is used in the .h/.c file convention below which is used to
satisfy the various constraints necessary to get prototypes correct.
#include "c.h" // refers to a "user" c.h file in the originating directory
for the compile
Int display();
display();
{
Preprocessor Operators
Printf(“\n Coming from bca.c”);
#include<stdio.h>
#include<conio.h>
Void main()
clrscr();
display();
getch();
Stringize (#)
The stringize or number-sign operator ('#'), when used within a macro definition, converts a
macro parameter into a string constant. This operator may be used only in a macro that has a
specified argument or parameter list.
For example:
#include <stdio.h>
void main()
{
clrscr();
say(HELLO);
getch();
}
When the above code is compiled and executed, it produces the following result:
Explanation
In the above program, after conversion the statement say (HELLO) is treated as
printf (“HELLO”). It is not essential to enclose the text in quotation marks in the stringizing
operator.
Token Pasting (##)
The token-pasting operator (##) within a macro definition combines two arguments. It permits
two separate tokens in the macro definition to be joined into a single token.
For example:
#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
void main()
{
int token34 = 40;
tokenpaster(34);
getch();
}
When the above code is compiled and executed, it produces the following result:
How it happened, because this example results in the following actual output from the
preprocessor:
This example shows the concatenation of token##n into token34 and here we have used both
stringizing and token-pasting.
Conditional Compilation
1. #if
2. #ifdef
3. #ifndef
Optionally, an alternative block of text can be set aside with one of two directives:
1. #else
2. #elif
The end of the block or alternative block is marked by the #endif directive.
If the condition checked by #if , #ifdef , or #ifndef is true (nonzero), then all lines between
the matching #else (or #elif ) and an #endif directive, if present, are ignored.
If the condition is false (0), then the lines between the #if , #ifdef , or #ifndef and an #else ,
#elif , or #endif directive are ignored.
This directive checks whether the constant-expression is true (nonzero). The operand must be a
constant integer expression that does not contain any increment (++), decrement (- -), sizeof ,
pointer (*), address (&), and cast operators.
The constant expression in an #if directive is subject to text replacement and can contain
references to identifiers defined in previous #define directives. The replacement occurs before
the expression is evaluated. Each preprocessing token that remains after all macro replacements
have occurred is in the lexical form of a token.
If an identifier used in the expression is not currently defined, the compiler treats the identifier as
though it were the constant zero.
#if example
#include <stdio.h>
#define SWITCH 0
#if (SWITCH==1)
#else
#endif
void main()
Printf(TEXT)
getch();
This directive checks whether the identifier is currently defined. Identifiers can be defined by a
#define directive or on the command line. If such identifiers have not been subsequently
undefined, they are considered currently defined.
#ifdef example
#include <stdio.h>
#define LINE 1
Void main()
Clrscr();
#ifdef LINE
Printf(“this is defined);
#else
#endif
Getch();
#ifndef example
#include <stdio.h>
#define LINE 8
Void main()
Clrscr();
#ifndef LINE
#else
Printf(“this is defined”);
#endif
Getch();
}
#else newline
This directive delimits alternative source text to be compiled if the condition tested for in the
corresponding #if , #ifdef , or #ifndef directive is false. An #else directive is optional.
The #elif directive performs a task similar to the combined use of the else-if statements in C.
This directive delimits alternative source lines to be compiled if the constant expression in the
corresponding #if , #ifdef , #ifndef , or another #elif directive is false and if the additional
constant expression presented in the #elif line is true. An #elif directive is optional.
#endif newline
This directive ends the scope of the #if , #ifdef , #ifndef , #else , or #elif directive.
The number of necessary #endif directives changes according to whether the elif or #else
directive is used. Consider the following equivalent examples:
Another way to verify that a macro is defined is to use the defined unary operator. The defined
operator has one of the following forms:
defined name
defined (name)
The defined operator is especially useful for checking many macros with just a single use of the
#if directive. In this way, you can check for macro definitions in one concise line without
having to use many #ifdef or #ifndef directives.
#ifdef macro1
printf (“Hello!\n" );
#endif
#ifndef macro2
printf (“Hello!\n" );
#endif
#ifdef macro3
printf( "Hello!\n" );
#endif
Another use of the defined operator is in a single #if directive to perform similar macro
checks: