Pointers
A pointer is a variable whose value is the address of some value.
The declaration looks as follows:
float *my_pointer
The pointer is defined by the type of the value that it points to. This is helpful, because:
- we can do various arithmetic operations on pointers (e.g.
++
will result in the correct amount of bytes being added). - we can dereference pointers - the runtime needs to know how many bytes a given
pointer points to and how to interpret them (e.g.
int
andfloat
both take 4 bytes, but the same contents mean different values)
The “star” sign may be placed adjacent to the type, or to the name, or both:
int *pointer;int* pointer2;int*pointer3;
Use-cases
Pointers are useful for:
- passing data to functions by reference (e.g.
void increment(int *number)
) - allocating memory on the heap and keeping reference to it
Memory
Memory is organized as follows:

Each slot is addressed.
A pointer stores an address to some value in memory:

The pointer itself also has an address in memory, it also is some variable.
In the case above, &p
is 64
.
Variables
When we define some variable, it will be assigned some address in memory. If we try to print the value under that address, we will find some “random” data:
int variable;int *pointer = &variable;printf("%d", *pointer); // 0 or some other trash value
Usage
int number = 10;int *pointer;
pointer = &number; // address where value 10 is stored
// Dereferencingint number_copy = *pointer; // returns the value stored under the address that the pointer contains
*pointer = 20; //updates the value of the `number` variable
Arrays
An array can be treated as a pointer to the first element that it contains.
int array[] = {1, 2, 3};
int *pointer = array; // same as &array[0]
printf("Address of array[0] = %x\n", pointer);printf("Value of array[0] = %x\n", *pointer);
pointer++;
printf("Address of array[1] = %x\n", pointer);printf("Value of array[1] = %x\n", *pointer);
Simply:
- address:
&array[i]
=array + i
=pointer + i
; - value:
array[i]
=*(array + i)
=*(pointer + i)
Multi-dimensional Arrays
int B[2][3];
int *p = B; // ERROR! B is a pointer to an array, not to an intint (*p)[3] = B; // OK; 3 is needed because pointer arithmetics needs to "know" // how many bytes to add in operations like p++

Pointer arithmetic examples:
- Printing
B
(or&B[0]
) would return400
(the address of the first sub-array) - Printing
*B
(orB[0]
or&B[0][0]
) would return400
(the address of the first element in the first sub-array) - Printing
B+1
(or&B[1]
) would return412
(the address of the second sub-array) - Printing
*(B+1)
(orB[1]
or&B[1][0]
) would return412
(the address of the first element in the second sub-array) - Printing
*(*B+1)
(orB[0][1]
) would return3
. p++
would move from400
to412
Pointer to Pointer
int x = 4;int *p = &a;int **q = &p;
A p
points to x
. q
points to p
.

In this example, we have even int ***
pointer (a pointer to pointer to pointer).
We can also dereference such “deep” pointers. For example:
printf("%d", **q); // prints 6
Arrays as arguments
When a function accepts an array as an argument, a pointer to an array is passed:

This means that sizeof(A)
will be different in main()
(20 bytes) and in
SumOfElements()
(4 bytes - just the size of a pointer to an integer!).
Returning a pointer
It’s wrong to return a pointer to a variable on a stack:
int *Add(int a, int b){ int c = a + b; return &c;}
int main(){ int a = 1; int b = 2; int *p = Add(a, b); // we got a pointer to a sum SomeOtherFunction(); // the value that p points to could be overwritten by the new stack frame!}
Instead, we should allocate the result on the heap and return a pointer to it.
Function Pointers
int Add(int a, int b){ return a + b;}
int main(){ int (*p)(int, int) = Add; // pointer definition contains return type and a list of parameters int c = p(2, 3); // executes Add via a pointer - adds 2 and 3}
A pointer p
points to a function Add
.