You are on page 1of 15

SCA Pvt. Ltd.

(Sharma Computer Academy)


Author: Saurabh Shukla

Chapter-12
Pointers
Introduction
Before pointers one should understand about address of memory blocks.
Consider the declaration:
int i=5;
This tells compiler:
1) to reserve a memory space of two bytes
2) to associate a name i (name of block)
3) to assign 5 as a content

i
5
65524

Name of location
called variable
Memory location or
memory block
Value at location
or content
Address of
memory block

Up till now we never used address of variable, but from now we will use it to access
memory location.
main()
{
int i=5;
printf(\n %d ,i);
printf(\n %u ,&i);
printf(\n %d ,*&i);
}

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
Output
5
65524
5
Explanation
First printf() is very simple, it prints 5 which is the value of i. Second printf() prints
address of block i. Notice operator & which we were invariably used in scanf(). Third
printf() is a bit tricky which prints 5. We used * operator whose operand is address of
block i.
Our observation
l
l
l
l
l

& is called address of operator


&i returns the address of the variable
* is called value at address operator or simply value at.
* returns the value stored at a particular address
* is also called an indirection operator.

Remember:
1. We cannot store anything in &i as &i is not a variable, it is the way to represent
address of block i.
2. We can collect the address of i (&i) in another variable. Lets say i and j are two
variables and we want to store address of i in j. we can do this by the following
statement:
j=&i;
3. Remember j is not an ordinary variable like any other integer variable.
4. j is a variable which contains the address of another variable
5. A compiler would provide a separate space in memory for this variable j.
6. As the j is also a variable and it requires a separate space, it is obvious that it has
some address also (location number).
7. We cant use j in program without declaring it. And since j is a variable, which
contains the address of i, it is declared as
int *j;
8. This special declaration tells the compiler that j will be used to store the address
of an integer value. In other words j points to an integer.

main()
{
int i = 5, *j;
j= &i;

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
printf(\n%u,
printf(\n%u,
printf(\n%u,
printf(\n%d,
printf(\n%d,
printf(\n%d,
printf(\n%d,

&i);
j);
&j);
*&j);
i);
*(&i));
*j);

}
Output:
65524
65524
3276
65524
5
5
5

65524

65524

3276

Explanation:
&i: read as address of i that is 65524
j: read as j, that represents value in j, that is 65524
&j: read as address of j which is 3276
*&j: read as value at address of j that is 65524
i: read as i, that represents value in i that is 5
*(&i): same as *&i: read as value at address of i that is 5
*j: read as value at address contained in j that is 5
Note operand of value at operator (*) must be address of some variable.
Pointer
l Pointer is a variable that contains address of another variable.
l Address of variable is an integer ranges from 0 to 65535.
l Since address range is same as the range of unsigned int variable, we use %u format
specifier when printing address of variable.
l Addresses of variables can be used to access them.
l Variable address can be stored in pointer variable.
l Pointer variable when declared always prefixed with * symbol. This special symbol
tells the compiler that this is a pointer which can only store address of some
variable.

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
l When pointer is declared without initialization, it contains garbage value. This
garbage is interpreted as address because it is stored in pointer variable. Obviously
this garbage represents invalid address as we havent made any reservation to that
memory location. Such pointers are called un-initialized pointers or wild pointers.
l To avoid un-initialized pointers we can assign 0 to them or NULL. This value when
stored in pointer, it is interpreted as if it is not pointing to anywhere. Such pointers
are called NULL pointer.
l NULL is a macro defined in stdio.h.
l Since pointers always stored address, they occupy 2 bytes in memory.
An important point to understand
float *s;
Above declaration does not mean that s is going to occupy 4 bytes and would store
floating point value. It actually means s is going to contain address of floating point
value.
s will store an address of some float block which contains floating point value.
We can call such pointer as float pointer.
Base Address
Consider the following declarations:
int *p, a;
float *s, k;
char *m, ch;
double *d, b;
p=&a;
s=&k;
m=&ch;
d=&b;
Now we have four pointers, each of different type. Each of the pointers consumes 2 bytes
in memory. p contains address of int block a, s contains address of float block k, m
contains address of char block ch and d contains address of double block b.
Consider the following diagram:

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla

1000

a
1000 1001

2000

k
2000 2001 2002 2003

3000

ch
3000

4000

b
4000 4001 4002 4003 4004 4005 4006 4007

It is important to note that operating system allocates address to every byte. In our
example a is a variable of type int whose address is 1000 (assume), but this is the
address of first byte of int block. 1001 is the address of the next byte. Similarly 2000 is
the address of first byte of float block. Since float block is of 4 bytes, each byte has
different address in a sequential manner.
Address of the first byte of the block of any type is known as base address of that block.
Pointer variable can store one address at a time and it is always base address. To access
any block through pointer requires address of remaining bytes of the block. This is
possible because of two reasons. First, addresses of bytes of a block are always in a
sequence. Second, type of pointer that stores base address.
If the pointer is declared as float pointer (consider s in above example), it is aware of 3
more addresses to be accessed along with base address. Similarly, if the pointer is
declared as double pointer (consider d in above example), it is aware of 7 more
addresses to be accessed along with base address.
Void Pointer
Pointers declared with keyword void are void pointers or generic pointers. Since type of
pointer is void, pointer can not access block, whose address it holds, by just dereferencing pointer. As we studied in the above section, pointers only hold base address
and type of pointer decides how many more bytes need to be accessed. If the type of
pointer is void then we can not know how many more bytes need to be accessed. Every
time when we access block through pointer, typecasting is needful.

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
Example:
main()
{
void *p;
int x=3;
float k=3.14;
p=&x;
printf(%d, *((int *)p));
p=&k;
printf(%f, *((float *)p));
}

Extended Concept of pointers


Pointer is a variable which contains address of another variable. Now this variable itself could be
another pointer. Thus we now have a pointer, which contains another pointer address

Consider the following example


main()
{
int i = 3, *j, **k;
j=&i;
k=&j;
printf(%u %u %u\n, &i, j,*k);
printf(%u %u %u, &j, k, &k);
printf(\n%d %d %d, i, *j, **k);
}

In memory consider the following diagram to support above program.

i
3
6048

6048

3276

3276

5140

Output is:
6048 6048 6048
3276 3276 5140
333
Pointer jargons
int i; // i is an int
int *j; // j is a pointer to an int
int **k; // k is a pointer to a pointer to an int

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
Pointers arithmetic
Although C language is not very strict about compatibility issues between various type of
data, but programmer has to take special care about type conversions. It is also needful in
forthcoming programming languages.
Rule 1: Take care for the compatibility
Example
main()
{
int i=3;
char *j;
j = &i; //Error as incompatible assignment
printf(%d %u, i, &i);
}
Error: cannot convert int* to char*
(error message depends on compiler most of the C compilers do not show any error)

Example
main()
{
long int i=3;
int *j;
j = &i;
//Error as incompatible assignment
printf(%d %u, i, &i);
}
Error: cannot convert long* to int*

Example
main()
{
int k, i=3, *j;
j = &i;
k = j; //Error as incompatible assignment
printf(%u, k);
}
Error: cannot convert int* to int
Example
main()

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
{
int k, i=3, *j;
j = &i;
k = *j;
printf(%d, k);
}
The output is
3
Example
main()
{
int k, i=3, *j;
j = &i;
k = *j + *j;
printf(%d, k);
}
The output is
6
In this program *j would means value at address contained in j and it is 3.
Rule 2: We can not add two addresses.
Example
main()
{
int *k, i=3, *j;
j = &i;
k = j + j;
printf(%d, k);
}
Error: Invalid pointer addition.
Call by reference
A function is called by passing address is called function call by reference.
Function can only access its own memory and can not access variables of other functions
but if we pass address of variables during function call, we actually give power to called
function to access variables of calling function with the help of addresses of variables.
To illustrate above convention go through the following example:
#include<stdio.h>
#include<conio.h>
void swap(int *, int*);
main()

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
{
int a,b;
clrscr();
printf(Enter two numbers\n);
scanf(%d%d,&a,&b);
swap(&a,&b);
printf(a=%d b=%d,a,b);
getch();
}
void swap(int *x, int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
Output:
Enter two numbers
10
20
a=20 b=10
l In the above program, two variables (a and b) are declared in main() function. They
can be accessed from main() function only by their names.
l Let us assume user enter values 10 and 20, which get stored in variable a and b.
l Observe the function call swap(). Instead of passing values of variable a and b,
addresses of a and b are passed.
l Since addresses are always stored in pointer variables, we create two pointer
variables in function swap() as formal argument.
l Pointer variables x and y received addresses of variable a and b.
l In function swap(), variable a and b of main() function can be accessed with the
help of pointers x and y.
l *x represent variable a and *y represent variable b.
l Notice that values need not to be returned as changes made in actual locations only.
l Also notice the declaration of function swap(). As two addresses of int block would
be passed during function call, it is specified as void swap(int*, int*);

Pointers with arrays


Remember two things about pointer and array:
1) However big an array it always stored in a contiguous location.
2) When pointer is incremented it always points to immediately next location of its
type.
Consider the following example:

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
#include<stdio.h>
#include<conio.h>
void input(int *);
void display(int *);
main()
{
int a[5];
clrscr();
input(&a[0]);
display(&a[0]);
getch();
}
void input(int *p)
{
int i;
printf(Enter five numbers);
for(i=0; i<=4; i++)
scanf(%d, p+i );
}
void display(int *p)
{
int i;
printf(Five numbers are: );
for(i=0; i<=4; i++)
printf(%d , *(p+i));
}
Explanation
l Address of very first block of array that is address of a[0] is passed during function
call of input() and display()
l Address is received in pointer variable p.
l We need not to create as many pointer variables as we have array blocks. We need
to store address of first block only (a[0]). Rest of the addresses can be obtained by
simple pointers arithmetic. By adding 1 to p we get address of a[1], similarly by
adding 2 to p, we get address of a[2] and so on.
l In the function input(), see scanf(), we wrote p+i in it. As the value of i increases
with every iteration of for loop, p+i represents address of successive blocks of
array.
l In function display(), see printf(), we wrote *(p+i), as we need to pass values of
array blocks in function printf().

Pointers with two dimensional arrays

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
There are two ways to create pointers that will be used to store address of two
dimensional arrays.
First is simply create a pointer and second is pointer to an array.
The following example illustrates the first way.
main()
{
int i;
int a[2][3]={3,5,1,6,7,8};
int *p;
p=&a[0][0];
for(i=0;i<=6;i++)
printf(%d,*(p+i));
}
Since array of any dimension always consumes memory in contiguous manner. In our
example we made an array of six blocks. Address of the first block gets stored in pointer
p. Now by incrementing address contained in p by one each time, we can point to next
block in array.
Second way is to create a pointer to an array.
main()
{
int i,j;
int a[2][3]={3,5,1,6,7,8};
int (*p)[3];
p=a;
for(i=0;i<=1;i++)
{
for(j=0;j<=2;j++)
printf(%d ,*( *(p+i)+j));
printf(\n);
}
}
Explanation:
l Notice the way we declare pointer. This is not a simple pointer but it is a pointer to
an array of 3 int blocks.
l In the line p=a, address of array gets stored in pointer p.

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
a[0][0]

a[0][1]

a[0][2]

a[1][0]

a[1][1]

a[1][2]

1000

1002

1004

1006

1008

1010

p
1000

l Consider the above diagram, let us assume the address of array is 1000 and it is
stored in pointer p.
l p+1 represent address of second array that is 1006. This happens because p is not a
simple pointer to an int, rather it is a pointer to an int array of size 3. Thus every
time when pointer is incremented, it points to next array.
l *(p+1) represent address of first block of first address and if we add 1 to it that is
*(p+1)+1, it means address of next block of the first array.
l Chart below gives you a clear picture of pointer jargons and their meaning.
Expression
P
p+1
*(p+0)
*(p+1)
*(p+0)+1
*(p+0)+2
*(p+1)+0
*(p+1)+1
*(p+1)+2

Meaning
1000
1006
1000
1006
1002
1004
1006
1008
1010

Expression
*(*(p+0)+0)
*(*(p+0)+1)
*(*(p+0)+2)
*(*(p+1)+0)
*(*(p+1)+1)
*(*(p+1)+2)
*p
**p

Meaning
3
5
1
6
7
8
1000
3

Pointers with strings


Just like an int array, char array can also be managed with pointers. We can store address
of char array in char pointer. Now this pointer can be used for any string manipulation.
main()
{
char str[ ]=Welcome;
char *p;
p=str;

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
printf(%s,p);
}
Output:
Welcome
There is a difference between p and str. Pointer p is used to store address of char array.
We can change value of p an any instant as it is merely a variable. On the other hand str
is not a variable. Name of array like str is always used to represent address of first byte of
array. Since str is not a variable operations attempting to change value of str leads to
compilation error.
Define a function to calculate length of string:
int stringlength(char *p)
{
int i=0;
while(*(p+i)!=\0)
i++;
return(i);
}

Array of pointers and pointer array


Array of pointers and pointer array are same, but careful about pointer to an array (see
pointer with two dimensional arrays in previous page).
Pointer array is like you are creating many pointers in one go, all of them are of same
type.
main()
{
int a=3,b=4,c=5,i;
int *p[3];
p[0]=&a;
p[1]=&b;
p[2]=&c;
for(i=0;i<=2;i++)
printf(%d ,*p[i]);
}
Output:
345

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
In the above example we have three pointers, p[0], p[1] and p[2]. These pointers are
used to contain addresses of a, b and c. Thus pointer array means sequence of pointers.
Dangling pointer
A pointer becomes dangling when memory of the block is released whose address is still
reside in pointer. It is much like wild pointer. The only difference in wild pointer and
dangling pointer is, wild pointers are un-initialized pointers thus containing invalid
address. Wild pointer points to unknown location which can be dangerous from
programming point of view.
On the other hand dangling pointers are initialized perfectly but due to programmers
carelessness it is still pointing to the memory area which was released.
main()
{
int *p;
{
int x=4;
p=&x;
}
*p=5;
}
See the scope of variable x is limited to the inner block. Pointer p is containing address of
variable x. As soon as control comes out from inner block, memory of variable x is
released, but the pointer p still contains address of x. Here p becomes dangling.

Const pointer and pointer to a const


Const pointer is a pointer whose value can not be altered.
Pointer to a const is a pointer that stores an address of const variable thus we can not
modify variable data using pointer.
Declaration of pointer to a const:
const int x = 4;
const int *p; //or int const *p;
p=&x;
The above code tells that the pointer p is a pointer to a const. This means we can not
modify variable x using pointer p.
For example:
*p=6; //error: cannot modify const variable

SCA Pvt. Ltd. (Sharma Computer Academy)


Author: Saurabh Shukla
p++; //valid:
Another example:
int x=4;
const int *p; //or int const *p;
p=&x;
x++; //valid
*p=6;//error: can not modify const variable
p++; //valid
Another example
const int x=4;
int *p;
p=&x;
x++; //error: can not modify const variable
*p=3; //undefined behavior , should be an error
p++; //valid
Example for const pointer
int x=5;
int *const p=&x;
p++; //error: can not modify const variable p
x++; //valid
*p=7; //valid
Another example:
int x=5;
int *const p;
p=&x; //error can not modify const variable p.

Remember that const variables must be initialized during declaration.

You might also like