Summary
Pointers
c
int a = 123;
int *a_ptr; // a_ptr is a pointer to an int
a_ptr = &a; // set a_ptr to the address of a
// printing a
printf("%d\n", a); // 123
// printin the pointer to a/the address of a
printf("%p\n", a_ptr); // (random hex number)
printf("%p\n", &a);
// use the %p format specifier to print pointers
// dereferencing the pointer to a
printf("%d\n", *a_ptr); // 123
*a_ptr
is synonymous witha
Size of a pointer
- depends on system architecture
c
printf("%d\n", sizeof(char *)); // 8
printf("%d\n", sizeof(int *)); // 8
8 bytes for 64-bit systems, 4 bytes for 32-bit systems
Concept
Pointer as a variable
- contains the address of another variable
Address operator
- get the address of a variable
&a
refers to the address ofa
Dereference operator
- refer to the value that the pointer points to
*p
refers to the value at address stored in pointerp
Pointer arithmetic
- the address is incremented/decremented according the type of variable it points to
- refer to the size of primitive types
c
type *p = &a; // some arbitraty pointer to a type
p += 5; // synonymous with p += 5 * sizeof(type)
Application
Pointers and dereferencing
c
int *p, *q, x = 743, y = 30;
p = &x; // 1) addr of x to p
q = &y; // 2) addr of y to p
*p = *q + 1; // 3) set the value at p to the value at q + 1
// var | address(dec) | value | (1) | (2) | (3)
// p | 1164 | ? | 1172 | |
// q | 1168 | ? | | 1176 |
// x | 1172 | 743 | | | 31
// y | 1176 | 30 | | |
Pointer to pointers
c
int *p; // pointer to an int
int **q; // pointer to a pointer to an int.
int x = 908, y = 4003;
p = &x; // 1) addr of x to p
q = &p; // 2) addr of p to q
p++; // 3) increment int pointer p, +4
(*p)--; // 4) decrement the value at p
(**q)++; // 5) increment the value at the value at q
// var | address(dec) | value | (1) | (2) | (3) | (4) | (5)
// p | 2980 | ? | 2988 | | 2992 | |
// q | 2984 | ? | | 2980 | | |
// x | 2988 | 908 | | | | |
// y | 2992 | 4003 | | | | 4002 | 4003
take note the parentheses in
(*p)--
and(**q)++
because the increment/decrement operator has higher precedence than the dereference operator
Incrementing pointers to various types
c
int a; float b; char c; double d;
int *ap; float *bp;
char *cp; double *dp;
ap = &a; bp = &b; cp = &c; dp = &d;
printf("%p %p %p %p\n", ap, bp, cp, dp); // eg: ffbff0a4 ffbff0a0 ffbff09f ffbff090
ap++; bp++; cp++; dp++;
printf("%p %p %p %p\n", ap, bp, cp, dp); // eg: ffbff0a8 ffbff0a4 ffbff0a0 ffbff098
// +4 +4 +1 +8
ap += 3;
printf("%p\n", ap); // eg: ffbff0b4
// +3x4
Casting to pointers to another type
c
int a[3] = { 1, 2, 3 };
printf("%p\n", a); // base
printf("%p\n", ((void *) a) + 1); // base + 1
printf("%p\n", (int *) ((void *) a) + 1); // base + 4, word allignment for ints during casting
reveals that the pointers are incremented based on the type it points to
Endian-ness
c
int a = 0xF070;
int *a_ptr = &a;
printf("%b\n", *a_ptr); // 1111 0000 0111 0000, 0xF070
printf("%b\n", *(((char *) a_ptr))); // 111 0000, 0x70
printf("%b\n", *(((char *) a_ptr) + 1)); // 1111 1111 1111 1111 1111 1111 1111 0000, 0xF0 sign extended to 32-bit
printf("%b\n", *(((char *) a_ptr) + 2)); // 0
C uses little-endian where the least significant byte is stored at the lower address, the 8-bit char is sign extended to 32 bits