Joseph Haugh
University of New Mexico
All function parameters in C are passed call by value.
This means the function gets its own copy of each parameter
Any changes to the parameter values are not seen outside the function
void swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
}
void main(void) {
int a = 10, b = 17;
swap(a, b);
printf("a=%d, b=%d\n", a, b);
}
Prints: a=10, b=17
A pointer is a variable that contains the address of another variable
You create a pointer using a * in front of the variable name
int *ptr;
ptr is a pointer variable that contains the address of a int variable
What will happen when I run the following code:
void main(void) {
int *ptr;
printf("ptr=%p\n", *ptr);
}
Segmentation fault!
That is because we tried to dereference a pointer that was not initialized
The * operator is used to dereference a pointer as well
int *ptr = 10;
int x = *ptr + 5;
printf("x=%d\n", x);
ptr: is a pointer to an int variable
x: is an int variable with the value 15
What if we wanted to save a pointer to an existing variable?
We can use & operator to get the address of a variable
int x;
int *ptr;
ptr = &x;
*ptr = 21;
printf("x=%d\n", x); // Prints: x=21
What does the following code do?
int x = 10;
*(&x) = 21;
printf("x=%d\n", x); // Prints: x=21
*(&x) gets the address of x and then dereferences the pointer and sets it to a new value
The type of a pointer must match the type of the variable it points to
The following code will cause a waring:
short x;
int *ptr;
ptr = &x;
If for some reason you need to do something like above you can add an explicit cast:
short x;
int *ptr;
ptr = (int *) &x;
Your program can still be wrong but you won’t get a warning from the compiler
Casting pointers is a common operation in C
For example you can save a pointer with not type as follows:
int x;
void *ptr = (void *) &x;
However, when you need to explicitly cast it to a type:
int x;
void *ptr = (void *) &x;
*((int *) ptr) = 10;
Why is the void * pointer useful?
Well when memory is allocated by the program it has no inherit type and you need to tell it the type
For example the malloc function returns a void * pointer
extern void *malloc(unsigned int size);
extern void free(void *ptr);
int *ptr;
ptr = (int *) malloc(sizeof(int));
*ptr = 10;
free((void *) ptr);
void swap(int *x, int *y) {
int tmp = *x;
*x = *y;
*y = tmp;
}
void main(void) {
int a=10, b=17;
swap(&a, &b);
printf("a=%d, b=%d\n", a, b);
}
We have now made the parameters pointers. This will now effect the x and y variables in the main function.
int j, k;
int *ptr;
int main(void) {
j = 1; k = 2;
ptr = &k;
printf("j has value %d and is stored at %p\n",
j,&j);
printf("k has value %d and is stored at %p\n",
k,&k);
printf("ptr has value %p and is stored at %p\n",
ptr,&ptr);
printf("The value of the int pointed to by ptr is "
"%d\n", *ptr);
}
j has value 1 and is stored at 0x404020
k has value 2 and is stored at 0x404024
ptr has value 0x601040 and is stored at 0x404028
The value of the int pointed to by ptr is 2
Pointer === Address === Reference === Memory Location
void main(void) {
int x=6;
int *y; /* y will be a pointer to an int. */
y = &x; /* y is assigned the address of x. */
printf("x=%d, y=%p, *y=%d\n", x, y, *y);
}
Output:
x=6, y=0x7ffcdb19c8d4, *y=6
In C, the * and & operators are overloaded
void main(void) {
int a = 6; /* binary: 0110 */
int b = 3; /* binary: 0011 */
int *c = &a; /* The '&' means address of */
int x = a * b; /* The '*' means multiply */
int y = a + *c; /* The '*' means dereference */
int z = a & b; /* The '&' means bitwise AND */
printf("%d, %d, %d\n", x, y, z);
}
Output:
18, 12, 2
void swapNot(int x, int y) {
printf("swapNot (1) x=%d, y=%d\n", x,y);
int tmp = x;
x = y;
y = tmp;
printf("swapNot (2) x=%d, y=%d\n", x,y);
}
void main(void) {
int v[] = {33, 44, 55, 66, 77};
printf("main (1) v[0]=%d, v[1]=%d\n",
v[0],v[1]);
swapNot(v[0], v[1]); /* Passed by Value */
printf("main (2) v[0]=%d, v[1]=%d\n",
v[0],v[1]);
}
main (1) v[0]=33, v[1]=44
swapNot (1) x=33, y=44
swapNot (2) x=44, y=33
main (2) v[0]=33 v[1]=44
void swapElements(int v[], int i, int k) {
int tmp = v[i];
v[i] = v[k];
v[k] = tmp;
}
void main(void) {
int v[] = {33, 44, 55, 66, 77};
printf("main (1) v[0]=%d, v[1]=%d\n",
v[0], v[1]);
/* passes address of v[0] */
swapElements(v, 0, 1);
printf("main (4) v[0]=%d, v[1]=%d\n",
v[0], v[1]);
}
main (1) v[0]=33, v[1]=44
main (4) v[0]=44, v[1]=33
void swap (int *x, int *y) {
/* value at address x. */
int tmp = *x;
/* val @ addr x assn val @ addr y. */
*x = *y;
*y = tmp;
}
void main(void) {
int v[] = {33, 44, 55, 66, 77};
printf("main (1) v[0]=%d, v[1]=%d\n",
v[0],v[1]);
swap(&v[0], &v[1]); //Passed by Reference
printf("main (3) v[0]=%d, v[1]=%d\n",
v[0],v[1]);
}
main (1) v[0]=33, v[1]=44
main (3) v[0]=44, v[1]=33
void swapElements (int v[], int i, int k)
/* same as: (int* v, int i, int k) */
/* same as: (int *v, int i, int k) */
/* same as: (int*v, int i, int k) */
void main(void) {
int* a, b; /* Bad style */
*a = 5;
b = 7;
printf("%d, %d\n", *a, b);
}
Output:
5, 7
a is a pointer and b is an int
You should instead use one of the following styles:
int *a, b;
int *a;
int b;
What will this code print:
void main(void) {
int x = 5;
int *ptr = &x;
ptr = ptr + 3;
printf("&x=%p ptr=%p\n", &x, ptr);
}
Output:
&x=0x7ffd5ff4cd64 ptr=0x7ffd5ff4cd70
Why?
Pointer arithmetic is done in terms of the size of the type the pointer points to
ptr = ptr + 3;
Really means:
ptr = ptr + 3 * sizeof(int);
ptr = ptr + 3 * 4;
ptr = ptr + 12;
So why then does it look like the addresses only differ by 6?
&x=0x7ffd5ff4cd64 ptr=0x7ffd5ff4cd70
Hexadecimal!