Module 1
Module 1
Note:
What are the different methods using which structure variables can be defined using
typedef?
How to ini<alize type-defined structure?
Note: The members “name” and “marks” are arrays inside the structure “STUDNT”.
How to initialize the members of a structure when structure has array as the member name? A structure
having array as the member can be initialized as shown in program segment below:
How to initialize the structures having arrays as member name? The structure having array name as
member can be initialized as shown below:
The complete program to read the student info, sort the student info and to print the student info can be
written as shown below:
The above function multiply can also be written using array operator as shown below:
How to represent a complex number in C? A complex number 3 + 8i can be represented using structures
as shown below:
The program to read a complex number, print a complex number and to add two complex numbers can
be written as shown below:
Write a C program to search for given student name in a student record consisting of name and marks
The given student called “key” has to be compared with all records as shown below:
The complete C program to search for a given key in an array of student records can be written as shown
below:
Write a program to print student information who got above average marks and who got below average
marks separately.
The complete program to print the student info who got more than average marks and who got less than
average is shown below:
How memory is allocated?
How memory is allocated?
Chapter 12: Pointers
What are we studying in this chapter?
¨ Pointers and address
¨ Pointers and function arguments
¨ pointers and arrays, address arithmetic
¨ character pointer and functions
¨ Pointer to pointer , Initialization of pointer arrays
¨ Understanding complex declarations
¨ dynamic allocation methods
¨ Array of pointers and programming examples. - 7 hours
Example 12.1: Program to print the values using variables and their addresses
#include <stdio.h>
void main()
a b
{
int a = 25; 25 45
int b = 45; 1000 1002
/* Accessing the data using variables */
printf(“Value of a = %d\n”, a); Value of a = 25
printf(“Value of b = %d\n”, b); Value of b = 45
Note: Observe that the operator pair *& gets cancelled each other. So,
¨ *&a is same as a
¨ *&b is same as b
Now, the question is “Is it possible to store the address of a variable into memory?”.
Yes, it is possible. As we store the data using assignment operator, we can store
address of variable using assignment operator as shown below:
12.2 : Pointers
p = &a; // Now, the variable p contains address of variable a
x = &b; // Now, the variable x contains address of variable b
Note: Please see that, the variables p and x in above two statements are not normal
variables, as they do not contain the data. Instead the variables p and x contain
addresses of the data. These variables p and x which contain the addresses are
called pointers or pointer variables.
Now, once we know what are pointer variables, the next question is “How to declare
the pointer variables?” It is very simple and can be done as shown below:
If a variable p contains address of int variable its declaration is: int *p;
If a variable x contains address of float variable its declaration is: float *x;
If a variable y contains address of char variable its declaration is: char *y;
If a variable z contains address of double variable its declaration is: double *z;
Note: The address operator can be used with any variable that can be placed on the
left side of an assignment operator. Since constants, expressions and array names
cannot be used on the left hand side of the assignment and hence accessing address is
invalid for constants, expressions and array names. The following are invalid:
Example 12.2: In the declaration, the position of * is immaterial. For example, all the
following declarations are same:
int *pa;
int * pa;
int* pa;
12.4 : Pointers
Any of the above declaration informs that the variable pa is a pointer variable and it
should contain address of integer variable.
Example 12.3: Consider the multiple declarations as shown below:
int* pa, pb, pc;
int *p;
This indicates that p is a pointer variable and the corresponding memory location
should contain address of an integer variable. But, the declaration will not initialize
the memory location and memory contains garbage value as shown below:
p Garbage value
Here, the pointer variable p does not contain a valid address and we say that it is a
dangling pointer. Now, let us see “What is a dangling pointer?”
Definition: A pointer variable which does not contain a valid address is called
dangling pointer.
C Programming Techniques : 12.5
Example 12.4: Consider following declarations and assume all are local variables.
int *pi; /* Pointer to an integer */
float *pf; /* Pointer to a float number */
char *pc; /* Pointer to a character */
¨ The local variables are not initialized by the compiler during compilation. This is
because, the local variables are created and used only during execution time.
¨ The pointer variables also will not be initialized and hence they normally contain
some garbage values and hence are called dangling pointers.
¨ The memory organization is shown below:
…..
…..
pi Garbage value
pf Garbage value
pc Garbage value
…..
…..
The pointer variables pi, pf and pc does not contain valid addresses and hence they
are dangling pointers.
Note: Most of the errors in programming are due to un-initialized pointers. These
errors are very difficult to debug. So, it is the responsibility of the programmer to
avoid dangling pointers. Hence, it is necessary to initialize the pointer variables so
that they always contain valid addresses.
Example 12.5: Consider following declarations and assume all are global variables.
int *pi; /* Pointer to an integer */
float *pf; /* Pointer to a float number */
char *pc; /* Pointer to a character */
All global variables are initialized by the compiler during compilation. The pointer
variables are initialized to NULL indicating they do not point to any memory
locations as shown below:
pi NULL
pf NULL
pc
NULL
12.6 : Pointers
12.2.4 Initializing a pointer variable
Now, the question is “How to initialize a pointer variable?” Initialization of a pointer
variable is the process of assigning the address of a variable to a pointer variable. The
initialization of a pointer variable can be done using following three steps:
Step 1: Declare a data variable
Step 2: Declare a pointer variable
Step 3: Assign address of a data variable to pointer variable
using & operator and assignment operator
Note that the steps 1 and 2 can be interchanged i.e., we can first declare a pointer
variable, then declare a data variable and then initialize the pointer variable. The three
ways using which initialization can be done is described below:
Method 1: Declaring a data variable, pointer variable and initializing pointer
variable in separate statements. For example, consider the following three statements:
int x; /* Step 1: x is declared as an integer data variable */
int *px; /* Step 2: px is declared as a pointer variable */
px = & x; /* Step 3: copy address of data variable to pointer variable */
int x;
int *px = &x;
ip = p;
Here, ip is a pointer to integer. It should contain the address. But, we are not
storing the address. Hence, it is an error.
ip = &d;
Here, ip should contain address of integer variable. But, we are storing address of
float variable. So, it results in error.
PROGRAM TRACING
1. #include <stdio.h>
2.
3. void main() Execution starts from main
sum
4.{
5. int a = 10, b = 20, sum; a 10 b 20 30
6
7. int *pa, *pb;
8.
9. pa = &a; pa pb
10. pb = &b;
11.
12. sum = *pa + *pb; sum = 10 + 20 =30
13.
14. Output
15. printf(“Sum = %d\n”, sum); Sum = 30
16.}
12.8 : Pointers
Example 12.8: Program to read two numbers and add two numbers using pointers
PROGRAM TRACING
1. #include <stdio.h>
2.
3. void main() Execution starts from main
4.{ sum
5. int a, b, sum; a 10 b 20 30
6
7. int *pa, *pb;
8.
9. pa = &a; pa pb
10. pb = &b;
11. Input
12. scanf(“%d %d”,&a, &b); 10 20
13. a = 10 b = 20
14. sum = *pa + *pb; sum = 10 + 20 =30
15. Output
16. printf(“Sum = %d\n”, sum); Sum = 30
17.}
Note: After executing statement 12, the values 10 and 20 which are read from the
keyboard are copied into memory locations identified by a and b. Then those values
are accessed using pointer variables pa and pb, added and result is stored in the
variable sum.
x 5006 10
12.10 : Pointers
int *r;
int x = 10;
2
p = &x; p 5000
q = &x; q 5002
r = &x; r 5004
x 5006 10
3
printf(“&p =%u, p = %u, *p = %d\n”,&p, p, *p); /* Output */
&p = 5000, p = 5006, *p = 10
printf(“&q =%u, q = %u, *q = %d\n”,&q, q, *q); /* Output */
&q = 5002, q = 5006, *q = 10
printf(“&r =%u, r = %u, *r = %d\n”,&r, r, *r); /* Output */
&r = 5004, r = 5006, *r = 10
We have used pointers which directly points to data. In this section, let us see “What
is pointer to a pointer?”
C Programming Techniques : 12.11
int a;
int *p1;
int **p2;
¨ The first declaration instructs the compiler to allocate the memory for the variable
a in which integer data can be stored.
¨ The second declaration tells the compiler to allocate a memory for the variable p1
in which address of an integer variable can be stored.
¨ The third declaration tells the compiler to allocate a memory for the variable p2 in
which address of a pointer variable which points to an integer can be stored. The
memory organization for the above three declarations is shown below:
p2 p1 a
Garbage Garbage
value
?
value
Assume the above declarations are followed by the following assignment statements:
a = 10;
p1 = &a;
p2 = &p1;
The memory organization after executing the statement a = 10 is shown below:
p2 p1 a
Garbage Garbage
value 10
value
The memory organization after executing the statement p1 = &a is shown below:
p2 p1 a
Garbage
value
10
The memory organization after executing the statement p2 = &p1 is shown below:
p2 p1 a
10
12.12 : Pointers
The data item 10 can be accessed using three variables a, p1 and p2 are shown below:
The following program illustrates the way the data item 10 can be accessed using the
variable a, using a pointer variable p1 and pointer to a pointer variable p2.
Example 12.14: Program to access 10, using a variable, pointer variable and pointer
to a pointer variable
#include <stdio.h> TRACING
void main()
{ p2 p1 a
int a;
Garbage Garbage
int *p1; value ?
value
int **p2;
p2 p1 a
Garbage Garbage
a = 10; value
10
value
p2 p1 a
p1 = &a; Garbage
value 10
p2 p1 a
p2 = &p1;
10
Output
printf(“a = %d\n”,a); a = 10
printf(“*p1 = %d\n”, *p1); *p1 = 10
printf(“**p2 = %d\n”, **p2); **p2 = 10
}
C Programming Techniques : 12.13
Note: If x is declared as integer, which of the following statements is true and which
is false?
a. The expression *&x and x are the same. // it is true
b. The expression *&x and &*x are the same. // it is false
illegal
/* Increment a */
a 6 b 7
++a;
p q
p q
a 7 b 6
/* Access b using pointer variable q*/
--(*q);
p q
12.14 : Pointers
a 7 b 5
/* Decrement b */
--b;
p q
Output a=7 b=5
*p = 7 *q = 5
Note: The address of the 0th memory location 0100 stored in a cannot be changed. So,
even though a contains an address, since its value cannot be changed, we call a as
pointer constant. Observe that &a[0] and a are same.
a &a[0] (a + 0)
same same
To justify above points, now let us see “What is the output of the following
program?”
C Programming Techniques : 12.15
PROGRAM TRACING
#include <stdio.h>
void main()
{
int a[5] = {10, 20, 30, 40, 50}; Output
Note: We may get different answer in our computer. But, whatever it is, observe that
the value of &a[0] or a or a+0 are same.
Now, let us see “How to access the address of each element?” The address of each
item can be accessed using two different ways:
In general,
&a[i] (a +i) where i = 0 to 4
is same as 0 to 5-1
0 to n – 1 (in general)
Note: The various ways of accessing the address of ith item in an array a is shown
below:
&a[i] is same as a + i
same same
&i[a] is same as i + a
So, address of a[i] can be obtained using any of the following notations:
The data in those addresses can be obtained using the indirection operator * as shown
below:
a[i] i[a]
So, *(a+i) or *(i+a) or a[i] or i[a] or a[i] or i[a] are one and the same.
Note: It is observed from the above example that: a[i] is same as *(a+i) denoted
using pointer concept. So, any array program can be written using pointers.
Consider 5 elements 10, 20, 50, 25 and 15. It is required to find the largest of these 5
numbers. Now, let us see “How to write the program to find largest of N numbers?”
Design: Assume the variable big contains 10 which is the 0th element of the array and
pos is 0 which is the position of that element. The equivalent code can be written as:
Note: When we know the program using arrays, we can easily write the program
using pointers. We have seen that a[i] is same as *(a+i) or *(i+a) or i[a]. So, replace
a[i] by *(a+i) to get the program using pointers.
Now, the complete program to find the largest of N elements using an array and
using pointer with indexing is shown below:
12.18 : Pointers
Example 12.16: Program to compute largest and its position
Example 12.17: Valid statements with operations such as multiplication and addition
Note: The error in the above statement can be eliminated by inserting the space
between / and * as shown below:
Note: Even though various operations can be performed on *p1 and *p2 (since they
represent the values to be manipulated), the operations are restricted on p1 and p2
since they contain only the addresses. The various operations that can be performed
on pointer variables are shown below:
int a[5]={10, 20, 30, 40, 50}; float a[5]={10.555, 20, 30, 40, 50};
int *p; float *p;
p = a; /* p points to a */ p = a; /* p points to a */
Note: Each time p++ is executed, Note: Each time p++ is executed, its
its value will be incremented by 2 value will be incremented by 4 because
because size of integer is 2 bytes. size of floating point number is 4 bytes.
In other words, p points to the In other words, p points to the next
next item. item.
Now, let us see “How to write a program to display array elements using pointer?”
C Programming Techniques : 12.21
Design: Consider the following array and assume p points to the beginning of the
array. To start with p points to 0100 and *p refers to 10. Let us observe the outputs in
various iterations shown below:
0100 0102 0104 0106 0108 0110
beginning
10 20 30 40 50
of array
p p p p p p
Iterations: i = 0 1 2 3 4
printf(“%d\n”, *p);
p++;
are repeatedly executed for i = 0 to 4, to get the output 10, 20, 30, 40 and 50. The C
equivalent statement using for loop is shown below:
for (i = 0; i <= 4; i++) /* i <= 4 is same as i < 5 */
{
printf(“%d\n”, *p);
p++;
}
12.22 : Pointers
The complete program is shown below:
#include <stdio.h>
void main()
{
int a[] = {10, 20, 30, 40, 50 };
int *p;
int i;
p = a; /* same as p = &a[0] */
#include <stdio.h>
void main()
{
int a[] = {10, 20, 30, 40, 50 };
int *p;
int i, sum;
Note: Observe that by executing p++, we can point p to the next element. On similar
lines by executing p--, we can point p to the previous element in an array.
Subtraction can be performed when first operand is a pointer and the second operand
is an integer. This can be explained by considering the following example.
Example 12.23: Write a program to display array elements using pointer from last
element to first element.
Note: As we execute p++, pointer variable p points to next element, if we execute p--,
pointer variable p points to the previous element.
Design: To get the array elements in reverse order, point the variable p to point to the
end of the array and replace p++ by p– – in the previous program. The complete
program is shown below:
#include <stdio.h>
12.24 : Pointers
void main()
{
int a[] = {10, 20, 30, 40, 50 };
int *p;
int i;
If two pointers are associated with the same array, then comparison of two pointers is
allowed using relational operators. But, if the two pointers are associated with
different arrays, even though comparisons of two pointers is allowed, the result is
meaningless.
Now, let us see “How to write a program to display array elements by comparing
of two pointers?”
Design: Let us use two pointers p and q where p points to the first element of array a
and q points to the last element of array a as shown below:
p q
Observe from the above figure that as long as p <= q, value pointed to by p can be
printed and updated using the following statements:
while (p <= q)
{ Output
printf("%d ",*p); 10 20 30 40 50
p++;
}
So, the complete program is shown below:
Example 12.24: Program to display array elements by comparing pointers
#include <stdio.h>
void main()
{
int a[] = {10, 20, 30, 40, 50 };
int *p;
int *q;
p = &a[0]; /* point p to the first element */
q = &a[4]; /* point q to the last element*/
while (p <= q) /* Comparing two pointer values */
{
printf("%d ",*p); 10 20 30 40 50
p++;
}
printf("\n");
}
Note: Two pointer subtractions and two pointer comparisons are generally performed
if both the pointers point to the same array.
The two ways of declaring and using the array in the called function are:
C Programming Techniques : 12.27
¨ using pointer declaration
¨ using array declaration
Now, using the above technique, any array program can be converted into a program
using pointers.
Consider the function to find the length of the string (Refer example 10.11, section
10.5.1 for design details). Various versions of the functions are written side by side to
show the difference:
The C program to access any of the above functions can be written as shown below:
12.28 : Pointers
Example 12.26: Program using the user-defined function my_strlen()
#include <stdio.h>
/* Include: Example 12.25: to compute the length */
void main()
{
char str[20];
int i; Input
Example 12.27: Function to copy string src to string dest using 3 methods.
Using arrays Using Pointers
void my_strcpy(char *dest, char *src)
void my_strcpy(char dest[], char src[])
{ {
int i = 0; /* copy the string */
while ( *src != ‘\0’)
/* Copy the string */ *dest++ = *src++;
while (src[i] != ‘\0’) /* attach null character at end */
{ *dest = ‘\0’;
dest[i] = src[i]; }
i++;
} Note: Following is most efficient one
void my_strcpy(char *dest, char *src)
/* Attach null character at the end */ {
dest[i] = ‘\0’; while (*dest++ = *src++)
} ;
}
C Programming Techniques : 12.29
Note: Observe the null statement “;” in the third version of my_strcpy. It does nothing.
The condition in the while loop i.e., *dest++ = *src++ is repeatedly executed and
each character of the source is copied into destination including ‘\0’. Once ‘\0’ is
reached, the condition fails and control comes out of the loop. The complete program
which uses the user defined function is shown below:
Example 12.32: Interpret the declaration: int *p. The declaration can be pictorially
represented as shwon below:
to
Reading in the direction of
end is a arrow along with the labels we
have:
int * p
p is a * to int
i.e., p is a pointer to an integer
start [By reading * as pointer, int as
integer]
Example 12.33: Interpret the declaration: int a[10]. The declaration can be
pictorially represented as shwon below:
is an array of
Reading in the direction of arrow
end
along with the labels we have:
int a [10]
a is an array of 10 int
i.e., a is an array of 10 integer
start
[By reading int as integer]
Example 12.34: Interpret the declaration: int *p[5]. The declaration can be
pictorially represented as shwon below:
to
is an array of Reading in the direction of
end
arrow along with the labels we
int * p [5] have:
p is an array of 5 * to int
i.e., p is an array of 5 pointers
start to integers where * is pointer,
int is integer
Example 12.35: Interpret the declaration: int (*p) [5]. The declaration can be
pictorially represented as shwon below:
12.32 : Pointers
is a function
end
int a (int b) with b as integer parameter
start
returning
Note: If an identifier is followed by (….), it indicates a function call or function
declaration. So, reading in the direction of arrow along with the labels we have:
a is a function with (int b) and returning int
i.e., a is a function which accepts b an integer as a parameter and returning an integer
Now, let us see “What are the differences between static memory allocation and
dynamic memory allocation?” The various differences between static allocation and
dynamic allocation technique are shown below:
Now, let us see “What are the various memory management functions in C?” Th
12.36 : Pointers
12.8.1 malloc(size)
Now, let us see “What is the purpose of using malloc?” This function allows the
program to allocate memory explicitly as and when required and the exact amount
needed during execution. This function allocates a block of memory. The size of the
block is the number of bytes specified in the parameter. The syntax is shown below:
#include <stdlib.h> /* Prototype definition of malloc() is available */
……..
ptr = (data_type *) malloc(size);
…….
where
¨ ptr is a pointer variable of type data_type
C Programming Techniques : 12.37
¨ data_type can be any of the basic data type or user defined data type
¨ size is the number of bytes required
Now, let us see “What is the purpose of using calloc?” This function is used to
allocate multiple blocks of memory. Here, calloc – stands for contiguous allocation of
multiple blocks and is mainly used to allocate memory for arrays. The number of
blocks is determined by the first parameter n. The size of each block is equal to the
number of bytes specified in the parameter i.e., size. Thus, total number of bytes
allocated is n*size and all bytes will be initialized to 0. The syntax is shown below:
void function_name()
{
……..
ptr = (data_type *) calloc(size);
C Programming Techniques : 12.39
if (ptr == NULL)
{
printf(“Insufficient memory\n”);
exit(0);
}
……..
}
#include <stdio.h>
#include <stdlib.h>
void main()
{
int *a, i, j, n;
printf("Enter the no. of elements\n");
scanf("%d",&n);
Before using this function, the memory should have been allocated using malloc() or
calloc(). Sometimes, the allocated memory may not be sufficient and we may require
additional memory space. Sometimes, the allocated memory may be much larger and
we want to reduce the size of allocated memory. In both situations, the size of
allocated memory can be changed using realloc() and the process is called
reallocation of memory. The reallocation is done as shown below:
¨ realloc() changes the size of the block by extending or deleting the memory at the
end of the block.
¨ If the existing memory can be extended, ptr value will not be changed
¨ If the memory cannot be extended, this function allocates a completely new block
and copies the contents of existing memory block into new memory block and
then deletes the old memory block. The syntax is shown below:
Now, let us see “What does this function return?” This function returns the following
values:
¨ On successful allocation, the function returns the address of first byte of allocated
memory.
¨ If specified size of memory cannot be allocated, the condition is called “overflow
of memory”. In such case, the function returns NULL.
Example: 12.40: Sample program to show the problems that occur when free() is not
used.
1. #include <stdlib.h>
2.
3. void main()
4. { a
5. int *a;
6.
7. a = (int *) malloc(sizeof(int)); a
8. *a = 100; 100
9.
10. a = (int *) malloc(sizeof(int)); 200
11. *a = 200;
12. }
Now, let us see “What will happen if the above program is executed?” The various
activities done during execution are shown below:
¨ When control enters into the function main, memory for the variable a will be
allocated and will not be initialized.
¨ When memory is allocated successfully by malloc (line 7), the address of the first
byte is stored in the pointer a and integer 100 is stored in the allocated memory
(line 8).
¨ But, when the memory is allocated successfully by using the function malloc in
line 10, address of the first byte of new memory block is copied into a (shown
using dotted lines.)
Observe that the pointer a points to the most recently allocated memory, thereby
making the earlier allocated memory inaccessible. So, memory location where the
value 100 is stored is inaccessible to any of the program and is not possible to free so
that it can be reused. This problem where in memory is reserved dynamically but not
accessible to any of the program is called memory leakage. So, care should be taken
while allocating and de-allocating the memory. It is the responsibility of the
programmer to allocate the memory and de-allocate the memory when no longer
required.