Skip to content

CS50 Week 4: Memory

Pointers, pointers, pointers!

Written by Eva Dee on (about a 13 minute read).

Hexadecimal permalink

  • We use hexadecimal notation to talk about computer memory.
  • Base 16, hexadecimal base (0 - f) Remember ints are four byes.
  • One hexadecimal digit is equivalent to four binary digits
  • If you are using hexadecimal, the convention is to prefix every value with 0x
  • So... the hex color values are just the hexadecimal RGB values (and in a different format)!
  • In C memory, values are stored in hexadecimal.

Pointers permalink

  • A pointer is a variable that contains the address of some other value.
  • & "the address of" operator (we use it every time we want to check what address a variable is stored at)
  • * "go to the address of" operator(for telling your program to look inside a particular memory address). Also known as the dereferencing operator.
  • %p - aka pointer - for the placeholder value to be interpreted as hexadecimal
int n = 50;
prinf("%p\n", &n)
// returns eg: 0x123456789

// this will just print out 50
prinf("%i\n", *&n)

And if you want to store the address of some variable inside another variable, you would use a pointer (an int star variable):

int n = 50;
int *p = &n;

// and to print the value stored at p
// get the value at the address
prinf("%i\n", *p)
  • If you are getting the address of something, you must store it in a pointer (*).
  • Pointers have 64 bits (the equivalent of a long)

A string is defined as back-to-back-to-back characters (one byte away, since a char take one byte of space in C).

  • 🤯 strings are just pointers pointing to the first character in the string
  • the null terminating character signifies the end
int n = 50;
int *p = &n;

string s = "EMMA";
char *s = "EMMA";
typedef char *string;

🔈 NEW STRING DEFINITION: A string is a variable that contains the address of a character, aka char *

char *s = "EMMA";
printf("%p\n", s); // the address of the char
printf("%p\n, &s[0]); // the address of the 1st char (same as ^)

printf("%c\n", *s); // prints "E"

// pointer arithmetic
printf("%c\n", *(s+1)); // prints "M"
  • when you're comparing two strings, if you just compare them like this s == t you are comparing their addresses in the memory, meaning these two strings will never be the same! (that's why you need to use strcmp() instead)
// changing one, will change the other
char *s = get_string("s: ");
char *t = s;
t[0] = toupper(t[0]);

Malloc() permalink


// copying a string in c
// without using strcopy()
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
char *s = get_string("s: ");

char *t = malloc(strlen(s) + 1);

// when allocating memory always check that malloc
// is giving you back a valid memory address and not NULL
if (t == NULL)
{
return 1;
}
// we need to include \0 that's why n + 1
// or i <= n
for (int i = 0, n = strlen(s); i < n + 1; i++)
{
t[i] = s[i];
}

if (strlen(t) > 0)
{
t[0] = toupper(t[0]);
}

printf("s: %s\n", s);
printf("t: %s\n", t);

free(t);
}

malloc() - memory allocate free() - freeing the memory previously allocated strcpy(str1, str2) - for copying strings

**Anytime you use malloc(), you must use free() afterward.

Debugging permalink

  • valgrind debugging tool helps you debug invalid reads, invalid writes, segmentation faults, or memory leaks (aka when you've allocated more memory than you have freed)
  • to run it: valgrind ./hi
  • You can preface it with cs50 to get a more helpful output.

🤔 What is a garbage value?

  • Anytime that you don't initialize the value of a variable
  • If you try to dereference and uninitialized variable, your program might crash.
  • Ergo, you should always initialize values before touching them (read/write) in any way 👍

int *x = malloc(10 * sizeof(int));
// allocate enough memory for 10 integers, and then
// store the address of that chunk of memory
// in a pointer called x.

🤔 What is a buffer overflow?

When you are overflowing the allocated memory (either stack overflow or heap overflow)

Computer memory permalink

In terms of standard order (you can imagine it going top to bottom):

  • machine code (the 0s and 1s representing your program)
  • globals (global variables)
  • heap (this where you can allocate/free the memory from/to with malloc) - can lead to heap overflow
  • stack - the memory for your functions, variables, parameters (can lead to stack overflow)
// swapping values in C
// note you must use pointers!
// otherwise only params a, b will be changed
// but the original x, y will remain as they were
// you wouldn't need pointers if you did all
// the swapping inside main
#include <stdio.h>

void swap(int *a, int *b);

int main(void)
{
int x = 1;
int y = 2;

printf("x is %i, y is %i\n", x, y);
swap(&x, &y);
printf("x is %i, y is %i\n", x, y);
}

void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}

// vs naive, old version of swap
// that doesn't change x, y
void swap(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}

Meaning! If you use the stack's memory you save yourself the trouble of having to do malloc() AND free() 🤯

	char s[4];
// vs
char *s = malloc(4);

CS50 Library permalink

All the CS50 get libraries (get_int, get_string), were there to help you with pointers. Equivalent of get_int:

int x;
prinf("x: ");
scanf("%i", &x);
prinf("x: %i\n", x);

for get_string:

char s[5];
prinf("s: ");
scanf("%s", s);
prinf("s: %s\n", s);

File I/O permalink

	// C does come with a pointer type FILE
// that... 🥁 points to a file
FILE *file = fopen("phonebook.csv", "a");

// always check for NULL
if (file == NULL)
{
return 1;
}

This is how you define a BYTE:

	typedef uint8_t BYTE;

🤔 How do you recognize a jpg file?

The first three bytes of any .jpg files are: 0xff, 0xd8 and 0xff.

🤔 What is a bitmap?

A map of bits 🥁

And, finally, this is how you copy a file, one byte at a time:

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

typedef uint8_t BYTE;

int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 3)
{
fprintf(stderr, "Usage: copy SOURCE DESTINATION\n");
return 1;
}

// open input file
FILE *source = fopen(argv[1], "r");
if (source == NULL)
{
printf("Could not open %s.\n", argv[1]);
return 1;
}

// Open output file
FILE *destination = fopen(argv[2], "w");
if (destination == NULL)
{
fclose(source);
printf("Could not create %s.\n", argv[2]);
return 1;
}

// Copy source to destination, one BYTE at a time
BYTE buffer;
while (fread(&buffer, sizeof(BYTE), 1, source))
{
fwrite(&buffer, sizeof(BYTE), 1, destination);
}

// Close files
fclose(source);
fclose(destination);
return 0;
}