Download presentation
Presentation is loading. Please wait.
Published byΠαύλος Αλεξάκης Modified over 6 years ago
1
Pointers, Pointers, Pointers CSE 333 Spring 2018
Instructor: Justin Hsia Teaching Assistants: Danny Allen Dennis Shao Eddie Huang Kevin Bi Jack Xu Matthew Neldam Michael Poulain Renshu Gu Robby Marver Waylong Huang Wei Lin
2
Administrivia Exercise 2 out today and due Monday morning
Exercise grading We will do our best to keep up Things to watch for: Input sanity check No functional abstraction (single blob of code) Formatting funnies (e.g. tabs instead of spaces)
3
Administrivia Homework 0 due Monday, 4/2
Logistics and infrastructure for projects clint and valgrind will be useful for exercises, too Should have set up an ssh key and cloned their GitLab repo Do this ASAP so we have time to fix things if necessary Homework 1 out today, due in 2 weeks (Thu 4/12) Linked list and hash table implementations in C Get starter code using git pull in your course repo See CSE 333 Git Tutorial for tips Might have “merge conflict” if your local copy has unpushed changes
4
Administrivia Documentation: Folklore:
man pages, books Reference websites: cplusplus.org, man7.org, gcc.gnu.org, etc. Folklore: Google-ing, stackoverflow, that rando in lab Tradeoffs? Relative strengths & weaknesses? Discuss
5
Lecture Outline Pointers & Pointer Arithmetic Pointers as Parameters
Pointers and Arrays Function Pointers
6
Box-and-Arrow Diagrams
boxarrow.c int main(int argc, char** argv) { int x = 1; int arr[3] = {2, 3, 4}; int* p = &arr[1]; printf("&x: %p; x: %d\n", &x, x); printf("&arr[0]: %p; arr[0]: %d\n", &arr[0], arr[0]); printf("&arr[2]: %p; arr[2]: %d\n", &arr[2], arr[2]); printf("&p: %p; p: %p; *p: %d\n", &p, p, *p); return 0; } Draw out (ink) boxes for x, arr, and p. Where are these located? address name value
7
Box-and-Arrow Diagrams
boxarrow.c int main(int argc, char** argv) { int x = 1; int arr[3] = {2, 3, 4}; int* p = &arr[1]; printf("&x: %p; x: %d\n", &x, x); printf("&arr[0]: %p; arr[0]: %d\n", &arr[0], arr[0]); printf("&arr[2]: %p; arr[2]: %d\n", &arr[2], arr[2]); printf("&p: %p; p: %p; *p: %d\n", &p, p, *p); return 0; } stack frame for main() These are local variables, so located on the Stack in some ordering. Let’s fill in the values. address name value &arr[2] arr[2] value &arr[1] arr[1] &arr[0] arr[0] &p p &x x
8
Box-and-Arrow Diagrams
boxarrow.c int main(int argc, char** argv) { int x = 1; int arr[3] = {2, 3, 4}; int* p = &arr[1]; printf("&x: %p; x: %d\n", &x, x); printf("&arr[0]: %p; arr[0]: %d\n", &arr[0], arr[0]); printf("&arr[2]: %p; arr[2]: %d\n", &arr[2], arr[2]); printf("&p: %p; p: %p; *p: %d\n", &p, p, *p); return 0; } Now let’s fill in the addresses. Don’t forget about ASLR – address randomization! address name value &arr[2] arr[2] 4 &arr[1] arr[1] 3 &arr[0] arr[0] 2 &p p &x x 1
9
Box-and-Arrow Diagrams
boxarrow.c int main(int argc, char** argv) { int x = 1; int arr[3] = {2, 3, 4}; int* p = &arr[1]; printf("&x: %p; x: %d\n", &x, x); printf("&arr[0]: %p; arr[0]: %d\n", &arr[0], arr[0]); printf("&arr[2]: %p; arr[2]: %d\n", &arr[2], arr[2]); printf("&p: %p; p: %p; *p: %d\n", &p, p, *p); return 0; } Don’t forget about ASLR – address randomization! Draw arrow from value of p to address of arr[1]. address name value 0x7fff…78 arr[2] 4 0x7fff…74 arr[1] 3 0x7fff…70 arr[0] 2 0x7fff…68 p 0x7fff…64 x 1
10
Pointer Arithmetic Pointers are typed
Tells the compiler the size of the data you are pointing to Exception: void* is a generic pointer (i.e. a placeholder) Pointer arithmetic is scaled by sizeof(*p) Works nicely for arrays Does not work on void*, since void doesn’t have a size! Valid pointer arithmetic: Add/subtract an integer to a pointer Subtract two pointers (within stack frame or malloc block) Compare pointers (<, <=, ==, !=, >, >=), including NULL Everything else is illegal since it doesn’t make sense for addresses.
11
Practice Question boxarrow2.c
int main(int argc, char** argv) { int arr[3] = {2, 3, 4}; int* p = &arr[1]; int** dp = &p; // pointer to a pointer *(*dp) += 1; p += 1; return 0; } At this point in the code, what values are stored in arr[]? 0x7fff…78 arr[2] 4 0x7fff…74 arr[1] 3 0x7fff…70 arr[0] 2 Don’t forget about ASLR – address randomization! address name value 0x7fff…68 p 0x7fff…74 0x7fff…60 dp 0x7fff…68
12
Practice Solution boxarrow2.c
Note: arrow points to next instruction to be executed. Practice Solution boxarrow2.c int main(int argc, char** argv) { int arr[3] = {2, 3, 4}; int* p = &arr[1]; int** dp = &p; // pointer to a pointer *(*dp) += 1; p += 1; return 0; } 0x7fff…78 arr[2] 4 0x7fff…74 arr[1] 3 0x7fff…70 arr[0] 2 4 Don’t forget about ASLR – address randomization! address name value 0x7fff…68 p 0x7fff…74 0x7fff…60 dp 0x7fff…68
13
Practice Solution boxarrow2.c
Note: arrow points to next instruction to be executed. Practice Solution boxarrow2.c int main(int argc, char** argv) { int arr[3] = {2, 3, 4}; int* p = &arr[1]; int** dp = &p; // pointer to a pointer *(*dp) += 1; p += 1; return 0; } 0x7fff…78 arr[2] 4 0x7fff…74 arr[1] 0x7fff…70 arr[0] 2 Don’t forget about ASLR – address randomization! address name value 0x7fff…68 p 0x7fff…74 0x7fff…60 dp 0x7fff…68
14
Practice Solution boxarrow2.c
Note: arrow points to next instruction to be executed. Practice Solution boxarrow2.c int main(int argc, char** argv) { int arr[3] = {2, 3, 4}; int* p = &arr[1]; int** dp = &p; // pointer to a pointer *(*dp) += 1; p += 1; return 0; } 0x7fff…78 arr[2] 4 0x7fff…74 arr[1] 0x7fff…70 arr[0] 2 Don’t forget about ASLR – address randomization! address name value 0x7fff…68 p 0x7fff…78 0x7fff…60 dp 0x7fff…68
15
Practice Solution boxarrow2.c
Note: arrow points to next instruction to be executed. Practice Solution boxarrow2.c int main(int argc, char** argv) { int arr[3] = {2, 3, 4}; int* p = &arr[1]; int** dp = &p; // pointer to a pointer *(*dp) += 1; p += 1; return 0; } 5 0x7fff…78 arr[2] 4 0x7fff…74 arr[1] 0x7fff…70 arr[0] 2 Don’t forget about ASLR – address randomization! address name value 0x7fff…68 p 0x7fff…78 0x7fff…60 dp 0x7fff…68
16
Endianness Memory is byte-addressed, so endianness determines what ordering that multi-byte data gets read and stored in memory Big-endian: Least significant byte has highest address Little-endian: Least significant byte has lowest address Example: 4-byte data 0xa1b2c3d4 at address 0x100 0x100 0x101 0x102 0x103 Big-Endian a1 b2 c3 d4 0x100 0x101 0x102 0x103 Little-Endian d4 c3 b2 a1
17
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] arr[1] arr[0] char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c
18
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c
19
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c
20
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c
21
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c int_ptr: 0x0x7ffffffde010 *int_ptr: 1
22
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c int_ptr: 0x0x7ffffffde014 *int_ptr: 2
23
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c int_ptr: 0x0x7ffffffde01C *int_ptr: ???
24
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c char_ptr: 0x0x7ffffffde010 *char_ptr: 1
25
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c char_ptr: 0x0x7ffffffde011 *char_ptr: 0
26
Pointer Arithmetic Example
Note: Arrow points to next instruction. Pointer Arithmetic Example Stack (assume x86-64) int main(int argc, char** argv) { int arr[3] = {1, 2, 3}; int* int_ptr = &arr[0]; char* char_ptr = (char*) int_ptr; int_ptr += 1; int_ptr += 2; // uh oh char_ptr += 1; char_ptr += 2; return 0; } arr[2] 03 00 arr[1] 02 arr[0] 01 char_ptr int_ptr The provided code has printf statements after every pointer manipulation. x86-64 is little-endian! pointerarithmetic.c char_ptr: 0x0x7ffffffde013 *char_ptr: 0
27
Lecture Outline Pointers & Pointer Arithmetic Pointers as Parameters
Pointers and Arrays Function Pointers
28
C is Call-By-Value C (and Java) pass arguments by value
Callee receives a local copy of the argument Register or Stack If the callee modifies a parameter, the caller’s copy isn’t modified void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ...
29
Broken Swap brokenswap.c Note: Arrow points to next instruction.
OS kernel [protected] Stack main brokenswap.c void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
30
Broken Swap brokenswap.c a 42 b -7 OS kernel [protected] Stack main
void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
31
Broken Swap brokenswap.c a 42 b -7 a 42 b -7 tmp ??
OS kernel [protected] Stack main a 42 b -7 swap a 42 b -7 brokenswap.c tmp ?? void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
32
Broken Swap brokenswap.c a 42 b -7 a 42 b -7 tmp 42
OS kernel [protected] Stack main a 42 b -7 swap a 42 b -7 brokenswap.c tmp 42 void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
33
Broken Swap brokenswap.c a 42 b -7 a -7 b -7 tmp 42
OS kernel [protected] Stack main a 42 b -7 swap a -7 b -7 brokenswap.c tmp 42 void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
34
Broken Swap brokenswap.c a 42 b -7 a -7 b 42 tmp 42
OS kernel [protected] Stack main a 42 b -7 swap a -7 b 42 brokenswap.c tmp 42 void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
35
Broken Swap brokenswap.c a 42 b -7 OS kernel [protected] Stack main
void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
36
Faking Call-By-Reference in C
Can use pointers to approximate call-by-reference Callee still receives a copy of the pointer (i.e. call-by-value), but it can modify something in the caller’s scope by dereferencing the pointer parameter void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... void swap(int a, int b) { int tmp = a; a = b; b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(a, b); ...
37
Fixed Swap swap.c a 42 b -7 Note: Arrow points to next instruction.
OS kernel [protected] Stack main a 42 b -7 swap.c void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
38
Fixed Swap swap.c a 42 b -7 a b tmp ?? OS kernel [protected] Stack
main a 42 b -7 swap a b swap.c tmp ?? void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
39
Fixed Swap swap.c a 42 b -7 a b tmp 42 OS kernel [protected] Stack
main a 42 b -7 swap a b swap.c tmp 42 void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
40
Fixed Swap swap.c a -7 b -7 a b tmp 42 OS kernel [protected] Stack
main a -7 b -7 swap a b swap.c tmp 42 void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
41
Fixed Swap swap.c a -7 b 42 a b tmp 42 OS kernel [protected] Stack
main a -7 b 42 swap a b swap.c tmp 42 void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
42
Fixed Swap swap.c a -7 b 42 OS kernel [protected] Stack main
void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int main(int argc, char** argv) { int a = 42, b = -7; swap(&a, &b); ... Heap Read/Write Segment .data, .bss Read-Only Segment .text, .rodata
43
Lecture Outline Pointers & Pointer Arithmetic Pointers as Parameters
Pointers and Arrays Function Pointers
44
Pointers and Arrays A pointer can point to an array element
You can use array indexing notation on pointers ptr[i] is *(ptr+i) with pointer arithmetic – get the data i elements forward from ptr An array name will provide the beginning address of the array Like a pointer to the first element of array, but can’t change int a[] = {10, 20, 30, 40, 50}; int* p1 = &a[3]; // refers to a's 4th element int* p2 = &a[0]; // refers to a's 1st element int* p3 = a; // refers to a's 1st element *p1 = 100; *p2 = 200; p1[1] = 300; p2[1] = 400; p3[2] = 500; // final: 200, 400, 500, 100, 300
45
Array Parameters Array parameters are actually passed as pointers to the first array element The [] syntax for parameter types is just for convenience This code: Equivalent to: void f(int a[]); int main( ... ) { int a[5]; ... f(a); return 0; } void f(int a[]) { void f(int* a); int main( ... ) { int a[5]; ... f(&a[0]); return 0; } void f(int* a) {
46
Lecture Outline Pointers & Pointer Arithmetic Pointers as Parameters
Pointers and Arrays Function Pointers
47
Function Pointers Based on what you know about assembly, what is a function name, really? Can use pointers that store addresses of functions! Generic format: Looks like a function prototype with extra * in front of name Why are parentheses around (* name) needed? Using the function: Calls the pointed-to function with the given arguments and return the return value returnType (* name)(type1, …, typeN) (*name)(arg1, …, argN)
48
Function Pointer Example
map() performs operation on each element of an array #define LEN 4 int negate(int num) {return -num;} int square(int num) {return num*num;} // perform operation pointed to on each array element void map(int a[], int len, int (* op)(int n)) { for (int i = 0; i < len; i++) { a[i] = (*op)(a[i]); // dereference function pointer } int main(int argc, char** argv) { int arr[LEN] = {-1, 0, 1, 2}; int (* op)(int n); // function pointer called 'op' op = square; // function name returns addr (like array) map(arr, LEN, op); ... funcptr parameter funcptr dereference funcptr definition funcptr assignment map.c
49
Extra Exercise #1 Use a box-and-arrow diagram for the following program and explain what it prints out: #include <stdio.h> int foo(int* bar, int** baz) { *bar = 5; *(bar+1) = 6; *baz = bar + 2; return *((*baz)+1); } int main(int argc, char** argv) { int arr[4] = {1, 2, 3, 4}; int* ptr; arr[0] = foo(&arr[0], &ptr); printf("%d %d %d %d %d\n", arr[0], arr[1], arr[2], arr[3], *ptr); return 0;
50
Extra Exercise #2 Write a program that determines and prints out whether the computer it is running on is little-endian or big-endian. Hint: pointerarithmetic.c from today’s lecture or show_bytes.c from 351
51
Extra Exercise #3 Write a function that:
Arguments: [1] an array of ints and [2] an array length Malloc’s an int* array of the same element length Initializes each element of the newly-allocated array to point to the corresponding element of the passed-in array Returns a pointer to the newly-allocated array
52
Extra Exercise #4 Write a function that:
Accepts a function pointer and an integer as arguments Invokes the pointed-to function with the integer as its argument
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.