Background

When a program is executed on your computer, it needs a certain amount of data to be stored at any specific point in time.

alt text

We humans know this as computer memory. For the sake of this course, we are going to simplify it in terms of lockers; the same lockers that you see at your local gym or at your physical campus.

Lockers have the following properties:

  • They are identified by a unique address.
  • They store a certain data type.

Locker addresses are, at the most basic level, just another 8-byte integer data type. Do you recall this chart from Week 1? Now, we add another row!

Data Type Defination Memory Value Range (AMD x64)
long integer 8 bytes 18,446,744,073,709,551,615
address integer 8 bytes 18,446,744,073,709,551,615

Data Type Declarations

Addresses, like char, int, and long, are simply just another data type! Nothing has changed.

1
2
3
4
5
6
7
8
9
int main()
{
    int* a;
    char* b;
    double* c;
    double** d;

    return 0;
}

An address data type, or pointer, is denoted by the * notation. To differentiate the type of data stored at that specific address, we look at the prefix before the *.

For instance, int* a is the address of a locker that stores an int data type.

For instance, double** d is the address of a locker that stores a double* data type.

The C Programming Language

C is a very low level programming language. It allows our programs to freely access its memory space.

For example, I can ask my Operating System: Hey, can you go to locker X and either get or update it's contents?

1
2
3
4
5
6
7
int main()
{
    int *locker = (int *)12345L;
    int value = *locker;
    printf("value=%d\n", value);
    return 0;
}
Me > Hey, can you go to locker 12345 and get it's contents?
Operating System > Okay!

Memory Address of Variables

But wait, hold up. Why would I ever want to see what’s inside Locker 12345? And you’re totally right! We wouldn’t. Locker 12345 is just a random locker in the middle of no-where that has absolutely no relevance to our code. So in practice, how can we apply this concept to real world scenarios?

It will be helpful to know the locker address of where our variables are stored.

1
2
3
4
5
6
7
int main()
{
    int value = 12345;
    int *address = &value;
    printf("addr=%d\n", (int)address);
    return 0;
}
addr=6422296

Here comes a plot twist. Array variables are actually just a memory address!

1
2
3
4
5
6
7
8
int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    int *head_addr_a = arr;
    int *head_addr_b = &arr[0];
    printf("%d %d\n", head_addr_a, head_addr_b);
    return 0;
}
6422276 6422276

When the main() function is called, 5 lockers that stores an int are given to the variable arr. These 5 lockers are sequential. This means that 0th locker is at address arr while the ith locker is at address arr + i.

1
2
3
4
5
6
int main()
{
    int arr[5] = {1, 2, 3, 4, 5};
    printf("%d %d\n", *arr, *(arr + 4));
    return 0;
}
1 5

The locked with the name value is located at address 6422296 and can store an int data type.

The takeaway here is that arr, while it is an array of int, is also a int* int address that stores the address of the 0th element of the array.