CS50 Week 4 Explained: Pointers, Memory and Files in C
Week 4 is where many people stall, and it's also where CS50 starts to pay off. Until now, CS50's string type has hidden something from you. This week takes that away and shows what's underneath: every value lives at a numbered location in memory, and you can work with those locations directly. Take this week slowly. Watching the lecture twice is normal.

Jump to the key moments
- 4:37Hexadecimal
- 11:44Memory
- 18:05Pointers
- 31:28Strings
- 43:34Pointer arithmetic
- 57:11Copying and malloc
- 1:13:17Valgrind
- 1:25:25Pointer Fun with Binky
- 1:33:28Swapping
- 2:02:20File I/O
Hexadecimal and addresses
Memory is a long row of bytes, each with a numbered address. Addresses are usually written in hexadecimal (base 16, digits 0 to 9 and then a to f), because one hex digit is exactly four bits, so two hex digits make exactly one byte. The prefix 0x tells you a number is written in hex: 0x1F is 31.
Pointers
A pointer is a variable whose value is an address. Two operators do all the work. &x means "the address of x", and *p means "go to the address stored in p". So int *p = &x; makes p point at x, and *p = 5; changes x without mentioning it by name. The "Pointer Fun with Binky" chapter is a short clay animation that makes this stick. Rewatch it whenever you're confused.
The secret of strings
CS50's string type is really char *: a pointer to the first character. That explains two puzzles. Comparing two strings with == compares their addresses, not their letters (use strcmp for that). And "copying" a string with = copies only the address, so both names point at the same letters, and changing one changes both.
malloc, free and Valgrind
To make a real copy, you ask for new memory with malloc (remembering one extra byte for the NUL), copy the characters over, and hand the memory back with free when you're done. Forget to free it and you have a memory leak. Valgrind is a tool that runs your program and reports leaks and invalid reads or writes. Get into the habit of running it on everything from here to Week 5.
Uninitialised variables contain garbage values: whatever bits were already there. Always give a variable a value before you read it.
Passing by value, and the swap problem
When you pass a variable to a function, C passes a copy. So a swap(a, b) function that swaps its own copies achieves nothing. The fix is to pass the addresses, swap(&a, &b), so the function can change the originals. This is where the lecture explains memory layout: function calls live on the stack, and memory from malloc lives on the heap. Too many nested calls causes a stack overflow, and writing past the end of an array causes a buffer overflow.
Files
fopen, fread, fwrite and fclose let you read and write bytes directly. Every file format (images, audio) is just bytes in an agreed layout, and this problem set has you work with three of them.
Problem Set 4: what it asks
- Volume: change the volume of a WAV audio file by copying its 44-byte header, then scaling each sample.
- One of Filter (less comfortable), which applies grayscale, sepia, reflect and blur to a bitmap image, or Filter (more comfortable), which swaps sepia for edge detection.
- Recover: pull deleted JPEG photos back out of a raw memory-card image.
Where people get stuck
- Filter's blur: if you change pixels in place, the next pixel's average uses values you've already blurred. Work from a copy of the original image. Take care at the edges and corners, where a pixel has fewer neighbours.
- Colour values over 255: sepia and edge detection can produce numbers too big for a byte. Cap them before storing them, and round rather than truncate.
- Recover: the card is read in fixed-size blocks, and a new JPEG starts wherever a block begins with the JPEG signature described in the spec. Write down, in plain English, what should happen when you find a signature, when you're partway through a file, and when you reach the end. Then code those three cases.
- Segmentation faults: you touched memory that isn't yours, usually through an uninitialised pointer, a NULL result from fopen or malloc that you didn't check, or an off-by-one index. Run Valgrind or debug50 to find the line.
Check yourself
If int x = 50; and int *p = &x;, what is *p, and what is p?
*p is 50, the value at the address. p is the address itself, something like 0x7ffc....
Why does if (s == t) say two identical words are different?
Strings are pointers, so == compares the two addresses. Two separate copies of "hi" live at different addresses. Use strcmp.
What's wrong with malloc(strlen(s)) for a copy of s?
It's one byte short. You also need room for the NUL terminator: strlen(s) + 1.
Why doesn't a swap function that takes two ints work?
It receives copies, and swaps the copies. The originals never change. Pass pointers to them instead.
Images are just numbers, and AI image models are too. Try Creative Lab to see how prompts turn into pictures.
Open Creative Lab →