Pointers
*, &, array similarities, functions, sizeof
Review of Variables
Since variables are used to hold a value which can change, the
compiler uses the computer’s memory as the storage area.
When the variable is declared, the compiler allocates enough space
in the memory for the data type and the variable name is used to
refer to the contents of the memory.
Reserves memory
int total ;
Refers to the memory
Review of Variables
The type in the declaration statement tells the compiler how much memory to
allocate to the variable. The char data type requires 1 byte, all other data types
require more than 1 byte.
eg
Here the compiler reads int and allocates 2 bytes in the memory for the
integer.
The variable name in the declaration is used as a reference to the
contents of the memory just allocated.
Since the variable is created in the memory, it must have an address
associated with it. If the variable requires more than one byte in the memory
then the address used is the address of the first data byte.
Whenever the variable is used, the program goes to the address of the variable
and accesses the contents.
The addressing is handled automatically by the compiler. As far as the
programmer is concerned the variable’s name is the value of the variable.
Review of Variables
A variable has an address and contents. They are usually drawn with
the address on the left and the variable contents in a box on the right,
as shown below.
•variable address
lvalue
variable value
rvalue
The variable’s address is called the lvalue because it appears on the
left hand side.
The variable contents is called the rvalue because it appears on the
right hand side.
Note
GCC uses lvalue and rvalue in its compiler errors and warnings.
Address Operator (&)
The address operator is &.
& means the address of.
The address of a variable can be found by using the address operator
(&) in front of the variable’s name.
eg
&counter means the address of counter. This is the address of the
memory allocated to the variable counter.
If
the variable is not a char, then the address is the address of the first
byte allocated. An int requires 4 bytes, the address of an int is the
address of the first byte in the memory.
Variables that hold addresses (pointers)
The address of a variable is just data. Data can be stored in the
memory. Therefore it is possible to have a special variable that just
holds addresses.
A special variable called a pointer is used to hold addresses. It is
called a pointer because it holds a value which points to a memory
address.
A pointer is a variable that is used to store the address of other
variables.
A pointer is always associated with a data type. This is because an
address just refers to the memory, it does not give an indication of how
many bytes to access. The data type tells the compiler how many bytes
to read or write starting at the address held in the pointer.
Declaring pointers
Like any variable pointers must be declared before they are used.
All pointers are declared with a * in front of the variable name.
syntax
type *pointer_name ;
where
type is the data type of the value to which the pointer points.
* means the variable is a pointer.
pointer_name is the name of the pointer variable.
Declaring pointers
Examples of declaring pointers
int *p ; This declares a variable (pointer) called p which will hold an address.
char *c, *ch ;
float *v ;
Using Pointers
&
*
Address of operator (address of variable)
Contents of address pointed to (read/write memory)
The & operator gets the address of a variable.
The * operator means access the variable whose address is held in the
pointer.
The * operator gets the address held in the pointer and accesses the
memory location pointed to by the address.
Using Pointers
The * operator on the left hand side of an equate (=) means write to
the variable whose address is held in the pointer.
For example
*p = 23 ; /* write 23 to the memory given by the address in p */
The * operator on the right hand side of an equate (=) means read
from the variable whose address is held in the pointer.
For example
b = *p ; /* read the contents of memory given by the address in p
to b */
and assigns it
Using Pointers
Example to illustrate pointers. This sets a to 5 and b to 5.
int
{
main(void)
int a, b ;
int *p1, *p2 ;
a = 77 ;
b = 222 ;
p1 = &a ;
p2 = &b ;
/* declare variables */
/* declare pointers */
/* assign a to be 77 */
/* assign b to be 222 */
/* set p1 to the address of variable a */
/* set p2 to the address of variable b */
// set contents of the memory referred to by p1 to 5 ( ie a)
*p1=5;
// set b to the contents of the memory referred to by p1 ( ie b)
b = *p1 ;
}
Using Pointers
Example Explained
Code:
int a, b ;
int *p1, *p2 ;
Memory:
Address
1000
1002
1004
1008
/* variables */
/* pointers */
Contents
00
00
00
00
Variable name
a
b
p1
p2
Comments
The variables are declared, which means that they are allocated
space in the memory. Assume that the compiler allocates the
addresses shown.
Using Pointers
Example Explained
Code:
a = 77 ;
b = 222 ;
Memory
/* assign a to 77 */
/* assign b to 222 */
Address
1000
1002
1004
1008
Contents
77
222
00
00
Variable name
a
b
p1
p2
Comment:
The values are written to the variables. The contents of memory
location 1000 is 77 because the memory allocated for a is at
address 1000.
Using Pointers
Example Explained
Code:
p1 = &a ; /* set p1 to the address of variable a */
p2 = &b ; /* set p2 to the address of variable b */
Memory:
Address
Contents
Variable name
1000
77
a
1002
222
b
1004
1000
p1
1008
1002
p2
Comment:
The pointer p1 gets the address of a. The address of a is 1000,
which means that 1000 is stored in p1. The pointer p2 gets the
address of b. The address of b is 1002, which means that 1002 is
stored in p2.
Using Pointers
Example Explained
Code:
*p1 = 5 ;
Memory:
Address
1000
1002
1004
1008
Contents
5
222
1000
1002
Variable name
a
b
p1
p2
Comment:
The * means access the variable pointed to by the pointer p1. The pointer
holds address 1000. The pointer type is an int which means that address
1000 is treated like it is an integer variable. Therefore the value 5 is
written to the integer at address 1000. (i.e the two bytes forming the
integer at address 1000 and 1001 are written to).
Using Pointers
Example Explained
Code:
b = *p1 ;
Memory:
Address
1000
1002
1004
1008
Contents
5
5
1000
1002
Variable name
a
b
p1
p2
Comment:
The variable b is a normal variable and is expecting the result of *p1. The *
means access the variable pointed to by the pointer p1. The pointer holds
address 1000. The pointer type is an int which means that address 1000
is treated like it is an integer variable. Therefore the value of the integer at
address 1000 is read and placed into b. Since the contents of 1000 is 5
then b is set to 5.
NULL pointer
The NULL pointer is a pointer that contains the value NULL. The value
of NULL is 0 and the word NULL is a #define in <stdio.h>.
A NULL pointer is used to indicates that a variable does not point to
any valid data or that an error has occurred in a function that returns a
pointer.
Do not use the * pointer operator with NULL. This will access address
0. This can cause the program to crash.
Call By Reference
The most common use of pointers is to pass a variable into a function
to allow that function to manipulate the data in the variable.
A function is made up of the function name and the parameter list.
i.e
type function_name(parameter_list).
The parameter_list consists of a list of the variables being passed to
the function.
Call By Reference
In a normal operation, the function receives values from its calling
function, stores these values as its own local variables, performs the
action of the function, and then returns a single value. Changing the
value of the variable does not affect the calling variable. This is called
call by value because only the values (contents) of the variables are
being passed to the function.
For example
y = sin(x) ;
The sin() function reads the value of x, performs an algorithm to find
out the sine of the value, and returns the sine value back. The
value of x is not changed.
Call By Reference
To alter one of the variables in the parameter list when we call the
function, the address of the variable must be used. The function
receives the address from the calling function, stores this in its own
local variable and performs the action of the function.
Since we have the address of the parameter used when calling the
function, we can change the contents of that variable directly.
This means that the function has direct access to the variable that
referred to when calling the function.
This is called call by reference because we are referring to the memory
location of the variables by its address.
Call By Reference
void fn(int *) ;
int main(void)
{
int a ;
fn(&a) ;
Variable a is given a memory location
eg 0x5000
Passing the address of variable a.
ie 0x5000
return 0 ;
}
void fn( int *val)
{
*val = 5 ;
}
val is set to the address of variable a.
ie 0x5000
This changes the contents of the
memory pointed to by val to be 5.
ie changes contents of a to be 5
since val points to the memory
address that is used for a
Call By Reference
An Example
scanf("%i",&x) ;
scanf() is a function.
The values in the parenthesis are the parameters passed to the
function.
Here we want the scanf() function to read in an integer from the
keyboard and place the result into the variable x.
A normal function cannot alter the x variable, therefore the x has to
be passed as an address.
Since the address of the x variable is passed to the scanf()
function then the function has direct access to the memory
location used to store the contents of x.
When the function reads in an integer from the keyboard, it writes
the value to the memory at the address given, which alters the x
variable.
Pointers and Arrays
Pointers refer to the address of a variable.
Arrays consist of consecutive elements of the same type for example
int numbers[3] consists of three integers. Assuming ints are two bytes
in this example.
Base Address
Addr
1000
1002
1004
Value
5
99
-1024
Element
numbers[0]
numbers[1]
numbers[2]
The array in the memory, showing the consecutive elements and their addresses.
Pointers and Arrays
Each element in the array appears like a variable of the given data type
except that each element in the array is referred to using an index.
For
example in the array
int numbers[3] ;
numbers[0] is an integer variable and can be used wherever and in
the same way that an int is used.
eg
numbers[0]++ ;
numbers[0] % 2 ;
scanf(“%i”,&numbers[0]) ;
Pointers and Arrays
Pointers can be used to refer to the address of array elements.
For example
&numbers[i] ; is the address of the ith element of numbers
The
base address of an array is the starting address of the array i.e. &array[0].
The
name of the array without any [ ] refers to the base address of the array. In
the numbers example, the base address is &numbers[0] which is address 1000.
address of the ith element is
address = base + i * sizeof(data_type)
where sizeof(data_type) is the number of bytes required to store the data type
of the array. (char = 1, int = 4, float = 4, double = 8)
The
Pointers and Arrays
Example
In an array declared as int numbers[3] ;
Base Address
The
Addr
1000
1002
1004
Value
5
99
-1024
Element
numbers[0]
numbers[1]
numbers[2]
address of
element 0: 1000 + (0 * 2) = 1000
element 1: 1000 + (1 * 2) = 1002
element 2: 1000 + (2 * 2) = 1004
Pointers and Arrays
The contents of the pointer can be accessed using the *
Example
int
int
p =
p =
numbers[3] = {5, 99, -1024} ;
/* declare array */
*p ;
/* declare pointer */
numbers ;
/* point to start of array */
p + 2; /* point to element 2 */
/* see pointer arithmetic later in slides */
printf("%i",*p) ; /* print out element */
p is pointing to element 2 in the array.
ie p = &numbers[2].
The value printed out will be -1024.
Passing arrays to functions
To pass an array to a function, you pass the base address of the array.
For example
Passing String string1
into function strcpy.
char string1[80] = “hello”, string2[80] ;
strcpy(string1, string2) ;
float prices[10] ;
total(prices) ;
Passing String string2
into function strcpy.
Passing Array prices into function total.
Function prototypes using arrays
The array being passed is a pointer to the first element of the array.
In the function definitions, the array can be declared in the parameter
list in two ways
void search(int array[ ], int search_value) ;
void search(int *array, int search_value) ;
The two methods are the same. Both pass the array through to the
function and the array can be accessed in the same way.
Pointer Arithmetic
The process of applying addition and subtraction to pointers is
called pointer arithmetic.
p + k is always &array[k].
when
p = pointer containing the base address of the array.
k = integer representing the number of elements.
p - k is always &array[-k].
when
p = pointer containing the base address of the array.
k = integer representing the number of elements.
Pointer Addition
Adding k is the same as moving k elements forwards in the array
Assuming the elements in the following array are short int then
p
Addr
1000
1002
1004
Value
5
99
-1024
Ele ment
numbers[0]
numbers[1]
numbers[2]
p+0
p+1
p+2
Pointer Addition
If you add an integer k to the base address of an array then the resultant
address is the address of the element at index k in the array.
eg
int
int
p =
p =
numbers[3] ;
// declare the array
*p ;
// declare the pointer
numbers ; // set the pointer to the start of the array
p + 2 ;
// pointer is now at &numbers[2]
The numbers array is declared, for example given earlier the base
address is 1000.
p is set to point to the base address of numbers. p = 1000
p = p + 2 gives
1000 + (2 x sizeof(short int) )
1000 + (2 x 2)
1004
Now p is at the address of numbers[2]. ie p = &numbers[2].
Pointer Subtraction
Subtracting k is the same as moving k elements backwards in the
array
Assuming the elements in the following array are short int then
q
Addr
1000
1002
1004
Value
5
99
-1024
Ele ment
numbers[0]
numbers[1]
numbers[2]
q-2
q-1
q+0
Pointer Subtraction
If you subtract an integer k from an address of an array element (p) then the
resultant address is the address of the element located k elements before p .
eg
int
int
p =
p =
numbers[3] ;
// declare the array
*p ;
// declare the pointer
&numbers[2] ; // set the pointer to the 3rd element
p - 2 ;
// pointer is now at &numbers[0]
The numbers array is declared, for example given earlier the base address is
1000.
p is set to point to the 3rd element . p = 1004
p = p - 2 gives
1004 - (2 x sizeof(short int) )
1004 - (2 x 2)
1000
Now p is at the address of numbers[0]. ie p = &numbers[0].
Pointer Increment and Decrement
The increment operator ++ and decrement operator -- can be
used on pointers. These just move the pointer up or down by one
element.
This is the same as adding 1 to the pointer and subtracting 1 from
the pointer.
The postfix form for the operator is *p++ ;
This means read the contents of the address pointed to by p, and
then add 1 to p.
The prefix form for the operator is *++p ;
This means add 1 to p, and then read the contents of the address
pointed to by p.
Pointers
Common Mistakes
The most common mistake in using pointers is to declare a pointer but
not set its value to point to a variable already declared.
When you declare a variable, the compiler allocates enough space for
the variable. When you declare a pointer, then the compiler allocates
enough space to hold an address. Therefore, if you use a pointer
without initialising it to the address of a variable that has already been
declared (allocated space by the compiler), then you will be trying to
access unallocated memory. This can result in the data being
destroyed.
Declaring the pointer does not allocate the space for the memory you
are trying to access.
SIZEOF operator
The sizeof operator evaluates to the size of the data type used as the
operand.
syntax:
sizeof( expression )
where
expression is a valid variable, or data type.
Examples
sizeof(char) will return the size in bytes of a char. (1)
sizeof(int) will return the size in bytes of an int (4)
sizeof(x) will return the size in bytes of variable x.
sizeof(char [3]) will return the size in bytes of the array. (3 x 1)
sizeof(string) will return the size in bytes of the char array.
SIZEOF operator
Note:
sizeof() is not a function, it is an operator with a high precedence.
The precedence is the same as ++, --, !, ~, & (address), *
(dereference).
Example Programs
Example 1
Program to swap two floating point numbers
#include <stdio.h>
#include <stdlib.h>
/* prototype */
void swapfloats(float *, float *) ;
int main(void)
{
float first=2, second=1;
swapfloats(&first,&second); // Note the 'address-of' operators
printf("%g %g\n", first, second);
}
Example Programs
Example 1 (continued)
/* function to swap two floats */
void swapfloats(float *a, float *b)
{
float temp; // This is still float, because we are swapping floats
temp = *a; /* Note the '*'s - get the float pointed to by a. */
/* Copy the float b points at into the variable a points at*/
*a = *b;
/* Copy the float in temp into the variable b points at. */
*b = temp;
}
Example Programs
Example 2
Program to print out the characters in a string.
#include <stdio.h>
#include <stdlib.h>
/* prototype */
void print_str(char *) ;
int main(void)
{
char
string[20] = "Hello" ;
/* Note: string is the address of the start of the
print_str(string);
}
array */
Example Programs
Example 2 (Continued)
/* function to print out the string */
void print_str(char *str)
{
Str originally points to the
start of the string.
/* read through each char until end of string ‘\0’ */
while ( *str != ‘\0’)
{
/* print out the character */
putchar(*str) ;
/* move to next element */
str++ ;
}
}
str now points to the next
location. The next character
in the string.
Value at the location
that str points to is
checked.
The character at the
location that str refers to
is printed.
© Copyright 2026 Paperzz