You are on page 1of 15

LAB SHEET: POINTERS

CONCEPT OF POINTERS
Different from other normal variables which can store values, pointers are
special variables that can hold the address of a variable. Since they store
memory address of a variable, the pointers are very commonly said to point to
variables. Lets try to understand the concept.

As shown in the above diagram:


A normal variable var has a memory address of 1001 and holds a value
50.

A pointer variable has its own address 2047 but stores 1001, which is
the address of the variable var

How to Declare a Pointer?


A pointer is declared as :
<pointer type> *<pointer-name>
In the above declaration :
1.

pointer-type : It specifies the type of pointer. It can be int,char, float etc.


This type specifies the type of variable whose address this pointer can store.

2.

pointer-name : It can be any name specified by the user. Professionally,


there are some coding styles which every code follows. The pointer names
commonly start with p or end with ptr
An example of a pointer declaration can be :
char *chptr;
In the above declaration, char signifies the pointer type, chptr is the name of
the pointer while the asterisk * signifies that chptr is a pointer variable.
How to initialize a Pointer?
A pointer is initialized in the following way :
<pointer declaration(except semicolon)> = <address of a variable>

OR

<pointer declaration>
<name-of-pointer> = <address of a variable>
Note that the type of variable above should be same as the pointer type.(Though
this is not a strict rule but for beginners this should be kept in mind).
For example :
char ch = 'c';

char *chptr = &ch; //initialize

OR

char ch = 'c';
char *chptr;
chptr = &ch //initialize
In the code above, we declared a character variable ch which stores the value
c. Now, we declared a character pointer chptr and initialized it with the
address of variable ch.
Note that the & operator is used to access the address of any type of variable.
How to Use a Pointer?
A pointer can be used in two contexts.
Context 1: For accessing the address of the variable whose memory address the
pointer stores.
Again consider the following code :
char ch = 'c';
char *chptr = &ch;

Now, whenever we refer the name chptr in the code after the above two lines,
then compiler would try to fetch the value contained by this pointer variable,
which is the address of the variable (ch) to which the pointer points. i.e. the
value given by chptr would be equal to &ch.
For example :
char *ptr = chptr;
The value held by chptr (which in this case is the address of the variable ch)
is assigned to the new pointer ptr.
Context 2: For accessing the value of the variable whose memory address the
pointer stores.
Continuing with the piece of code used above :
char ch = 'c';
char t;
char *chptr = &ch;
t = *chptr;
We see that in the last line above, we have used * before the name of the
pointer. What does this asterisk operator do?
Well, this operator when applied to a pointer variable name(like in the last line
above) yields the value of the variable to which this pointer points. Which
means, in this case *chptr would yield the value kept at address held by chptr.
Since chptr holds the address of variable ch and value of ch is c, so
*chptr yeilds c.

When used with pointers, the asterisk * operator is also known as value of
operator.

POINTER ARITHMETIC
Pointers do not have to point to single variables. They can also point at the cells
of an array. For example, we can write
int *ip;
int a[10];
ip = &a[3];
and we would end up with ip pointing at the fourth cell of the
array a (remember, arrays are 0-based, so a[0] is the first cell). We could
illustrate the situation like this:

We'd use this ip just like the one in the previous section: *ip gives us
what ip points to, which in this case will be the value in a[3].
Once we have a pointer pointing into an array, we can start doing pointer
arithmetic. Given that ip is a pointer to a[3], we can add 1 to ip:
ip + 1
What does it mean to add one to a pointer? In C, it gives a pointer to the cell one
farther on, which in this case is a[4]. To make this clear, let's assign this new
pointer to another pointer variable:
ip2 = ip + 1;
Now the picture looks like this:

If we now do
*ip2 = 4;
we've set a[4] to 4. But it's not necessary to assign a new pointer value to a
pointer variable in order to use it; we could also compute a new pointer value
and use it immediately:
*(ip + 1) = 5;
In this last example, we've changed a[4] again, setting it to 5. The parentheses
are needed because the unary ``contents of'' operator * has
higher precedence (i.e., binds more tightly than) the addition operator. If we
wrote *ip + 1, without the parentheses, we'd be fetching the value pointed to
by ip, and adding 1 to that value. The expression *(ip + 1), on the other hand,
accesses the value one past the one pointed to by ip.
Given that we can add 1 to a pointer, it's not surprising that we can add and
subtract other numbers as well. If ip still points to a[3], then
*(ip + 3) = 7;
sets a[6] to 7, and
*(ip - 2) = 4;
sets a[1] to 4.
Up above, we added 1 to ip and assigned the new pointer to ip2, but there's no
reason we can't add one to a pointer, and change the same pointer:
ip = ip + 1;
Now ip points one past where it used to (to a[4], if we hadn't changed it in the
meantime). The shortcuts we learned in a previous chapter all work for pointers,
too: we could also increment a pointer using
ip += 1;
or
ip++;
Of course, pointers are not limited to ints. It's quite common to use pointers to
other types, especially char. Here is the innards of the mystrcmp function we
saw in a previous chapter, rewritten to use pointers. (mystrcmp, you may recall,
compares two strings, character by character.)
char *p1 = &str1[0], *p2 = &str2[0];

while(1)
{
if(*p1 != *p2)
return *p1 - *p2;
if(*p1 == '\0' || *p2 == '\0')
return 0;
p1++;
p2++;
}
The autoincrement operator ++ (like its companion, --) makes it easy to do two
things at once. We've seen idioms like a[i++] which accesses a[i] and
simultaneously increments i, leaving it referencing the next cell of the array a.
We can do the same thing with pointers: an expression like *ip++ lets us access
what ip points to, while simultaneously incrementing ip so that it points to the
next element. The preincrement form works, too: *++ip increments ip, then
accesses what it points to. Similarly, we can use notations like *ip-- and *--ip.

Q. What would be the equivalent pointer expression for referring the array
element a[i][j][k][l]
A.

((((a+i)+j)+k)+l)

B.

*(*(*(*(a+i)+j)+k)+l)

C.

(((a+i)+j)+k+l)

D.

((a+i)+j+k+l)

Answer: Option B

POINTERS AND FUNCTIONS(CALL BY REFERENCE)

When, argument is passed using pointer, address of the memory location


is passed instead of value.
Example of Pointer And Functions
Program to swap two number using call by reference.
/* C Program to swap two numbers using pointers and function. */

#include <stdio.h>
void swap(int *a,int *b);
int main(){
int num1=5,num2=10;
swap(&num1,&num2); /* address of num1 and num2 is passed to swap
function */
printf("Number1 = %d\n",num1);
printf("Number2 = %d",num2);
return 0;
}
void swap(int *a,int *b){ /* pointer a and b points to address of num1 and
num2 respectively */
int temp;
temp=*a;
*a=*b;
*b=temp;
}
Output
Number1 = 10
Number2 = 5
Explanation
The address of memory location num1 and num2 are passed to function
and the pointers *a and *b accept those values. So, the
pointer a and b points to address of num1 and num2 respectively. When,
the value of pointer are changed, the value in memory location also
changed correspondingly. Hence, change made to *a and *b was reflected
in num1 and num2 in main function.

Questions:
1. consider the snippet of the swap:
void swap(int *a, int *b){ /* pointer a and b points to address of
num1 and num2 respectively */
int temp;
temp=*a;
a=b;
*b=temp;
}
2. consider the snippet of the swap:
void swap(int *a, int *b){ /* pointer a and b points to address of
num1 and num2 respectively */
*a ^= *b;
*a ^= *b;
*a ^= *b;
}

This technique is known as call by reference in C programming

Examples of call by reference:


Eg. 1: Adding a number using call be reference

#include <stdio.h>

void call_by_reference(int *y) {


printf("Inside call_by_reference y = %d before adding 10.\n", *y);
(*y) += 10;
printf("Inside call_by_reference y = %d after adding 10.\n", *y);
}

int main() {
int b=10;

printf("b = %d before function call_by_reference.\n", b);


call_by_reference(&b);
printf("b = %d after function call_by_reference.\n", b);

return 0;
}

The output of this call by reference source code example will look like this:

b = 10 before function call_by_reference.


Inside call_by_reference y = 10 before adding 10.
Inside call_by_reference y = 20 after adding 10.
b = 20 after function call_by_reference.
Lets explain what is happening in this source code example. We start with
an integer b that has the value 10. The function call_by_reference() is called
and the address of the variable b is passed to this function. Inside the

function there is some before and after print statement done and there is 10
added to the value at the memory pointed by y. Therefore at the end of the
function the value is 20. Then in main() we again print the variable b and as
you can see the value is changed (as expected) to 20.

Eg. 2: Incrementing a number using call by reference:

int increment(int *var)


{
*var = *var+1;
return *var;
}
int main()
{
int num1=20;
int num2 = increment(&num1);
printf("num1 value is: %d", num1);
printf("num2 value is: %d", num2);
return 0;
}
Output:
num1 value is: 21
num2 value is: 21
In this method the value of num1 got changed because the address of num1 is
passed as an argument so the increment operation is performed on the value
stored at the address.

POINTERS AND ARRAYS:

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.

Suppose we declare an array arr,

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 element 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.

arr is equal to &arr[0] // by default


We can declare a pointer of type int to point to the array arr.

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 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.

Example of pointers and arrays:


Here array is declared as an array containing three integers:
int array[3] = { 45, 67, 89 };
In C, in most places, the name array becomes a pointer to its first element.
Most usages of array are equivalent to if array had been declared as a pointer.
For example, if an array is passed to printf, the array name becomes a pointer:
printf ("%p\n", array);
prints the address of array[0].
#include <stdio.h>

int main()
{
int array[3] = {45, 67, 89};
printf ("%p\n", array);
printf ("%p\n", & array);
printf ("%p\n", & array[0]);
return 0;
prints out
0xbfbfd924
0xbfbfd924
0xbfbfd924

This is called decaying. Decaying is an implicit &. array == &array ==


&array[0]. These expressions are read array, pointer to array, and
pointer to the first element of array.
Q.1. The size of an int in bytes is architecture-dependent. Write an architectureindependent program to reverse an int array byte-wise (not element-wise).
#include <stdio.h>
void swap(char*, char*);
int main()
{
unsigned int wordSize, arrSize;
wordSize = sizeof(unsigned int);
scanf("%u", &arrSize);
unsigned int arr[arrSize] , i, j;
for (i = 0; i < arrSize; ++i)
scanf("%u", &arr[i]);
for (i = 0; i < arrSize; ++i)
printf("%u\t", arr[i]);
printf("\n");
for (j = 0; j < 2; ++j)
{
for (i = 0; i < (arrSize * wordSize) / 2; ++i)
swap((char*) &arr + i, (char*) &arr + (arrSize * wordSize) - i - 1);
for (i = 0; i < arrSize; ++i)
printf("%u\t", arr[i]);
}

printf("\n");

return 0;
}
void swap(char* src, char* dest)
{
*src ^= *dest;
*dest ^= *src;
*src ^= *dest;
}