CSCI206 - Computer Organization & Programming Introducing Pointers in C zyBook: 9.1, 9.3 prelab for lab 7
Pointers Powerful feature of C. Key: pointers are simply memory addresses of the variables! Java/C++ “references” are pointers with extra safety checks. In C the programmer is responsible. * is the dereference operator, used to declare a pointer and access memory pointed to by a pointer. & is the address of operator, it returns a pointer.
Pointers int i = 7; int j = -1; int* pi = &i; int *pj = &j; printf(" i = %d\n", i); printf(" j = %d\n", j); printf(" pi= %p\n", pi); printf(" pj= %p\n", pj); printf(" data pointed to by pi= %d\n", *pi); printf(" data pointed to by pj= %d\n\n", *pj); *pi = 6; declare and initialize pointers
Pointers int i = 7; int j = -1; int *pi = &i; int *pj = &j; printf(" i = %d\n", i); printf(" j = %d\n", j); printf(" pi= %p\n", pi); printf(" pj= %p\n", pj); printf(" data pointed to by pi= %d\n", *pi); printf(" data pointed to by pj= %d\n\n", *pj); *pi = 6; dereference the pointer to access the value it points to
Result of executing the above C program on polaris [bash xmeng@polaris 18-CPointers]$ gcc -o pointers pointers.c [bash xmeng@polaris 18-CPointers]$ ./pointers i = 7 j = -1 pi= 0x7ffc3383e58c pj= 0x7ffc3383e588 data pointed to by pi= 7 data pointed to by pj= -1 [bash xmeng@polaris 18-CPointers]$ cat /proc/cpuinfo … address sizes : 39 bits physical, 48 bits virtual
Result of executing the above C program on mips [bash xmeng@mips 18-CPointers]$ gcc -o pointers pointers.c [bash xmeng@mips 18-CPointers]$ ./pointers i = 7 j = -1 pi= 0x7f977318 pj= 0x7f97731c data pointed to by pi= 7 data pointed to by pj= -1 This is a more familiar 32-bit address space.
Pointers compared to assembly dereference (*pointer) lw $t0, pointer or sw $t0, pointer e.g., lw $t0, 4($s0) # value of $s0 plus 4, an address! address of operator (&variable) la $t0, variable
Pointers allow pass by reference void addone(int i){ i = i + 1; } void addone(int *i){ *i = *i + 1; addone: addi $a0, $a0, 1 jr $ra lw $t0, 0($a0) addi $t0, $t0, 1 sw $t0, 0($a0) pass by copy pass by ref
Pass by pointer [bash xmeng@polaris 18-CPointers]$ make conversion #include <stdio.h> #include <stdlib.h> void ConvFeetInches(int totDist, int inFeet, int inInches) { inFeet = totDist / 12; inInches = totDist % 12; return; } int main(void) { int initMeasure = 45; int resFeet = 0; int resIn = 0; ConvFeetInches(initMeasure, resFeet, resIn); printf("%d feet %d inches\n", resFeet, resIn); return 0; } [bash xmeng@polaris 18-CPointers]$ make conversion gcc -Wall -g -c conversion.c gcc -o conversion conversion.o [bash xmeng@polaris 18-CPointers]$ ./conversion 0 feet 0 inches [bash xmeng@polaris 18-CPointers]$
Pass by pointer [bash xmeng@polaris 18-CPointers]$ make conversionp #include <stdio.h> #include <stdlib.h> void ConvFeetInches(int totDist, int* inFeet, int* inInches) { *inFeet = totDist / 12; *inInches = totDist % 12; return; } int main(void) { int initMeasure = 45; int resFeet = 0; int resIn = 0; ConvFeetInches(initMeasure, &resFeet, &resIn); printf("%d feet %d inches\n", resFeet, resIn); return 0; } [bash xmeng@polaris 18-CPointers]$ make conversionp gcc -Wall -g -c conversionp.c gcc -o conversionp conversionp.o [bash xmeng@polaris 18-CPointers]$ ./conversionp 3 feet 9 inches [bash xmeng@polaris 18-CPointers]$
Pointers vs arrays At the machine level, arrays are treated as pointers in C. int arr[10]; assert(arr == &arr[0]); // TRUE printf("%p\n", &arr[0]); printf("%p\n", arr); 0x7fff85d95490
Pointer Arithmetic Addr of array : 0x7fff85d95490 int array[10] = {30,31,32,33,34,35,36,37,38,39}; int *ptr; printf("Addr of array : %p\n", array); printf("ptr holds addr: %p\n", ptr); ptr = array; printf("ptr holds addr: %p\n\n", ptr); ptr = ptr + 1; printf("Addr of arr[1]: %p\n", &(array[1])); printf("ptr hold addr : %p\n", ptr); printf("ptr points to : %d\n\n", *ptr); Addr of array : 0x7fff85d95490 ptr holds addr: (nil) ptr holds addr: 0x7fff85d95490 Addr of arr[1]: 0x7fff85d95494 ptr hold addr : 0x7fff85d95494 ptr points to : 31
Pointer Arithmetic ptr = ptr + 4; printf("ptr hold addr: %p\n", ptr); printf("ptr points to: %d\n\n", *ptr); ptr--; // or ptr -= 1; double arr2[5] = {0.0, 0.5, 3.1415, 2.71, 1.41}; double *ptr2; ptr2 = arr2; printf("ptr2 holds addr: %p\n", ptr2); ptr2++; printf("ptr2 holds addr: %p\n\n", ptr2);
C array with unknown size This is often used to pass arrays into functions. Does not allocate space for the array! We don’t know input size at compile time. Must pass size as another parameter or use a sentinel value. Beginning of array is passed as a pointer. int arr[]; // valid, same as int *arr int *arr; // valid, same as above
Clear1 and Clear2 clear1(int array[], int size) { int i; for (i = 0; i < size; i += 1) array[i] = 0; } clear2(int *array, int size) { int *p; for (p = &array[0]; p < &array[size]; p = p + 1) *p = 0; }
clear1(int array[], int size) { int i; for (i = 0; i < size; i += 1) array[i] = 0; } move $t0,$zero # i = 0 loop1: sll $t1, $t0, 2 # $t1 = i * 4 add $t2, $a0, $t1 # $t2 = address of array[i] sw $zero, 0($t2) # array[i] = 0 addi $t0, $t0, 1 # i = i + 1 slt $t3, $t0, $a1 # $t3 = (i < size) bne $t3, $zero, loop1 # if (i < size) go to loop1 array access using indices requires multiply by 4 to convert index to array offset
clear2(int. array, int size) { int clear2(int *array, int size) { int *p; for (p = &array[0]; p < &array[size]; p = p + 1) *p = 0; } Clear2 move $t0, $a0 # p = address of array[0] sll $t1, $a1, 2 # $t1 = size * 4 add $t2, $a0, $t1 # $t2 = address of array[size] loop2: sw $zero, 0($t0) # Memory[p] = 0 addi $t0, $t0, 4 # p = p + 4 slt $t3, $t0, $t2 # $t3 = (p < &array[size]) bne $t3, $zero, loop2 # if (p < &array[size]) go to loop2 compute end address. increment pointer by 4 to get next array element.
Clear3 clear3(int *array, int size) { while (size--){ *array++ = 0; clear2(int *array, int size) { int *p; for (p = &array[0]; p < &array[size]; p = p + 1) *p = 0; } clear1(int array[], int size) { int i; for (i = 0; i < size; i += 1) array[i] = 0; } clear3(int *array, int size) { while (size--){ *array++ = 0; } } book real world Few C programmers would actually use a for loop like this, instead consider a while loop.
Pointers vs arrays In assembly it is often easier to operate on pointers rather than arrays. Avoids converting indexes to memory addresses. However, this doesn’t mean operating on pointers in C is more efficient than arrays. The compiler is very good at optimizing array access! Array code can be more readable and less error prone!
Summary Pointers are just addresses of variables. Pointers have types such that ptr ++ means different amount of increment, depending on the type of the pointer.