Tutorial 6 Memory Addresses and Pointers scanf() function Perils of Pointers Function Pointers Declarations vs. Definitions CS 136 Spring 2018 Tutorial 6 1
Memory Addresses and Pointers A pointer can be declared by placing an indirection operator (*) before the identifier. C requires you to specify the type of the value stored at an address. int i = 42; int *p = &i; Note that in this example we are declaring the variable named p of the type int *. You can get the starting address of where the value of an identifier is stored in memory by using the address operator (&). CS 136 Spring 2018 Tutorial 6 2
Memory Addresses and Pointers To get the value of what a pointer "points at", we use the indirection operator (*). This is often known as the deference operator and it is the inverse of the address operator (&). // To print the value p is pointing at printf("the value of i is: %d", *p); CS 136 Spring 2018 Tutorial 6 3
Pointers as Function Parameters Allows functions to mutate variables that live outside the function. Allows functions to avoid copying large structures. CS 136 Spring 2018 Tutorial 6 4
Example: Mutating Values in Functions Compare these two segments of code void inc(int p) { p += 1; } int main(void) { int x = 42; inc(x); printf("%d\n", x); } Output: 42 void inc(int *p) { *p += 1; } int main(void) { int x = 42; inc(&x); printf("%d\n", x); } Output: 43 CS 136 Spring 2018 Tutorial 6 5
Example: Call Stacks with Pointers Trace the content of the Call Stack for the following program 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } CS 136 Spring 2018 Tutorial 6 6
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } p1: p2:.x = 3.y = 4.x = 5.y = 6 CS 136 Spring 2018 Tutorial 6 7
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 3.y = 4 p2: [addr_2].x = 5.y = 6 CS 136 Spring 2018 Tutorial 6 8
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_int: i: addr_3 j: addr_4 temp:? return address: swap_posn:9 swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 3 [addr_3].y = 4 p2: [addr_2].x = 5 [addr_4].y = 6 CS 136 Spring 2018 Tutorial 6 9
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 * i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_int: i: addr_3 j: addr_4 temp: 3 return address: swap_posn:9 swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 3 [addr_3].y = 4 p2: [addr_2].x = 5 [addr_4].y = 6 CS 136 Spring 2018 Tutorial 6 10
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 * j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_int: i: addr_3 j: addr_4 temp: 3 return address: swap_posn:9 swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 4 p2: [addr_2].x = 5 [addr_4].y = 6 CS 136 Spring 2018 Tutorial 6 11
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 4 p2: [addr_2].x = 3 [addr_4].y = 6 CS 136 Spring 2018 Tutorial 6 12
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 4 p2: [addr_2].x = 3 [addr_4].y = 6 CS 136 Spring 2018 Tutorial 6 13
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_int: i: addr_5 j: addr_6 temp:? return address: swap_posn:10 swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 4 [addr_5] p2: [addr_2].x = 3 [addr_4].y = 6 [addr_6] CS 136 Spring 2018 Tutorial 6 14
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 * i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_int: i: addr_5 j: addr_6 temp: 4 return address: swap_posn:10 swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 4 [addr_5] p2: [addr_2].x = 3 [addr_4].y = 6 [addr_6] CS 136 Spring 2018 Tutorial 6 15
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 * j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_int: i: addr_5 j: addr_6 temp: 4 return address: swap_posn:10 swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 6 [addr_5] p2: [addr_2].x = 3 [addr_4].y = 6 [addr_6] CS 136 Spring 2018 Tutorial 6 16
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } swap_posn: p1: addr_1 p2: addr_2 return address: 16 p1: [addr_1].x = 5 [addr_3].y = 6 [addr_5] p2: [addr_2].x = 3 [addr_4].y = 4 [addr_6] CS 136 Spring 2018 Tutorial 6 17
Example: Call Stacks with Pointers 1 void swap_int(int *i, int *j) { 2 int temp = *i; 3 *i = *j; 4 *j = temp; 5 } 6 7 void swap_posn(struct posn *p1, 8 9 struct posn *p2) { swap_int(&(p1->x), &(p2->x)); 10 swap_int(&(p1->y), &(p2->y)); 11 } 12 13 int main(void) { 14 struct posn p1 = {3, 4}; 15 struct posn p2 = {5, 6}; 16 swap_posn(&p1, &p2); 17 } End of Stack Trace p1: [addr_1].x = 5 [addr_3].y = 6 [addr_5] p2: [addr_2].x = 3 [addr_4].y = 4 [addr_6] CS 136 Spring 2018 Tutorial 6 18
scanf() function Reads data and stores it based on the parameter format. Returns the number of values that have been successfully read. It returns EOF if it hits the end of the input. For example: (See Seashell) char char1; char char2; printf("enter a character:"); scanf("%c", &char1); // can read whitespace printf("the input is %c\n", char1); scanf(" %c", &char2); // ignores whitespace printf("the input is %c\n", char2); CS 136 Spring 2018 Tutorial 6 19
Perils of Pointers: Expired Scopes What will this program output when foo runs? When it doesn t run? // Get a bad address int *weird(int a) { return &a; } int main(void) { int p_content; int *p = weird(5); // #JUSTFOOTHINGS void foo(void) { int x = 1; } } //foo(); p_content = *p; printf("%d\n", p_content); CS 136 Spring 2018 Tutorial 6 20
Example: Perils of Pointers: Stack Trace Trace the content of the Call Stack for the following program 1 int *foo(int a) { 2 return &a; 3 } 4 5 int main(void) { 6 int x = 42; 7 int *p = foo(x); 8 printf("%d\n", *p); 9 } CS 136 Spring 2018 Tutorial 6 21
Example: Perils of Pointers: Stack Trace 1 int *foo(int a) { 2 return &a; 3 } 4 5 int main(void) { 6 int x = 42; 7 int *p = foo(x); 8 printf("%d\n", *p); 9 } x: 42 p:? CS 136 Spring 2018 Tutorial 6 22
Example: Perils of Pointers: Stack Trace 1 int *foo(int a) { 2 return &a; 3 } 4 5 int main(void) { 6 int x = 42; 7 int *p = foo(x); 8 printf("%d\n", *p); 9 } foo: a: 42 [addr] return address: 7 x: 42 p:? CS 136 Spring 2018 Tutorial 6 23
Example: Perils of Pointers: Stack Trace 1 int *foo(int a) { 2 return &a; 3 } 4 5 int main(void) { 6 int x = 42; 7 int *p = foo(x); 8 printf("%d\n", *p); 9 } End of Stack Trace x: 42 p: addr CS 136 Spring 2018 Tutorial 6 24
Example: Perils of Pointers: Stack Trace x: 42 p: addr Notice that the stack frame for main has a pointer to addr. However, the stack frame which contains the contents of addr has been popped. Accessing the contents of this memory will result in undefined behaviour. CS 136 Spring 2018 Tutorial 6 25
Function Pointers Functions are not first-class values in C. Function pointers, on the other hand, are. A function pointer stores the (starting) address of a function, which is an address in the code section of memory. The syntax to declare a function pointer with name fpname is: return_type (*fpname)(param1_type, param2_type,...) A function pointer can only point to a function that already exists. CS 136 Spring 2018 Tutorial 6 26
Problem: find_max Implement the function find_max(fp, lower, upper) on Seashell. The function does the following: // find_max(fp, lower, upper) returns the // maximum value of fp(x) in the range // [lower, upper] // requires: upper > lower CS 136 Spring 2018 Tutorial 6 27
Declarations vs. Definitions // Declaration: bool is_impossible(int power_level); // Definition: bool is_impossible(int power_level) { return (power_level > 9000); } CS 136 Spring 2018 Tutorial 6 28
Why? Reusability. Maintainability. Abstraction. CS 136 Spring 2018 Tutorial 6 29