class: center, middle # CMPE 30: Lecture 3 Pointers --- # Review: What does this print? ```c char s[] = "Ghostbusters"; printf("%zu %zu\n", strlen(s), sizeof(s)); ``` 1. `12 12` 1. `12 13` 1. `13 12` 1. `13 13` 1. Ben got this wrong --- # Learning Objectives - Define a pointer as a variable holding an address - Use `&` and `*` - Draw a memory diagram - Explain array decay and pointer arithmetic - Use `->` for struct members - Pass a pointer to modify a caller's variable --- # What Is a Pointer? - A variable whose value is a memory address - All pointers are the same size on a given system - The base type describes what's at the address, not the pointer itself - Nothing magical --- just a number --- # Declaring Pointers ```c int *p; // pointer to int char *s; // pointer to char double *d; // pointer to double ``` **Trap:** `*` binds to the variable. ```c int *p, q; // p is int*, q is int ``` ```c int *p, *q; // both are int* ``` --- # & and * .lc[ ```c int score = 100; int *p = &score; printf("%d\n", *p); // 100 *p = 200; printf("%d\n", score); // 200 ``` ] .rc[ - Declaration `*` = "pointer" - Expression `*` = "follow it" - `&x` = "address of `x`" - Modifying through `p` modifies `score` ] --- # Pointers to Pointers ```c int val = 42; int *p = &val; int **pp = &p; printf("%d\n", **pp); // 42 ``` - `main(int argc, char **argv)` uses one - Dereference twice to reach the `int` --- # Memory Diagram ``` Variable Address Value x 0x1000 1985 y 0x1004 80 p 0x1008 0x1000 -> x pp 0x1010 0x1008 -> p -> x ``` - `*p` reaches `x` - `**pp` reaches `x` - `&p` is `0x1008`, not `0x1000` --- # NULL ```c int *p = NULL; if (p) { printf("%d\n", *p); } ``` - Dereferencing `NULL` is **undefined** (usually segfault) - `nullptr`: C++11; C added it in C23 --- most C code uses `NULL` --- # Pointers and Arrays .lc[ ```c int nums[] = {10,20,30,40,50}; int *p = nums; // decay printf("%d\n", *p); // 10 printf("%d\n", *(p + 1)); // 20 printf("%d\n", p[2]); // 30 ``` ] .rc[ - Array name decays to `&nums[0]` - `a[i]` == `*(a + i)` - `[]` works on pointers too - Bounds are your problem ] --- # Pointer Arithmetic ```c int *p = nums; // points at nums[0] p++; // now at nums[1] ``` - `p + 1` advances by `sizeof(*p)` bytes - `int *`: if `int` is 4 bytes, `p++` moves 4 bytes - `char *` moves 1 byte (guaranteed); `double *` typically 8 - You never multiply by byte size yourself **Wut:** `2[nums]` works --- it is `*(2 + nums)` --- # Structs via Pointers .lc[ ```c struct song { char title[40]; int year; }; struct song t = { "Karma Chameleon", 1983 }; struct song *p = &t; ``` ] .rc[ ```c (*p).title // works, ugly p->title // idiomatic ``` - `.` binds tighter than `*`, so `(*p).x` needs parens - `p->x` is just `(*p).x` - You will see `->` everywhere ] --- # Pass by Value .lc[ ```c void increment(int *x) { (*x)++; } int score = 99; increment(&score); // score is now 100 ``` ] .rc[ - C++: `void increment(int &x)` --- C has no references - Every C parameter is copied - To modify caller's variable: pass a pointer - Function gets a **copy** of the address - Both addresses point at the same memory ] --- # The Classic: swap .lc[ ```c void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; } int x = 3, y = 7; swap(&x, &y); // x is 7, y is 3 ``` ] .rc[ - In C++ you would take `int &` - C has no references --- pass pointers - Caller opts in with `&x`, `&y` - `*a` and `*b` name the caller's memory ] --- # Common Bug ```c int *get_value(void) { int result = 42; return &result; // DANGLING } ``` - `result` lives on the stack - Its memory is reclaimed when the function returns - Returned pointer points at garbage - Fix: return the value, use an out-param, or `malloc` (lectures 5+6) --- # What does this print? ```c int a[] = {10, 20, 30, 40, 50}; int *p = a + 2; printf("%d %d %d\n", *p, *(p - 1), p[1]); ``` 1. `30 20 40` 1. `20 10 30` 1. `3 1 4` 1. `30 40 20` 1. Ben got this wrong --- # Where is the bug? ```c struct song { char title[40]; int year; }; struct song *p = NULL; printf("%s\n", p->title); ``` 1. Missing `&` on `p` 1. `->` should be `.` 1. Dereferencing NULL is undefined 1. `title` is not initialized 1. Ben got this wrong --- # On 64-bit, sizeof(int *) is? 1. 2 1. 4 1. 8 1. Depends on the int it points to 1. Ben got this wrong --- # Key Points - Pointer = variable holding an address - `*` declaration: pointer; expression: follow it - `a[i]` is `*(a + i)` - Pointer arithmetic moves in units of the pointed-to type - `p->x` is `(*p).x` - Pass a pointer to let a function modify your variable - Never return the address of a local **Read:** chapter 7 of *Gorgo C for C++ Programmers*. **Do:** exercises 1-7.