Introduction to Scientific Computing and Problem Solving Lecture #22 Pointers CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.0 Announcements HW8 due tomorrow at 2:30pm What s left: Lab 9 & 10, HW9 & Image project CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.1 1
This lecture Pointers The true beauty of C Examples - applications CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.2 Let s C so far Intro Basic types (int, float, double), variables, operations, basic I/O Conditionals & Loops Flow control Arrays Representation, usage/manipulation Functions declaration, definition, usage call by value Vs. call by reference (w/ arrays) CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.3 2
3 Recall: Memory Organization The amount of memory needed to store a variable depends on the variable type int 4 bytes double 32 bytes Each memory location contains a byte and has a unique address var1 (int) var2 (int) 1000 1001 1002 1003 1004...... CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.4 Recall: Arrays Memory Representation Arrays occupy contiguous blocks of memory int myarray[3]; myarray[0] 1000 total number of bytes = 12 myarray[1] myarray[2] 1004 1008... CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.5
Memory Organization: Closer View On the machine level a computer's main memory is typically divided into bytes A byte is capable of storing eight bits of information, i.e., it can represent 2 8 = 256 different values 0 1 0 1 1 0 0 1 2 6 +2 4 +2 3 +2 0 = 89 Each byte in memory has an associated address Addresses are consecutive numbers that define the address space of a computer... 40210 40211 40212 40213 40214 40215 40216 40217... CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.6 Lvalues We have already seen how variables and arrays are represented in memory In general, an expression that can appear on the left side of the assignment operator = is called an Lvalue An Lvalue must refer to a memory location (so far, just names of variables and array elements) char c; short int a[3]; Some other C data types, occupying 1 and resp. 2 bytes (more in next lecture)... 40210 40211 40212 40213 40214 40215 40216 40217... c a[0] a[1] a[2] CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.7 4
What Else Can Be an Lvalue? Pointers Make it possible to return multiple values from a single function call Facilitate working with large data aggregates (e.g., struct, next lecture) Shortcut for array element manipulation Makes things easy and hard CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.8 Pointers: "Remember the Address" A pointer variable is a variable that can store an address Its value, a pointer, is nothing more than an address in memory The number of bytes needed to store an address depends on the size of the address space For example, a 32-bit address is sufficient for 4 gigabytes (GB) of main memory (2 10 = 1024 = 1 K, 2 32 = 4 * 2 10 * 2 10 * 2 10 ). Graphically, a pointer variable p that points to the address of a variable i is shown as: p i CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.9 5
Pointers and Ordinary Variables Ordinary variable holds a data value (int, char, float, struct ) Pointer variable holds a reference to a variable The map leads us points to the treasure CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.10 Declaring Pointer Variables Like ordinary variables, pointer variables need to be declared before they can be used in C Moreover, C requires that we explicitly describe the type of variable (Lvalue really) that the pointer will refer to - the reference type An asterisk * is used to distinguish a pointer (variable) from regular variables int *p; float *f; /* pointer variable to an integer type lvalue */ /* pointer variable to a float type lvalue */ int i, a[5], *q; /* combined declaration */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.11 6
Pointer Variables as Lvalues So how do we store an address in a pointer? One can simply refer to a particular address by a numerical constant; this is usually not so interesting neither likely to be correct since we often don't (or want to) know the exact address numbers! int *p; p = 4301922; /* address of some memory location */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.12 Address Operator & Pointers are most frequently used in conjunction with & (address) operator, which obtains the address of a variable The reference type can be any type (basic or user-defined, see next lecture) int *p, i=1; p = &i; /* store address of variable i */ All we care about is that p points to the address of another variable - say i - while the actual numerical address is irrelevant int *p, a[5]; p = &a[0]; /* store address of element a[0] */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.13 7
8 Pointer Assignment Pointers can also be copied by using them in assignment statements int *p, *q, i=-2341; p = &i; /* p stores address of variable i */ q = p; /* q stores value of p which is simply the address of i */ 1245052? p 1245060 p 1245060 p 1245056? q? q 1245060 q 1245060-2341 i -2341 i -2341 i CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.14 To Point or Not to Point - "What's the Point?" Modifying pointer variables in assignment operations will not affect the actual value stored in a variable int i=0, j=1; int *p = &i, *q; q = p; /* q stores value of p = address of i */ q = &j; /* q now stores address of j */ p = q; /* p points to j as well */ /* the values of variables i and j have not been changed by this "exchange of addresses" */ printf("i=%d, j=%d\n", i, j); CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.15
9 Indirection Operator * Once we have the address of a memory location (Lvalue) stored in a pointer, how do we get to the value stored there? Access is provided through the indirection operator * Also called dereferencing Different role of * int i=1001, j, k; int *p; What is the value of j and k? p = &i; /* address operator, stores address of i in p */ j = *p; /* indirection operator, assigns value stored in the address pointed to by p in j */ i = 0; /* changes the value of i */ k = *p; /* indirection operator */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.16 Pointer Confusion? & & * * & * Although the concept of a pointer variable is very simple, the use of pointer variables can sometimes be confusing Consequently many programming errors in C are the result of incorrect usage of pointer variables CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.17
10 Pointer Confusion? Why are pointers potentially confusing? We always have to be aware of the difference between an address and the value stored at an address & & * * & * int i=1000, j=2000; int *p, *q; p = &i; q = &j; *p = *q; /* copies an integer value */ p = q; /* copies an address */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.18 Pointer Confusion? & & * * & * Why are pointers potentially confusing? Via the indirection operator pointer variables can be used as aliases, i.e., there are multiple "names" referring to the same Lvalue int i = 1, *p, *q; p = &i; q = &i; *p = 2; /* i is now 2 as well */ *q = 3; /* i (and *p) is now 3 as well */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.19
11 Pointer Example (1) Let's look at a simple example again: 1245052 1 i int i = 1, *p, *q; 1245056? p 1245060? q p = &i; q = p ; 1245052 1245056 1245060 1 1245052 1245052 i p q CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.20 Pointer Example (2) 1245052 2 i *p = 2; 1245056 1245052 p 1245060 1245052 q 1245052 3 i *q = 3; 1245056 1245052 p 1245060 1245052 q CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.21
12 Another Example #include <stdio.h> int main () { double *p1, *p2, b = 5.6; /* p1 gets the address of b */ p1 = &b; printf("b is now %lf\n", b); /* change b by dereferencing the pointer */ *p1 = 7.5; printf("b is now %lf\n", b); /* make another pointer to b */ p2 = p1; /* change b again, by dereferencing the new pointer */ *p2 = 9.3; printf("b is now %lf\n", b); } return 0; CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.22 More Pointer Pitfalls Dereferencing a pointer variable using the indirection operator (*) when it has not been initialized properly can lead to (extremely!) undesirable program behavior int *p; /* an uninitialized pointer variable */ *p = 0; /* manipulating a random memory location */ int i; /* an integer variable */ scanf ("%d", i); /* should have used &i */ Segmentation fault CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.23
13 NULL Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end. - 10 Commandments for C Programmers by H. Spencer As a defensive measure, it is useful to assign a special (constant) value to uninitialized pointer variables This special value is called NULL, and it is different from every valid address #include <stdio.h> int *p = NULL; if (p == NULL) printf("invalid pointer!\n"); else printf("dereferencing = %d\n",*p); CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.24 Pointers as Function Arguments Pointers can be passed as parameters in functions just like any other data type Passing a pointer to a variable is known as passing by reference If we pass a variable by value, the value gets copied and we cannot modify the variable in a function Pointers offer a solution to this problem: instead of passing a variable, we pass a pointer to the variable A pointer argument provides the address through which the function can alter the value of the original variable CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.25
14 Pointers as Function Arguments Here is a simple example of a function that sets a variable to zero /* * Function that sets the value of an int * Lvalue to zero using a pointer variable as * an argument */ void settozero(int *ptr) { *ptr = 0; } int main() { int i=1001; printf("before = %d\n",i); settozero(&i); printf("after = %d\n",i); } return 0; CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.26 Example: Step by Step int i = 1001; 0020000 i 1001 settozero(&i); settozero(int *ptr) 0020000 i 1001... 0020000 ptr *ptr = 0; 0020000 i 0... 0020000 ptr CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.27
15 Pointers as Local Variables Use a pointer as a parameter to allow the function to modify variables What happens if a function modifies a parameter which happens to be a pointer variable? Nothing, it's a local variable void SetToZero(int *ptr) { *ptr = 0; /* has an effect outside of the function */ ptr = NULL; /* has no(!!) effect outside of the function */ } CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.28 Passing by Reference Passing by reference provides a way for functions to return multiple values /* Compute maximum and minimum value in an array */ void maxmin(double a[], int n, double *max, double *min) { *max = *min = a[n-1]; for (n = n-2; n >= 0; n--) } [...] if (a[n] > *max) *max = a[n]; else if (a[n] < *min) *min = a[n]; Better: (by operating on copies of addresses) to manipulate the original contents of multiple input parameters double a[size], largest, smallest; [...] maxmin(a, SIZE, &largest, &smallest); printf("max = %lf, min = %lf\n", largest, smallest); CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.29
16 Pointers in C! Three is a very special number. It pervades religion, psychology, art, literature and more! This demo will show you some basic uses of pointers in C while exploring this magical and mystical number! CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.30 scanf - Revisited We have been using "passing by reference" since the beginning in arguments to the scanf function We want scanf to actually return the input values in the variables passed as arguments #include <stdio.h> int main() { int i,j ; scanf ("%d%d", &i, &j); /* pass by reference */ printf("read in %d and %d\n", i, j); /* pass by value */ } return 0; CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.31
17 Swap Here is an example to implement a swap function using pointers: /* * Function to swap values of two integer variables */ void swap(int *a, int *b) { int itmp; itmp = *a; *a = *b; *b = itmp; } [...] int x=1, y=2; swap(&x, &y); swap( x, y); //this would not work CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.32 Addresses of Array Elements The address of an array element can be determined by the address operator & int arr[10]; int *ptr ; ptr = &arr[0]; /* the address of the 1st array element */ ptr = &arr[2]; /* the address of the 3rd array element */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.33
18 Pointer Arithmetic (1) We can perform arithmetic operations with pointer variables Pointer arithmetic is defined taking into account the pointer variable's base type (now you know why that was important!) int arr[10]; int *ptr1, *ptr2 ; ptr1 = &arr[2]; /* the address of the 3rd array element */ ptr2 = &arr[0] + 2 ; /* equivalent */ Notice how this is different from simply adding 2 to the actual address; pointer arithmetic takes into account that an integer element occupies sizeof(int) bytes CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.34 Pointer Arithmetic (2) Pointers can be used as a "cursor" to move along an array; moving n elements forward or backward can simply be achieved by: int arr[10], *ptr = &arr[0]; ptr += 5; /* move 5 elements forward, points to arr[5] now */ ptr -= 2; /* move 2 elements backward, points to arr[3] now */ ptr += 1; /* move 1 element forward, points to arr[4] now */ ptr += 6; /* oops! */ Pointers can also be subtracted int diff, arr[10], *p = &arr[2], *q = &arr[7]; diff = q - p; printf( Pointer difference = %d\n", diff) ; CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.35
Pointer Arithmetic (3) Step by step example: int arr[10]={0,1,1,2,3,5,8,13,21,34}; int *ptr = &arr[0]; ptr += 5; *ptr = -1; ptr -= 2; *ptr = -2; ptr += 1; *ptr = -3; ptr += 6; ptr p ptr+=6; ptr = &arr[0]; ptr-=2; ptr+=1; ptr+=5; *ptr=-2; *ptr=-3; *ptr=-1; arr 0 1 1-2 2-3 3-1 5 8 13 21 34 CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.36 Array Names as Pointers C treats an array name as a pointer to the first element int i, arr[n]; for (i = 0; i < N; i++) *(arr + i) = i; /* equivalent to arr[i] = i; */ int *p; /* move pointer over array */ for (p = arr; p < arr + N; p++) sum += *p; However, array names are constant pointer variables, i.e., one cannot assign it a new value (address) int i, arr[n]; for (i = 0; i < N; i++) *arr++ = i; /* NO!!! */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.37 19
Pointers as Array Names In many situations, it is also possible to treat a pointer as an array name In particular one can use the subscript operator (i.e., brackets []) to access array elements int i, arr[n], *p ; [...] /* fill array here */ p = arr; for (i = 0; i < N; i++) p[i] = 0; as if p is an array name although it is the name of a pointer variable CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.38 Arrays as Function Arguments Looking back we see now why arrays are passed as function arguments by reference: because the array name is nothing but a (constant) pointer variable /* Multiplies each element of an array by a constant */ void mult(double a[], int num, double value) { int i; for (i = 0; i < num; i++) a[i] *= value; } [...] double b[5] = {1e-1, 1e-2, 1e-3, 1e-4, 1e-5 }; mult(b, 5, 2.0); CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.39 20
21 Pointers & Multi-dimensional Arrays Pointers can also point to elements in a multidimensional array Remember the memory layout of 2D arrays: rows are stored consecutively in memory a row 0 row 1 row 2 a[0][0]a[0][1]a[0][2]a[1][0]a[1][1]a[1][2]a[2][0]a[2][1]a[2][2] memory (sequential) #define SIZE 3 int a[size][size]; /* treated as 1D array (a[]) with elements that are 1D arrays (the rows) */ int *row, n = 1 ; row = a[n]; /* pointer to the first element in n-th row */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.40 Relational Operators on Pointers Pointers can also be compared by relational operators <, >, <=, >=, == int arr[100], *p = &arr[10], *q = &arr[21]; [...] /* some pointer arithmetic here */ if (p == q) printf("p and q point to the same element.\n"); else if (p < q) printf("element index of p smaller than that of q.\n"); else printf("element index of p greater than that of q.\n"); CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.41
22 Using Pointers in Array Processing (1) A first useful example of pointer arithmetic: Compute the sum of the elements in an array #define N 10 int arr[n], *p = NULL ; int sum = 0; [...] /* fill array elements here */ /* move pointer over array */ for (p = &arr[0]; p < &arr[n]; p++) sum += *p; printf("sum of array elements = %d\n", sum); CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.42 Using Pointers in Array Processing (2) A closer look at the details pointer variable points to first array element pointer variable advances to next element in array for (p = &arr[0]; p < &arr[n]; p++) sum += *p; pointer dereferencing (indirection operator) relational operator, check whether past last array element CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.43
23 Using Pointers in Array Processing (3a) p arr p = &arr[0]; 11-5 3-7 21 12-3 0 0 1 sum 11 sum += *p; p p++ arr 11-5 3-7 21 12-3 0 0 1 sum 6 sum += *p; CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.44 Using Pointers in Array Processing (3b) p arr p++ 11-5 3-7 21 12-3 0 0 1 sum 9 sum += *p; p p++ arr 11-5 3-7 21 12-3 0 0 1 sum 2 sum += *p; CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.45
Subscripting vs. Pointers In our example, the use of pointers could easily be replaced by subscripting using a counter int *p; /* move pointer over array */ for (p = &arr[0]; p < &arr[n]; p++) sum += *p; int i; /* use subscripting */ for (i = 0; i < N; i++) sum += arr[i]; Some compilers will produce more efficient code when using pointer arithmetic CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.46 Combining Operators Pointer operators can be combined Example: initialize array elements to zero #define N 100 [...] int *p = &arr[0], *last = &arr[n-1]; while (p <= last) *p++ = 0; /* dereference, assign and increment */ CS4 - Introduction to Scientific Computing and Problem Solving 2010-22.47 24