CS 202 - Notes 2018-09-17
Pointers
Pointers allow us to refer to memory location in C.
int * xp | type declaration -- xp is an a pointer to an integer |
* xp | dereference xp "the value referred to by xp" |
&x | the address of x |
Important, a declaration of a pointer only creates a location in memory that can hold an address, it does not also create a location for the integer value it refers to. Do not dereference a pointer without first assigning it to a valid location of the appropriate value.
Example: swap
We can use this facility to create a function that swaps the contents of two memory locations.
swap.c
/*
Example showing the use of low level memory manipulation.
C. Andrews
to compile: gcc -o swap swap.c
to run: ./swap
*/
#include <stdio.h>
#include <stdint.h>
/*
In this function, we attempt to do the swap using conventional ints. The swap
is made, but only within the function. The local x and y receive the values
of the main x and y, but that is the only connection. So it doesn't work.
x - first integer to be swapped
y - second integer to be swapped
*/
void swap(int x, int y){
printf("\t[swap] before: x: %d, y %d\n", x, y);
int tmp = x;
x = y;
y = tmp;
printf("\t[swap] after x: %d, y %d\n", x, y);
}
/*
This time, we pass in two addresses, which allows us to swap their contents.
xp - address of the first integer to be swapped
yp - address of the second integer to be swapped
*/
void swap2(int *xp, int *yp){
printf("\t[swap2] before: x: %d, y %d\n", *xp, *yp);
int tmp = *xp;
*xp = *yp;
*yp = tmp;
printf("\t[swap2] after x: %d, y %d\n", *xp, *yp);
}
/*
This demonstrates the difference between the two swap functions. It creates
two int variables, and then shows the before and after for each function.
*/
int main(int argc, char * argv[]){
int x, y;
x = 1;
y = 2;
printf("[main] before: x %d, y %d\n", x, y);
swap(x,y);
printf("[main] after: x: %d, y %d\n", x, y);
printf("[main] before: x %d, y %d\n", x, y);
swap2(&x,&y);
printf("[main] after: x: %d, y %d\n", x, y);
return 0;
}
Arrays
In C, there is a tight coupling between pointers and arrays (array notation is just a thin veneer over pointers).
Arrays basically look the same in C as they do in Java.
int a[5]; // declare the array
// initialize the array
for (int i = 0; i < 5; i++){
a[i] = i*2;
}
// print it out
for (int i = 0; i < 5; i++){
printf("%d: %d\n", i, a[i]);
}
We can use pointers to move around the array. Note that when we add (or subtract) 1 from a pointer, it actually moves by the size of the type being pointed at by the pointer (so our int pointer moves by 4).
p = &a[0]; // set p to point to the first element
printf("%d %d\n", a[0], *p);
printf("%p\n", p); // look at the address stored in p
p++; // add 1 to the pointer (actually moving it by 4)
printf("%p\n", p);
printf("%d %d\n", a[1], *p);
printf("%d %d\n", a[2], *(p+1));
printf("%d %d\n", a[0], *(p-1));
output:
0 0
0x7ffd27ac5a30
0x7ffd27ac5a34
2 2
4 4
0 0
Our variable a
is just a pointer -- a[i]
is just syntactic sugar and equivalent to *(a+i)
. The only different between a
and p
is that a
doesn't really exist (the compiler maintains it internally), so we can't change the value of a
.
Another thing to note about arrays is that they don't know their own length. So, we will always need to keep track of the length to make sure we do not walk off the end of the array.
basic_array.c
#include <stdio.h>
int main(int argc, char * argv[]){
int x = 5;
int y = 6;
int a[5]; // declare the array
// initialize the array
for (int i = 0; i < 5; i++){
a[i] = i*2;
}
// print out the array
for (int i = 0; i < 5; i++){
printf("%d: %d\n", i, a[i]);
}
int *p; // declare our pointer
// initialize p ( both of these lines do the same thing)
//p = &a[0];
p = a;
// pointer math examples
printf("%d %d\n", a[0], *p);
printf("%p\n", p);
p++;
printf("%p\n", p);
printf("%d %d\n", a[1], *p);
printf("%d %d\n", a[2], *(p+1));
printf("%d %d\n", a[0], *(p-1));
printf("%d %d\n", a[0], *a);
printf("%d %d\n", a[1], *(a+1));
printf("%d %d\n", p[1], *(a+2));
printf("%d %d\n", a[3], 3[a]); //DON'T EVER DO THIS!!!!!
/*
This is an example I did with section B.
We don't need to start with an array to walk around in memory.
Here we find that x and y are next to each other in memory and we can walk
between them using pointer math.
*/
p = &y;
printf("%p %p\n", &x, &y);
printf("%p %d\n", p, *p);
p++;
printf("%p %d\n", p, *p);
return 0;
}
full output
0: 0
1: 2
2: 4
3: 6
4: 8
0 0
0x7ffcf446ce10
0x7ffcf446ce14
2 2
4 4
0 0
0 0
2 2
4 4
6 6
0x7ffcf446ce2c 0x7ffcf446ce28
0x7ffcf446ce28 6
0x7ffcf446ce2c 5