Pointers and Arrays C and Data Structures Baojian
Pointers and Arrays C and Data Structures Baojian Hua bjhua@ustc. edu. cn
Pointers and Addresses n Think the memory as a big array n n n With each slot a distinct address In these slides, I’ll use pseudo-address A pointer is a variable that contains a memory address x 1000 p ? ? 1004 1008 1012 1016
Pointers and Addresses // in C’s syntax: // x is declared as an integer int x = 88; x=88 ? ? 1000 1004 1008 1012 1016
Pointers and Addresses // in C’s syntax: // x is declared as an integer int x = 88; // p is declared as a pointer to an integer int *p; p=? ? ? x=88 ? ? 1000 1004 1008 1012 1016
Pointers and Addresses // in C’s syntax: // x is declared as an integer int x = 88; // p is declared as a pointer to an integer int *p; // p points to x p = &x; p=1000 // Question: could we write this? p = (int *)1000; x=88 ? ? 1000 1004 1008 1012 1016
Dereference // symbol * has another meaning as dereference int x = 88; int *p; // p’s value is junk p = &x; // *p takes the value in // the memory slot p points to int y = *p; p=1000 x=88 ? ? 1000 1004 1008 1012 1016
Dereference int x = 88; int *p; p = &x; // here, *p and x denotes the same memory slot // as we can see: *p = 99; x=99 1000 ? 1004 // or try this: p=1000 ? 1008 ++(*p); ? 1012 ? 1016
Pointer Assignment // Pointers are just ordinary variables, so // they could also be used in assignment int x = 88; int *p, *q, *r; p = &x; q = p; r = q + 1; q=1000 p=1000 r=1004 x=88 ? ? 1000 1004 1008 1012 1016
Pointers and Function Arguments // C uses call-by-value strategy. So arguments // from caller are not changeable. Consider: void swap (int x, int y) x==3 y==5 { int temp; temp = x; x = y; y = temp; } // and a call: swap (a=3, b=5); a==3 b==5
Pointers and Function Arguments // C uses call-by-value strategy. So arguments // from caller are not changeable. Consider: void swap (int x, int y) x==5 y==3 { int temp; temp = x; x = y; y = temp; } // and a call: swap (a=3, b=5); a==3 b==5
Pointers and Function Arguments // To achieve this using pointers: void swap (int *x, int *y) { x: 2000 y: 8400 int temp; temp = *x; *x = *y; *y = temp; } // and a call: swap (&a, &b); a==3 b==5
Pointers and Function Arguments // To achieve this using pointers: void swap (int *x, int *y) { x: 2000 y: 8400 int temp; temp = *x; *x = *y; *y = temp; } // and a call: swap (&a, &b); a==5 b==3
Pointers and Function Arguments n In summary, pointer arguments make it possible: n n n to access data in the caller to change values of arguments to return values implicitly n See next slide for an example
Pointers and Function Arguments // implicit returned values: void sum (int x, int y, int *result) { *result = x + y; return; } // the caller: int s; sum (3, 4, &s); // everywhere in system code
Pointers and Arrays a int a[5]; int *p; p p = &(a[0]); ? ? ? 0 1 2 3 4
Pointers and Arrays int a[5]; int *p; p = &(a[0]); // the assignments *p = 88; // and a[0] = 88; // take the same effect a p 88 ? ? 0 1 2 3 4
Pointers and Arrays int a[5]; int *p; a p 88 77 ? ? 0 1 2 p = &(a[0]); 3 // we could also do arithmetic ? 4 // operations on pointers, as in: *(p+1) = 77; // recall that the compiler automatically moves // the pointer p to an appropriate location.
Pointers and Arrays int a[5]; int *p; a p 88 77 ? ? 0 1 2 p = &(a[0]); 3 // By definition, the value of an ? 4 // array variable a equals the address // of a’s first element. So the above // code is equivalent to: p = a; // However, a is not changeable, this is illegal: a++;
Arrays as Function Arguments // array as function argument is essentially a // pointer to the first element of the array. So void foo (int a[]) { …; } // could also be written as: void foo (int *a) { …; }
Address Arithmetic // More forms of address arithmetic: int *p; int i; // increment: p + i; // decrement: p – i; // substraction int *q; p – q; // or: q – p;
Character Pointers and Functions // Recall that a string s is a sequence of // characters terminated with a null char . And // the storage it occupies is one more than the // characters in the string. So, “hello, world” // will occupy 12 bytes, rather than 11. // Any string s passed as argument to a function // is the address of the first element of s. So printf (“hello, worldn”); // could roughly reads: char *s = “hello, worldn”; printf (s);
String Copy // copy from src to dst void str. Copy (char *dst, char *src) { int i = 0; // recall the relationship between pointer // and array while (dst[i]=src[i]) i++; return; }
String Copy // A pointer-based version: void str. Copy (char *dst, char *src) { while (*dst=*src) { dst++; src++; } return; }
String Copy // Or even: void str. Copy (char *dst, char *src) { while (*dst++ = *src++) ; return; }
Pointer Arrays; Pointers to Pointers // An array could contain pointers, as in: int *(a[10]); // a is an array containing 10 pointers to // integers. And we may write a summation func: sum = 0; for (int i=0; i<10; i++) sum += *(a[i]);
Pointer Arrays; Pointers to Pointers // Pointer Arrays to string: char *(a[10]); // a print function printing all strings for (int i=0; i<10; i++) printf (“%sn”, a[i]); // Rethink the prototype of main function: int main (int argc, char *argv[]); // argc is the numbers of command arguments, // including the name of the executable, with all // arguments (an array of pointers to string) // stored in argv.
Pointer Arrays; Pointers to Pointers // Sample program: int main (int argc, char *argv[]) { for (int i=0; i<argc; i++) printf (“argv[%d]=%sn”, i, argv[i]); return 0; } // Compile this program, and // run it (on Linux): $. /a. out hello world // or (on Windows): c: a. exe hello world
Pointers to Functions n Besides for calling, in essence, a C function could be: n n n assigned to other variables stored in data structures passed as arguments returned from functions But could not nest n n Though some compilers support this feature In the following slides, we’d see how to do all these really cool things n n Essential to understand OO languages, say C++ or Java And functional languages, say ML or F#
What’s a Function in Memory? // A function is // essentially a // pointer! int sum (int x, int y) { int temp; temp = x + y; return temp; } // Roughly as right: 1000 sum: temp=x+y 1004 return temp 1008 ? 1012 ? 1016
Function Variable Declaration // Syntax for Function variable declaration: type (*name)(type 1, …, typen); // Example: int (*f) (int, int); // Or, much simpler: : -) typedef type (*ty. Name) (type 1, …, typen); ty. Name f. Name; // Example again: typedef int (*ty. Fun) (int, int); ty. Fun f; // We’d like to discuss “typedef” in next slide, // for now, I’ll make use of the raw form.
Function Variable Assignment int sum (int x, int y) { int temp = x + y; return temp; } int main () { int (*f 1)(int, int); int (*f 2)(int, int); f 1 = ∑ f 2 = sum; return 0; } f 1 f 2 1000 1004 sum: temp=x+y return temp 1008 ? 1012 ? 1016
Function Variable Call int sum (int x, int y) { int temp = x+y; return temp; } int main() { int (*f)(int, int); f = sum; f (3, 4); (*f) (7, 8); // another form return 0; }
Function as Arguments // We cook a “higher order” functions: int hf (int x, int y, int (*f)(int, int)); // And the sameple definition of “high”: int hf (int x, int y, int (*f)(int, int)) { return f (x, y); }
Function as Arguments // First, I cook some functions: int sum (int i, int j) { return i+j; } int mult (int i, int j) { return i*j; } // Now I may call function “hf” with: hf (3, 4, sum); // or hf (3, 4, mult);
Function as Return Values // Functions can return functions: int (*f(int)) (int, int); int (*f(int kind)) (int, int) { switch (kind) { case 0: return sum; case 1: return mult; default: error (“…”); return NULL; }; }
Functions Stored in Data Structures // As the function name is just a pointer, so it // is possible to store functions in any other // data structures. // For instance: int (*A[3])(int, int); // declares a 3 -element array A, with each slot a // function of type “int * int -> int”. // Sample operations on this array A: A[0] = sum; A[1] = mult; A[2] = sum; // … and a call: A[1](8, 9);
Function Pointer Beyond (Note: This is NOT C) // Nested functions: int (*foo (int x))(int, int) { int local = 100; int bar (int y) { return local+y; } return bar; } // And a call: foo (3)(4); // Why C does not support this feature?
Summary n Function pointers make functions first-class: n n assignment passed as arguments, returned as results stored in data structures This mechanism make it possible to implement call back or dynamic code dispatch n n think objects and methods in C++/Java/C# more on this topic later
- Slides: 38