loading...

Memory Addresses & Pointers

giladri profile image Gilad Ri Updated on ・5 min read

Welcome to Memory street! In Memory street, there are 2^64 plots. Each plot has an address, starting from 0 to 2^64 - 1 (yeah, that's a long street, especially because all the plots are on the same side of the road). In some plots, there is a house, in others not. Some houses are built on several plots and others are built on only one. For example, the Charles's house (we will call it ch from now on) is built on only one plot, and there is only one person who lives in it. The address of this house is 100, Memory street.

If we translate this information to our language, we can say that the variable ch contains 1 as its value, and its address is 100. Also, its size is one Byte. A byte is the smallest unit of memory that can be accessed (like one plot in our theoretical street) and it contains 8 bits. A bit is the smallest unit of memory, which can be only 0 or 1.

Let's look now on the Interno's house (ih__ from now on), which contains 4 people and is built on 4 plots: 200, 201, 202 and 203. What means that its address is 200. Right next to this house, there is the Floaters' house (fh__ from now on), which its address is 204 and is also built on 4 plots. The number of people that live in this house is 10.5.

What can we say about all the houses we mentioned above? We can say that the addresses of the houses are 100, 200, and 204, respectively. Moreover, we can say that their values are 1, 4, and 10.5, respectively. We already know how to represent the values in our code:

char ch = '1';
int ih = 4;
float fh = 10.5;
Enter fullscreen mode Exit fullscreen mode

But how do we represent the addresses?

Remember the '&' sign in the scanf function? That's the answer. If you put this operator before a variable, you get its address instead of its value. For example:

char * chAddress = &ch; // 100 in our example
int * ihAddress = &ih; // 200 in our example
float * fh fhAddress = &fh; // 204 in our example
Enter fullscreen mode Exit fullscreen mode

Pay attention, the '*' here is not the multiplication operator but it's how we declare a pointer. A pointer is a variable in which we save addresses. That means that the value of a pointer is a memory address. A pointer also has its own address, what means we can also points to it with another pointer. If we want to declare a pointer we write:

<variable_type> * <pointer_name>;
Enter fullscreen mode Exit fullscreen mode

For example:

int * pointer; // can  point at an integer variable
Enter fullscreen mode Exit fullscreen mode

If we want to get the value of the variable the pointer points at, we can use again the asterisk ('*') operator this way:

#include <stdio.h>

int x = 10;
int * pointer = &x; // pointer now points at x
printf("The value of the variable which the pointer points at is: %d", *pointer); // we put '*' before a pointer in order to get the value of the variable/address it points at
Enter fullscreen mode Exit fullscreen mode

In other words, if we want to declare a pointer we add a '*' after the type, and if we want to get the value of the variable/address the pointer points at, we also add '*' before the pointer name. It may be a little confusing, but you will get used to it soon.

"Why do we need pointers?" you probably ask. One answer is that we want to pass the addresses of variables to functions, and not their values. In other words, we want to tell the function where it can find the original box and gets what it contains, to prevent it from the need to create a new box in which it will only copy the value of the original box. For example, as we mentioned above, the scanf function:

#include <stdio.h>

int x;
printf("Enter a number:\n");
scanf("%d", &x);
Enter fullscreen mode Exit fullscreen mode

In the example above, the scanf function gets the address of x and the reason is clear: the scanf function doesn't need the value of x, (to be more accurate: the value of x is "garbage" because we have never initialize it before), but it needs the address of x in order to know where to put the input from the user. The scanf function gets an address of a box and fills it with the input!

This passing variables method is called by reference (instead of by value).

Let's observe the next example:

#include <stdio.h>

void swapByValue(int x, int y) {
    int temp = x;
    x = y;
    y = temp;
}

void swapByReference(int * x, int * y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}

int main() {
    // Initializes two variables
    int x = 5;
    int y = 3;
    printf("x=%d, y=%d\n", x, y);
    // Runs the first function and prints the values of x and y
    swapByValue(x, y);
    printf("x=%d, y=%d\n", x, y);
    // Runs the second function and prints the values of x and y
    swapByReference(&x, &y);
    printf("x=%d, y=%d\n", x, y);
    // Success
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

The output of the code in the example above is:

x=5, y=3
x=5, y=3
x=3, y=5
Enter fullscreen mode Exit fullscreen mode

Why? The first printf output is trivial, it's just how we initialize our variables in main. The second output should also be trivial to the wise reader because actually the swapByValue function does nothing! This function creates two new variables, x and y which are completely different from the main's variables x and y ("other boxes"), but have the same values. What means that the swap happens, but on irrelevant variables that no longer exist at the end of the function (we will learn about scopes in the future). The last output is the output we want. The variables really swapped their values in the right scope (the code block of main). That's because the swapByReference function also creates two new variables, but this time the values of the variables are not just a copy of the values of the main_'s variables. The values of the new variables are the addresses of the main's variable, and therefore, the swap operation occurs on the main's variables! (Just as was the intention).

That's all for this post. This is a lot for one time, I know. Make sure you fully understand what we said before you continue to the next post, which is about Memory Allocation and Dynamic Arrays.

A nice challenge, which appears frequently in job interviews: can you write a swap function that doesn't initialize a new variable? (temp, in our case.)

Always remember, it's much C-mpler than you thought!

Regards,
Gilad

Discussion

pic
Editor guide