MSC Cprog Study Guide Lec6 Pointers
MSC Cprog Study Guide Lec6 Pointers
Lecture 6. Pointers
The simple example below shows how an integer variable number can be
accessed through a pointer to it which is called p_number :
int number=10;
int* p_number=&number;
This example shows the use of the two operators that we use when
manipulating pointers –
p_number is said to “point to” number. Also, the “contents of” the
memory location (p_number) contain the value number. Both these
descriptions are interchangeably used when discussing pointers.
The “address of” (&) and “contents of” (*) operators are opposites of
each other:
Contents-of (*) operator
p_number number
Address -of (&) operator
6-1
Introduction to C Programming Lecture 6 - Pointers
It’s important to realize that pointers are variables just like any other
variable – they just store a 32-bit value which happens to be a memory
location. We can manipulate pointer variables just like any other variable.
The program below gives an example of this.
#include <stdio.h>
int main(void)
{
int number=10;
int* p_number=&number;
return 0;
}
Sample program output
10 268438072
11 268438076
This program prints out both the pointer value and the contents of the
memory location that the pointer points to. It also increments the pointer
value and its contents. As can be seen the value of the pointer is a fairly
meaningless value which is a 32-bit memory location. However, it can be
manipulated like any other variable. For example in this program, its
value is output and it has been incremented. Note that incrementing a
pointer, as we shall see, is a very useful operation for accessing arrays.
6-2
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
int main(void)
{
char c=’Q’;
char *p_c=&c;
return 0;
}
Q 268438069
Z 268438069
In this case, the value of the char variable c has been modified through
indirection of the char pointer variable p_c.
6-3
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
int main(void)
{
char my_string[10]="Hello";
char *p_c=&my_string[0]; /* Points to the first char */
printf("%c %d\n", *p_c, p_c);
Sample output:
H 703258592
e 703258593
f 703258593
To get from ‘H’ to ‘e’, we used p_c++ to jump to the second element.
Notice how the address has changed from “…92” to “…93”.
Then we used (*p_c++) to increment ‘e’. This results in ‘f’, but the
address is still the same (the second element, ‘…93’).
If we were now to print out the whole string my_string, we would get
“Hfllo”.
6-4
Introduction to C Programming Lecture 6 - Pointers
x[0] - same as *x
x[1] - same as *(x+1)
x[2] - same as *(x+2)
.
.
x[i] - same as *(x+i)
In other words, the variable (x+i) is a pointer to the ith array element and
hence *(x+i) is the array element x[i].
6-5
Introduction to C Programming Lecture 6 - Pointers
The example program below shows how an array can be accessed using a
pointer.
#include <stdio.h>
int main(void)
{
int x[5]={0,10,20,30,40};
int* xp=x;
int i;
return 0;
}
x[0]=0
x[1]=10
x[2]=20
x[3]=30
x[4]=40
In this program, the pointer to the array xp, initially points at the first
element. This is because of the assignment int* xp=x. The statement
inside the for loop, xp++ moves the pointer on one array element to the
right so that it points to the next element.
6-6
Introduction to C Programming Lecture 6 - Pointers
int main(void)
{
int x[5]={0,10,20,30,40};
int* left=x;
int* right=x+4;
int temp;
while (left<right)
{
temp=*left;
*left++=*right;
*right--=temp;
}
return 0;
}
In this case, the left and right pointers are initialized to point to the first
and last array elements as shown in the diagram. The left and right
pointers are then progressively moved right and left with the statements
*left++=*right and *right--=temp respectively.
left right
6-7
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
int main(void)
{
char source[20];
char dest[20];
char* p_s=source;
char* p_d=dest;
while (*p_s!=’\0’)
*p_d++=*p_s++;
*p_d=’\0’;
return 0;
}
As can be seen, the character pointers p_s and p_d are initialized to point
to the first elements of the source and destination strings respectively.
The actual string copy is carried out with the statement
*p_d++=*p_s++. It is important to look at this statement closely.
*p_s++ is interpreted as returning the value pointed to by the pointer p_s
followed by incrementing the pointer value. Note the difference between
this and (*p_s)++ which increments the contents of the location pointed
to by p_s.
The other small thing to note about this program is the use of the string
terminator ’\0’ in indicating the end of the string.
6-8
Introduction to C Programming Lecture 6 - Pointers
3. Multi-dimensional arrays
int a[3][5];
a[0]
[0,0] [0,1] [0,2] [0,3] [0,4]
a[1]
[1,0] [1,1] [1,2] [1,3] [1,4]
a[2]
[2,0] [2,1] [2,2] [2,3] [2,4]
So, for example, element a[1][2] is the 3rd element of the array pointer to
by a[1]. Here is a program which can output each of the elements of the
2-D array.
6-9
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
int main(void)
{
int a[][5]={{3,1,6,5,3},{7,2,5,7,1},{8,3,2,6,2}};
int row,col,val;
From the above diagram and what we know already about the relationship
between pointers and 1-dimensional arrays, we can see immediately that
a[0],a[1] and a[2] are pointers (in other words they are of type int*)
which are also (effectively) 1-D integer arrays.
int main(void)
{
int a[][5]={{3,1,6,5,3},{7,2,5,7,1},{8,3,2,6,2}};
int row,col,val;
int* p_row;
6 - 10
Introduction to C Programming Lecture 6 - Pointers
a[0][0] = 3
a[0][1] = 1
.
.
a[2][4] = 2
Another way to access each array element is to recognize the fact that the
elements are stored in row order as shown below.
[0,0] [0,1] [0,2] [0,3] [0,4] [1,0] [1,1] [1,2] [1,3] [1,4] [2,0] [2,1] [2,2] [2,3] [2,4]
#include <stdio.h>
int main(void)
{
int a[][5]={{3,1,6,5,3},{7,2,5,7,1},{8,3,2,6,2}};
int ele,val;
int* p=a[0];
return 0;
}
6 - 11
Introduction to C Programming Lecture 6 - Pointers
element 0 = 3
element 1 = 1
.
.
element 14 = 2
4. Pointer to a pointer
We have seen how we can access individual rows of our array a[][] using
the pointers a[0], a[1] and a[2]. Imagine that these 3 pointers,
themselves form an array as shown below. We can then set up a pointer to
point to this array of pointers. This will be a pointer to a pointer and is of
type int**.
int** p_a
a[0]
[0,0] [0,1] [0,2] [0,3] [0,4]
a[1]
[1,0] [1,1] [1,2] [1,3] [1,4]
a[2]
[2,0] [2,1] [2,2] [2,3] [2,4]
6 - 12
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
void increment(int n)
{
n++;
}
int main(void)
{
int number;
printf(“Input a number: ”);
scanf(“%d”,&number);
increment(number);
return 0;
Input a number : 5
The number now equals 5
6 - 13
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
void increment(int* n)
{
(*n)++;
}
int main(void)
{
int number;
printf(“Input a number: ”);
scanf(“%d”,&number);
increment(&number);
return 0;
Input a number : 5
The number now equals 6
In the main program, we take the address of the number when we pass
it to increment() in order to pass a pointer. Thus increment(&number)
is called.
6 - 14
Introduction to C Programming Lecture 6 - Pointers
1. number=5
function increment()
on entry
int* &number
2. number=6
main program
program
function increment()
on exit
int* &number
6 - 15
Introduction to C Programming Lecture 6 - Pointers
Consider the following program. This will swap two integers, e.g. two
elements of the array.
Notice the arguments of swap in the main program also need to be int *.
int main(void)
{
int i, array[]={10,20,30,40,50};
Program output:
20 10 30 40 50
In the next program, we set up two pointers in the main program so that
they are both pointing to the first element of two separate arrays.
We can swap these two pointers. This has the effect of swapping the two
arrays, but not swapping the elements within the array. However, the
swap function must now be redefined so that it is swapping two int *
6 - 16
Introduction to C Programming Lecture 6 - Pointers
int main(void)
{
int i, array_a[]={10,20,30,40,50}, array_b[]={60,70,80,90,100};
int *p_array_a = array_a;
int *p_array_b = array_b;
return 0;
}
Program output:
6 - 17
Introduction to C Programming Lecture 6 - Pointers
#include <stdio.h>
int main(void)
{
int array[]={0,1,2,3,4};
int i;
increment(array,5);
return 0;
}
array[0] = 0
array[1] = 1
.
.
array[4] = 4
6 - 18
Introduction to C Programming Lecture 6 - Pointers
array[0] = 1
array[1] = 2
.
.
array[4] = 5
6 - 19
Introduction to C Programming Lecture 6 - Pointers
calloc() and malloc() are functions which take arguments of type size_t.
This is an unsigned integer returned by the sizeof() function which is the
size (in bytes) of a data type. Thus size_of(int) would return 4 since an
integer normally occupies 4 bytes of memory. Also calloc() and malloc()
6 - 20
Introduction to C Programming Lecture 6 - Pointers
return a void* data type. This is a pointer which can be cast to any other
type of object pointer. Thus calloc() and malloc() return a pointer to the
area of memory allocated. This memory can be subsequently de-allocated
by a call to free() by using this pointer as the argument to free(). calloc()
and malloc() perform similar tasks. calloc() requires the number of
storage elements and the amount of memory allocated per element whilst
malloc() requires the total amount of memory to be allocated. The other
difference is that calloc() initializes the allocated memory to zero.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* ptr_array,i;
int length;
/* Allocate memory */
ptr_array = (int*)malloc(length*sizeof(int));
/* de-allocate memory */
free(ptr_array);
return 0;
}
}
6 - 21
Introduction to C Programming Lecture 6 - Pointers
int * ptr_array
The next example shows how a 2-d array can be allocated. This makes
use of the pointer-to-a-pointer idea which we met earlier. Essentially, we
allocate memory for the 1-d column array of pointers and then allocate
memory for each 1-d row array.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int** matrix;
int nrows,ncols,row,col;
The above program then has a 2-d array matrix which is dynamically
allocated. Note again that the return variable from malloc() has to be cast
to the correct type.
int** matrix
As can be seen from the program, the main advantage with this approach
over and above allocating the memory automatically is that the size of the
array is determined at run-time. In this simple example, the matrix size
depends on user inputted values. In contrast, using declaring the matrix
as an automatic variable such as int matrix[4][5] fixes the upper limit of
the size of the matrix which could be inconvenient or wasteful of
memory.
Note also the order of the free functions within the de_allocate function.
In C, 2d arrays must be freed in the reverse order they were created. So
we see that each row is freed, and then the whole 2d array variable is
freed. This is opposite to the order they were allocated.
6 - 23
Introduction to C Programming Lecture 6 - Pointers
return matrix;
}
int main(void)
{
int** matrix;
int nrows, ncols, row, col;
return 0;
}
6 - 24
Introduction to C Programming Lecture 6 - Pointers
There are 2 main pitfalls in dynamic memory allocation which cause run-
time errors in programs which are sometimes difficult to trace.
int* p;
int q=2;
p=(int*)(malloc(5*sizeof(int)));
p=&q; /*creates unreferenced memory */
Un-referenced
p q
6 - 25
Introduction to C Programming Lecture 6 - Pointers
void f(int* x)
{
…
free(x);
}
int main(void)
{
int i;
int* iarray=(int*)(malloc(5*sizeof(int)));
f(iarray); /* creates dangling pointer */
for (i=0; i<5; i++)
iarray[i]=0; /* accesses memory which
doesn’t exist */
return 0;
}
6 - 26