Lecture – Pointers and Arrays

Ryan Robucci

Table of Contents

Pointers and Arrays

Multiple operators can dereference pointers

Let there be the declarations

int a[]={1,2,3,4,5,6,7,8}; 
int *intPtr; 

a is actually an address that can be referenced with an offset

a[0], so the square bracket operator [ ] is actually dereferencing with an offset

In fact, we can do the same with the pointer variable.

intPtr=a;

or

intPtr=&(a[0]); 

result in
intPtr[0] is the value 1;

So, we have learned two of three ways to dereference pointers:

Syntax Method
* dereference
[index] dereference with an memory offset of index times sizeof(type)
-> this is a third that we will see soon for accessing members of struct/union

Pointee Type and Array Element Type

So, how is an array different than a pointer?

Cant change where the array associated with an array name is

Generate a new view of an existing array

	int image5x5[25];
	int *middleRow = &arr[10];
	int *middle = &arr[12];

0123456789101112131415161718192021222324\begin{matrix} &0 & 1 & 2 & 3 & 4\\ &5 & 6 & 7 & 8 & 9\\ \rightarrow &\underline{10} & 11 & \textcircled{12} & 13 & 14\\ &15 & 16 & 17 & 18 & 19\\ &20 & 21 & 22 & 23 & 24 \end{matrix}

If you allocate an extra terminating element, you are allowed to get the address of it and work backwards:

	int image5x5[26];
	int *end = &arr[25];

Usually an array decays into a pointer to the first element, but not always

Arrays as function parameters are pointers

With respect to a function's formal parameters, C treats a one-level array just like a pointer (multi-dimensional and variable-length arrays will be discussed in a later lecture)

The following results from a function call from main to bubble(int arr[]) illustrate this as will as similarities and differences between arrays and pointers

File bubble.c:

void bubble(int arr[]){
  int tmp;
  for (int i=0;i<(4-1);i++){
    if (arr[i+1]<arr[i]){
      tmp=arr[i];
      arr[i+1]=arr[i];
      arr[i]=tmp;
    }
  }
}

int main() {
  int arr[8]={10,30,20,40};
  bubble(arr);
  return arr[0];
}
gcc -Wall -g -O0 bubble.c
gdb ./a.out
b bubble.c:3
run
gdb command result after select-frame 1 caller main result after select-frame 0 function bubble note
print arr {10, 30, 20, 40, 0, 0, 0, 0} (int *) 0x7fffffffdb90 gdb knows the length of the array
the command explore arr will invite you to examine an element of the array
print &arr (int (*)[8]) 0x7fffffffdb90 (int **) 0x7fffffffdb68 pointer to array of eight integers vs. pointer to a pointer to an integer
print sizeof(arr) 32 8 an array does not decay into a pointer in the context of the sizeof operator
print *arr 10 10 an array decays into a pointer to the first element under most circumstances
print &(arr[0]) (int *) 0x7fffffffdb90 (int *) 0x7fffffffdb90 both point to the same first element
print arr+0 (int *) 0x7fffffffdb90 (int *) 0x7fffffffdb90 a shorthand to force decay into a pointer to the first element
print arr+1 (int *) 0x7fffffffdb94 (int *) 0x7fffffffdb94 pointer arithmetic is handled the same
print (&arr)+1 (int (*)[8]) 0x7fffffffdbb0 (int **) 0x7fffffffdb70 pointer to array vs pointer to pointer
+32 (sizeof length-8 integer array) +8 (sizeof(pointer))

Pointer Arithmetic

Work through the following code and find what it prints by practicing diagraming pointers.

ptrAdd.c:

int main() {  
  char c, *cPtr = &c; 
  int i, *iPtr = &i; 
  double d, *dPtr = &d; 
  printf("\nThe addresses of c, i and d are:\n"); 
  printf("cPtr = %p, iPtr = %p, dPtr = %p\n",             cPtr, iPtr, dPtr) ;  
  cPtr = cPtr + 1 ; 
  iPtr = iPtr + 1 ; 
  dPtr = dPtr + 1 ; 
  printf("\nThe values of cPtr, iPtr and dPtr are:\n") ; 
  printf("cPtr = %p, iPtr = %p, dPtr = %p\n\n",         cPtr, iPtr, dPtr) ; 
  return 0; 
}

Iterating through an Array

Function Array Arguments

Array Length

Managing array sizes in C is not a minor issue. (On an exam you should be prepare for questions about determining the size of an array or ask you about designing functions using arrays. )

Going outside the bounds of an array is not automatically checked and can lead to serious program or system crashes. The size of an array is also not usually available.

Basic approaches for approaching the design of functions using arrays in parameters are:

  1. Predetermined Fixed Size: Use a predetermined size for the array or some other predetermined method for determining it that the caller and callee conform to
  2. Additional Length Parameter: Use extra parameter to convey the number of elements in an array
  3. Termination Value: Use a termination value in the array itself that can be discovered by iterating through the array.

Iteration through an Array

int SumArray( int a[ ], int length) 
{ 
  int k, sum = 0; 
  for (k = 0; k < length; k++) 
    sum += a[ k ]; 
  return sum; 
} 

Note the need to pass the size, which is not typically required in higher-level languages where the size of an array can be queried with expressions similar to

a.size()  

or

length(a) 

Avoid (careless) sizeof(array)

sizeof(a)/sizeof(int) does would not work in the context within the SumArray function to determine the size of the array
which is why I recommend avoiding it in general
even though it works in the the following case

int a[]={3,1,4,1,5,9};
int len = sizeof(a)/sizeof(int);

since the length is known at compile time, it is better style to simply provide an explicit label with the length:

const int PI_PRECISION=6;
int a[PI_PRECISION]={3,1,4,1,5,9};
int len = PI_PRECISION;

Use of pointer arithmetic with addition of variable offset

int SumArray( int arr[ ], int length) { 
  int k, sum = 0; 
  for (k = 0; k < length; k++) 
    sum += *(a + k);  //***
  return sum;  
} 

Using pointer arithmetic with fixed pointer increment:

int SumArray( int arr[ ], int length) { 
  int k, sum = 0;  
  for (k = 0; k < length; k++) 
    sum += *a++; //** implies use of dereference with auto-increment 
  return sum; 
} 

Arrays, strings, and pointers question

char hello[ ] = "Smith,Sara"; 

char * ptrChar; 

ptrChar = &(hello[6]); 

What is printed from each of the following?

printf("%s\n",hello); 
printf("%s\n",ptrChar ); 
printf("%s\n",&(hello[6])); 
printf("%s\n",hello + 6); 
printf("%s\n",hello[6]); //see compiler note 

What is wrong with this?

ptrChar[4]='h';

Would this be OK?

ptrChar[5]='\0';
compiler note produces an error

Arrays of pointers and arrays of strings

Since a pointer is a variable type, we can create an array of pointers just like we can create any array of any other type.

A common use of an array of pointers is to create an array of strings.
The declaration below creates an initialized array of strings (char *) for some baby names.
The diagram below illustrates the memory configuration.

char *name[] = { "Bobby", "Sam", "Harold"};
alt

Beware of pointers to string literals and constant arrays

#include <stdio.h>
#include <stdlib.h>

int main(){
  char * name[]={"Bobby","Jim","Harold" }; //might be stored in read-only (e.g. program) memory
  printf("%s",name[1]);
  fflush(stdout); //needed to ensure output displayed before seg fault (useful to consider when debugging projects)
  name[1][2]='r'; // here
  printf("%s",name[1]);
  return 0;
}

Code compiles with no errors or warnings.

Code Output:

JimSegmentation fault

Command Line Arguments