You are on page 1of 40

Pointers in C

Rohit Khokher

Pointers are Memory Addresses


Segment part Offset part

0x9FFF:000F
What does this number really mean?

Address 0x9FFF0 + 0x 000F = 0x9FFFF


655,359 (0 to 655,359) or
(1 to 655,360) or 1 to 640 Kb

0xFFFF:000F
0xFFFF0 + 0x 000F = 0xFFFFF
1 Mb = 1,048,576

Memory address space

Pointers are Memory Addresses


Pointers are variables that contain
A value between
memory addresses as their values.
0xFFFF0 + 0x 000F = 0xFFFFF

1 to 1,048,576

A variable name directly


references to a value (direct
Segment Offset
addressing).

A pointer indirectly references to a


value. Referencing a value
A pointer
points
through
a pointer
is called
to a memory
indirection
addressing).
location (indirect
that
0xFFFFF
contains the
data

0xFFFFF

456

Concept of Address and


Pointers
Memory can be
conceptualized as a
linear set of data
locations.
A variable refers to the
content of a locations Addre
ss
A pointer variable
space
holds the address of a
given location that
contains the data
value.

ADDR1
ADDR2
ADDR3
ADDR4
ADDR5
ADDR6
*
*
*

Contents

.
*
*
1048576

Contents

POINTERS DECLARATION
Examples of pointer declarations:
int *a;
float *b; What does float *b;
char *c; What does char *c;

mean
mean

The asterisk, in the declaration int *a;,


tells the compiler that the variable a is
a pointer type, meaning it contains an
address (pointer) of a memory location
address
that will contain an integer.
0xFFFFF

0xFFFFF
456

Conten
t/value

POINTERS
Consider the statements:

#include <stdio.h>
int main ( )
What is
{ the difference between int *aptr; and int a; declaratio
int *aptr ; /* Declare a pointer to an int */
float *bptr ; /* Declare a pointer to a float */
int a ; /* Declare an int variable */
float b ; /* Declare a float variable */
0xFFFFF
0xFFFFF

aptr = &a ;
bptr = &b ;

Assign the address of a to


the location at which aptr
is pointing to.

float x;

POINTERS

X is an address that would contain a float value

Remember! The content of the6.5


memory location referenced by a
pointer is obtained using the 0xFFFFF
``*''
operator (this
is called
px is a pointer
to objects of type
float meaning that it would contain
dereferencing
pointer).
an address ofthe
float type
object
the address of
Thus, *px refers to the Ifvalue
ofx
is 0xFFFFF then what
Store the address of x into px
would be assigned to
x which is 6.5.

float
*px;
x=

px?

POINTERS
We must associate a pointer to a
particular data type. For example, we
can't assign the address of a short int
0xFFFFF
0xFFFFE
to a long int. Why?

Int x = 1, y = 2;
Int *ip;
ip= &x;
y = *ip;
*ip= 3;

1
3

0xFFFFE

2
1

What is wrong with


float a, b;
Int x, * p;
p=&a;?

POINTERS
When a pointer is
declared it does not
point anywhere. We
must set it to point
somewhere before its
use. The statements
int*p;
*p = 10;
will generate an error.
Why?

int*p, *q, x, y;
p = &x;
q = &y;
*p = 10;
*q = 20;
p = q;
*p = *q;
10

20

You can see the addresses of the data


where in the memory they are loaded
{ char a; int b; float c;
a=n; b= 20; c= 20.5;
printf (%c is stored at address %u,\n,a,&a);
printf (%d is stored at address %u,\n,b,&b);
printf (%f is stored at address %u,\n,c,&c);
}

You can see the addresses of the data


where in the memory they are loaded
{ int x, y, *p;
X=10; p=&x; y=*p;
printf (value of x is %d is,\n,x);
printf (%d is stored at address %u,\n,x,&x);
printf (%d is stored at address %u,\n,*&x,&x);
printf (%d is stored at address %u,\n,*p,
p); address
Pinter
printf (%d is stored at address %u,\n, p, &p);
printf (%d is stored at address %u,\n,y, &y);
}

POINTERS
a=5;
b=6.75;
aptr = &a ;
bptr = &b ;
printf ("%d %d\n", aptr,
bptr ) ;
printf ("%d %f\n", *aptr, *bptr
);
printf ("%d %f\n",
a,
b);
printf ( "%d %d\n", &a , &b )
;
return 0 ;
}
}

1659178974 1659178976
5 6.750000
5 6.750000
1659178974 1659178976

POINTERS
double x = 3.14;
*p = &x;

3.14

Address of X

p will be 3.14
Set pointer value directly
double x; *p = &x;
*p = 3.14;
Make sure pointer has been set
to an
allocated memory region

Setting pointer value to


null
int *p = 0; int *p = NULL;
printf(%x,p);
Prints a hexadecimal number
the address that p points to

For a pointer p, ++p and p++ are both equivalent to p + 1

You can see the addresses of the data


where in the memory they are loaded
/*Program to illustrate the
pointer expression and pointer
printf(\n Address of a +%u, p1);
arithmetic*/
printf(\n Address of b %u, p2);
#include< stdio.h >
printf(\n a=%d, b=%d, a, b);
main()
printf(\n x=%d, y= %d, x, y);
{
p1=p1 + 70;
int *p1,*p2;
p2= p2;
int a, b, x, y, z;
printf(\n a=%d, b=%d,a,b);
a=30; b=6;
}
p1=&a; p2=&b;
Can Add or subtract integers from pointers.
x=*p1+ *p2 6;
Can subtract one pointer from the other.
y=6*- *p1/ *p2 +30; Can use operators with the pointers p1+=;
sum+=*p2; etc.,
Can use relational operators the expressions
such as p1 >p2 , p1==p2 and p1!=p2

Arithmetic and Logical Operations


on Pointers
A pointer may be incremented or
decremented
An integer may be added to or
subtracted from a pointer.
Pointer variables may be subtracted
from one another.
Pointer variables can be used in
comparisons, but usually only in a
comparison to NULL.

Arithmetic Operations on
Pointers
When an integer is added to or subtracted
from a pointer, the new pointer value is
changed by the integer times the number
of bytes in the data variable the pointer is
pointing to. For example, if the pointer
valptr contains the address of a double
precision variable and that address is
8 bytes
234567870, then the statement:
234567870 + 2 x 8
valptr = valptr + 2;
would change valptr to 234567886

Review

A variable is declared as int k;


A pointer variable is declared as int *p;
we can get the address of a declared variable
by using the unary & operator as in &k.
We can "dereference" a pointer, i.e. refer to the
value of that which it points to, by using the
unary '*' operator as in *ptr.
Pointer operators: * dereferences a pointer, &
creates a pointer (reference to)
An "lvalue" of a variable is the value of its
address, i.e. where it is stored in memory. The
"rvalue" of a variable is the value stored in
that variable (at that address).

Pointers to Referencing &


Derefrencing

nt x, *y, z, *q;
= 3;
= &x;
// y points to x

printf("%d\n", x);

// outputs 3

printf("%d\n", y);

// outputs xs address, will seem like a random number to

printf("%d\n", *y);

// outputs what y points to, or x (3)

printf("%d\n", *y+1);

// outputs 4 (print out what y points to + 1)

printf("%d\n", *(y+1)); // this outputs the item after x in memory what is it?
= *(&x);

q = &*y;

// z equals 3 (what &x points to, which is x)


// q points to 3 note *& and &* cancel out

Pointers to Arrays
int x = 1, y = 2, z[10];
int *ip;
// ip is a pointer to an int, so it can point to x, y, or an
element of z

ip = &x;

// ip now points at the location where x is stored

y = *ip;

// set y equal to the value pointed to by ip, or y = x

*ip = 0;
=0

// now change the value that ip points to to 0, so now x

You can interact with the


array
elements
either
ip = &z[0]; // now
ip points
at the first location
in the array z
through pointers or by using
index]
*ip = *ip + 1; z[
// the
value that ip points to (z[0]) is incremented
//

but notice that y is unchanged

Using Pointers with Arrays

ip = &z[0]; sets pointer ip to


point at the first element of
the array
Using &z[0],ip = &z[0] or z
are the samethey all hold
the address of first element of
an array.
In fact, z is a pointer as
well and we can access
z[0] either using z[0], *ip,
or *z
What about accessing z[1]?
We can do z[1] as usual, or
we can add 1 to the
location pointed to by ip or
z, that is *(ip+1) or *(z+1)
While we can reset ip to
be ip = ip+1, we cannot
reset z to be z = z+1
adding 1 to ip will point
to z[1], but if z = z + 1

Notice that ip=ip+1 (or


ip++) moves the pointer
4 bytes instead of 1 to
point at the next array
location

if the array were an array


of doubles, the increment
would move ip to point 8
bytes away, if the array
were chars, then ip would
be 1 byte further

Increment depends on the size


(in bytes) of the object to which
a pointer is pointing at.

Iterating Through the


Array
Here we see two ways
to iterate through an array,
the usual way, but also a method using pointer
arithmetic
int j;
int *pj;
for(j = 0; j < n; j++)
a[j]++;

for(pj = a; pj < a + n; pj++)


(*pj)++;

Lets consider the code on the right:


pj is a pointer to an int
We start with pj pointing at a, that is, pj points to a[0]
The loop iterates while pj < a + n

pj is a pointer, so it is an address
a is a pointer to the beginning of an array of n elements so a + n is the size of the array
pj++ increments the pointer to point at the next element in the array
The instruction (*pj)++ says take what pj points to and increment it

NOTE: (*pj)++; increments what pj points to, *(pj++); increments the pointer to
point at the next array element
what do each of these do?

*pj++;

++*pj;

Array Example Using a


Pointer
int x[4] = {12, 20, 39, 43},
*y;
y = &x[0];
// y points to
the beginning of the array
printf("%d\n", x[0]);// outputs
12
printf("%d\n", *y);
// also
outputs 12
printf("%d\n", *y+1); //

Strings
There is no string type in C, strings are arrays of
chars

char str[10]; // str is an array of 10 chars or a string


char *str;
// str points to the beginning of a string of
unspecified length

There is a string.h library with numerous string


functions
they all operate on arrays of chars and include:

strcpy(s1, s2) copies s2 into s1 (including \0 as last char)


strncpy(s1, s2, n) same but only copies up to n chars of s2
strcmp(s1, s2) returns a negative int if s1 < s2, 0 if s1 = =
s2 and a positive int if s1 > s2
strncmp(s1, s2, n) same but only compares up to n chars
strcat(s1, s2) concatenates s2 onto s1 (this changes s1, but
not s2)
strncat(s1, s2, n) same but only concatenates up to n
chars
strlen(s1) returns the integer length of s1
strchr(s1, ch) return a pointer to the first occurrence of ch
in s1 (or NULL if ch is not present)
strrchr(s1, ch) same but the pointer points to the last
occurrence of ch

Implementing Some of
These
int strlen(char *s)
int strcmp(char *s, char *t) void strcpy(char *s, char

*t)
{
int n;
int i;
int i = 0;
for(n = 0; *s != \0; s++) for(i=0;s[i] = = t[i];i++)
while((s[i] = t[i]) !=
n++;
if(s[i] = = \0)
\0)
return n;
return 0;
i++;} strcpy(s1, s2)
}
return s[i] t[i];
strlen(s1)
}
strcmp(s1, s2) }
void strcpy(char *s, char *t)
int strcmp(char *s, char *t) {
while((*s = *t) != \0)
{
for( ; *s = = *t; s++, t++) {
Notice in the second
if(*s = = \0) return 0; s++; t++;
strcmp and second and return *s - *t;
}
third strcpy the
strcmp(s1, s2)}
strccpy(s1, s2)
}
use of pointers to iterate
void strcpy(char *s,
through the strings.
Check it
char *t)
The conciseness of the
copies t[i]
{
last strcmp and strcpy
into s[i] and
while((*s++
= *t+ s2)
strcpy(s1,
make them hard to
checks for
+) != \0);
understand
NULL
}

More On Pointer
Arithmetic
Got to the

We can also perform


first subtraction on pointers
Start with
the 10th
element

element
int a[10] = {};
int *ip;
for(ip = &a[9]; ip >= a; ip--)
wepass to a function

Decrease
pointer by
1

Here,
the address of the
third element of an array (&a[2]) and use
pointer subtraction
get to a[0] and a[1])Functio
ip = to
&a[2];
int a[3] = {};
printf(%d, addem(&a[2]));
Recall:
a[0] = *a and
a[i] = *(a + i)

int addem(int *ip)


{
int temp;
temp = *ip + *(ip 1)
return temp;
}

ns
addme
m
+ *(ip 2);

If a is an array, and p = &a[0] then we can reference array


elements as a[i], *(p+i), but we can also reference them as
p[i] and *(a+i) that is, a and p are both pointers to the arra
And can be dereferenced by * or by [ ]

Multidimensional Arrays
C allows multidimensional arrays
Example: int matrix[5][10 ];
Some differences:
Because functions can be compiled separately, we must denote all but
one dimension of a multiple dimensional array in a functions parameter
list
void afunction (int amatrix[ ][10]);

Because arrays are referenced through pointers, there are multiple ways
to declare and access 2+ dimensional arrays
This will be more relevant when dealing with an array of strings (which is a 2D array)

int *a[3];
// array of 3 pointers
int x[2] = {1, 2};
int a[10][20];
int y[3] = {3, 4, 5};
int *a[10];
int z[4] = {6, 7, 8, 9};
int **a;
*a = &x[0]; // a[0] points to x[0]
*a[4] first element of 5th array element *(a+1) = &y[0];// a[1] points to y[0]
*a[9] first element of 10th array element*(a+2) = &z[0];// a[2] points to z[0]
// array a is a jagged array, it is not
**a first element of a[0]
// rectangular, or of equal dimensions

Pointers to Pointers
As indicated in the last slide, we can
have an array of arrays which is really
an array of pointers or pointers to
pointers

We may wish to use pointers to pointers


outside of arrays as well, although it is more
common that pointers to pointers represent
array of pointers
int
a;Consider
Wethe
dereference
our pointer p with *p but we dereference
following:
int *p;
our pointer to a pointer q with **q
int **q;
a = 10;
10
*q is actually p, so **q is a
p = &a;
q = &p;
Address of
printf(%d, **q);
// outputs 10
a
Address of
p

Arrays of Strings
Implementation

We could implement an array of strings as a 2-D


array of chars
char array[10][10];

This has two disadvantages


All strings will be 10 chars long
Requires 2 nested for-loops for most operations such as
string comparison or string copying, which can become
complicated

Instead, we will implement our array of strings as an


array of pointers
char *array[10];

Each pointer points to one string


Follow the string through the pointer
Go to the next string using a for-loop
Because strcpy, strcmp, strlen all expect pointers, we can

Example

r *x[ ] = {"hello\0", "goodbye\0", "so long\0", "thanks \0"};


// our array of strings x is a set of 4 pointers
r *y;// let y be a pointer to a char so it can be used to move through a single stri
;
i=0;i<4;i++)
// iterate for each string in x

y = x[i];
// x[i] is an array, x is really a pointer, so this sets y to xs starting ad
while(*y!='\0') // while the thing y points to is not the end of a string
{
printf("%c", *y);
// print whatX[0]
y pointshello
to
NUL
y++;
// and go on to the next char in x L
}
X[1]
goodby NUL
printf("\n");
// separate strings in output
with \n
e
L
X[2]

So long

NUL
L

X[3]
NUL the storage
Notice that if we had used char
x[ ][ ]thanks
= {}; then
L
space would have been 4 strings of length 23 (the
length of the
longest string) or 92 bytes instead of 42 bytes as it is above

Passing Arrays
Because you can
When an array is
passed to a function,
what is being passed
is a pointer to the
array

compile functions
separately, the compiler
must be able to know
about an array being
passed in to a function,
so you must specify all
(or most) of the
definition:

In the formal
parameter list, you
can either specify the
parameter as an array
The type and all
int array[100];
or a pointer
dimensions except for the
int array[5][10][15];

first

afunction(array);

void afunction(int *a) {}


or
void afunction(int a[ ]) {}

afunction(array);

void afunction(int
void afunction(int
void afunction(int
void afunction(int

a[ ][10][15]) {}
*a[10][15]) {}
a[5][10][15]) {}
**a[15]) {}

or
or
or
etc

Some Additional
In functions, doComments
not return p; where p is a pointer
Recall local variables are deallocated when the function
ends
so whatever p is pointing to will no longer be available
but if you return the pointer, then you still are pointing at that
memory location even though you no longer know what is there

We can declare a pointer to point to a void type,


which means that the pointer can point to any type
However, this does require a cast before the pointer can
be assigned
int x; float y; void *p; // p can point to either x or y
p = (int *) &x; // p can point to int x once the address is cast
p = (float *) &y; // or p can point to float y

Pointers that dont currently point to anything have


the special value NULL and can be tested as (p =
= NULL) or (!p), and (p != NULL) or (p)

Pointers and Structures

struct tag {
char lname[20]; /* last name */
char fname[20]; /* first name */
int age; /* age */
float rate; /* e.g. 12.75 per hour */
};
struct tag my_struct; /* declare the
structure my_struct */
It will copy the last
int main(void)
name and the first
name into the
{
structure
strcpy(my_struct.lname,"Jensen");
strcpy(my_struct.fname,"Ted");Passing structure takes
more memory (stack
printf("\n%s ",my_struct.fname);
space) , aThe pointer uses
printf("%s\n",my_struct.lname);
a minimum amount of
return 0;
stack space.
}

Pointers and Structures


struct tag{
/* the structure type */
char lname[20];
/* last name */
char fname[20];
/* first name */
Int age;
/* age */
float rate;
/* e.g. 12.75 per hour */
};
struct tag my_struct;
/* define the structure */
void show_name(struct tag *p);
/* function
prototype */
int main(void)
{
struct tag *st_ptr;
/* a pointer to a structure */
st_ptr = &my_struct;
/* point the pointer to
void show_name(struct tag *p)
my_struct */
{
strcpy(my_struct.lname,"Jensen");
printf("\n%s ", p->fname); /* p
strcpy(my_struct.fname,"Ted");
points to a structure */
printf("\n%s ",my_struct.fname);
printf("%s ", p->lname);
printf("%s\n",my_struct.lname);
printf("%d\n", p->age);
my_struct.age = 63;

Pointers and Structures


struct tag{
/* the structure type */
char lname[20];
/* last name */
char fname[20];
/* first name */
Int age;
/* age */
float rate;
/* e.g. 12.75 per hour */
};
struct tag my_struct;
/* define the structure */
struct tag *st_ptr;
st_ptr = &my_struct;
Access a member by
de-referencing the
pointer.
(*st_ptr).age = 63; OR
st_ptr -> age = 63;

An instance of
tag in memory,
also called
instantiation
Address of my
struct

Lname
[20
Fname
[20]
age
rate

Pointers to Functions
A function that is capable of sorting
virtually any collection of data that
can be stored in an array.
The data might be an array of
strings, or integers, or floats, or even
structures. The sorting algorithm can
be the same for all.

Pointers to Functions
int arr[10] =
{ 3,6,1,2,3,8,4,1,7,2};

void bubble(int a[], int N)


{
int i, j, t;
for (i = N-1; i >= 0; i--)
{
for (j = 1; j <= i; j++)
{
if (a[j-1] > a[j])
{
t = a[j-1];
a[j-1] = a[j];
a[j] = t;
}
}
}
}

void bubble(int a[], int N);


int main(void)
{
int i;
putchar('\n');
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
bubble(arr,10);
putchar('\n');
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
SORTING AN ARRAY OF INTEGERS
return 0;
}

Pointers to Functions
void bubble(int *p, int N)
int arr[10] = { 3,6,1,2,3,8,4,1,7,2}; {
int i, j, t;
void bubble(int *p, int N);
for (i = N-1; i >= 0; i--)
int compare(int *m, int *n);
{
int main(void)
for (j = 1; j <= i; j++)
{ int i;
{ if (compare(&p[j-1],
for (i = 0; i < 10; i++)
&p[j]))
{
printf("%d ", arr[i]);
{
}
t = p[j-1];
bubble(arr,10);
p[j-1] = p[j];
for (i = 0; i < 10; i++)
p[j] = t;
{ printf("%d ", arr[i]);
}
}
m=&p[j-1],
}
return 0;
}
}
n=&p[j],
}
int compare(int *m, int *n)
SORTING AN ARRAY OF
{
INTEGERS BUT IN THIS
return (*m > *n);
COMPARISON Is DONE BY
}
A FUNCTION

Pointers to Functions
void bubble(int *p, int N)
int arr[10] =
{ int i, j, t;
{ 3,6,1,2,3,8,4,1,7,2};
void bubble(int *p, int N); for (i = N-1; i >= 0; i--)
{ for (j = 1; j <= i; j++)
int compare(void *m, void
{ if (compare((void *)&p[j-1],
*n);
(void *)&p[j]))
int main(void)
{
{
t = p[j-1];
int i;
p[j-1] = p[j];
for (i = 0; i < 10; i++)
p[j] = t;
{ printf("%d ", arr[i]); }
}
bubble(arr,10);
}
for (i = 0; i < 10; i++)
{ printf("%d
arr[i]);
}
Bubble
sort or",any
program
can }
return
0; general by identifying }
be
made
int compare(void *m, void *n)
}
the code that can be made
{
general. For example by making
int *m1, *n1;
the compare function or
m1 = (int *)m;
swapping operations general the
n1 = (int *)n;
same bubble sort can be used
return (*m1 > *n1);}

Pointers to a Function

Remember the difference


The function name translates into an address of that function in
the code segment.
Declaration like int (*fptr)(const void *p1, const void
*p2); indicates that we are declaring a function
Passpointer.
a pointer to a
function as a
parameter
Declaration int *fptr (const void *p1, const
void *p2);
indicates that we are declaring a function that will return a
pointer
to an integer
type.
void bubble(void
*p, int
width, int N, int(*fptr)(const void *,
const void *));
compare_string(const
void *m,
int compare_string(const void *m, const int
void
*n);
const
void *n)
int compare_long(const void *m, const void
*n);
{ char *m1 = (char *)m;
Int main (void){ /* in the caller origramchar
*/ *n1 = (char *)n;
return (strcmp(m1,n1)); }
.
bubble(arr, 4, 10, compare_long); /* sort the
longs */
int compare_long(const void *m,
bubble(arr2, 20, 5, compare_string); const void *n)
{ long *m1, *n1;
.
m1 = (long *)m;
}
n1 = (long *)n;
return (*m1 > *n1); }

Pointers and Dynamic Allocation of


Memory
What is run time allocation?What is compile time allocation?
Allocate memory at run time using
malloc(), calloc()
int *iptr;
iptr = (int *) malloc(10 * sizeof
(int));
if (iptr == NULL)
Access the
{ . Error.}
allocated
for (k = 0; k < 10; k++)
locations
Iptr [k] = 2;
#define COLS 5
typedef int RowArray[COLS];
RowArray *rptr;
int main(void)
{ int nrows = 10; int row, col;
rptr = malloc(nrows * COLS *
sizeof(int));
for (row = 0; row < nrows; row++)
{ for (col = 0; col < COLS; col++)

Return a pointer to the


first byte of the
allocated block. The
ANSI compiler return
void type pointer
Allocates 10 memory
locations to store the 10
integers.

Explain

You might also like