# Pointers, references and memory allocation (7)

Antonin Hérault
·Jul 12, 2022·

Subscribe to my newsletter and never miss my upcoming articles

• Common point between arrays and pointers
• Pointers and references
• Using pointers in function parameters
• Allocation functions
• Note
• Exercises
• Solutions

This tutorial might be hard to understand, don't hesitate to review any part one more time. Pointers scare a lot of programmers so I'm trying to make things simple here.

A pointer is the memory address of a variable, it redirects to the memory place where a value is stored.

## Common point between arrays and pointers

When we create an array, we simply create a pointer to the beginning memory place.

``````int x = 5;
char hello[5] = "Hello";
int y = 10;
``````

This is a dumb overview of the memory, and how are stored the variables :

``````________________________________________
| 5 | 'H' | 'e' | 'l' | 'l' | 'o' | 10 |
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
⇈    ⇈                            ⇈
x   hello                          y
``````

## Pointers and references

This is the syntax to declare a pointer :

``````<type>* <identifier> = &<variable identifier>;
``````

To retrieve the pointed data from a pointer :

``````*<identifier>
``````

To get the memory address of a variable, also called "reference" :

``````&<variable identifier>
``````

### Example

``````#include <stdio.h>
#include <assert.h>

int main(void) {
int value = 5;
int* ptr_value = &value;
assert(*ptr_value == 5);

return 0;
}
``````

## Using pointers in function parameters

Pointers are useful to save memory usage. Instead of creating a new variable and return it, we can use pointers in function parameters and directly modify a value from its pointer

``````#include <assert.h>

void triple(int* value) {
*value *= 3;
}

int main(void) {
int x = 5;
triple(&x);
assert(x == 15);

return 0;
}
``````

In this example, only one variable was created in the whole program.

But when we don't use pointers :

``````#include <assert.h>

int triple(int value) {
value *= 3;
return value;
}

int main(void) {
int x = 5;
x = triple(x);
assert(x == 15);

return 0;
}
``````

The `value` parameter is a new variable inside the `triple` function. So, two variables were created there.

When you have the possibility to use pointers instead of simple parameters, use pointers.

Note that you can use a different syntax in parameters for pointers

``````void triple(int* value);
void triple(int value[]);
``````

Got it ? Pointers and arrays are both the same. It's like having an array of an unknown length

## Allocation functions

If you try to create an array with the pointer syntax, you will get important compiler warnings because it doesn't work.

But you told me that it was the same thing ?

Yes, but no. There are differences between the `[length]` and `*`/`[]` syntaxes.

``````int values[5] = {9, 4, 1, 23, 6};
``````

In this example, the compiler knows the memory size of `values` and can reserve space for the values.

But, if you try to create an array with the pointer syntax (with `*` or `[]`), it will not work.

``````int* values = {9, 4, 1, 23, 6};
int values[] = {9, 4, 1, 23, 6};
``````

The compiler cannot calculate the memory size because it doesn't have the array length, so you cannot assign the values correctly. You will get weird results.

To do this, we have to call a special function coming from the standard library.

### The `malloc` function

This function permits to reserve some space in memory, and it returns the array beginning memory address.

Prototype for `malloc` :

``````void* malloc(size_t s);
``````

What's `size_t` ? And how a pointer can be for `void` type ?

It's close to a long type, it's often used for memory size. When we don't know what type of value has to be pointed, we write `void` that stands for "unknown".

``````#include <assert.h>
#include <stdlib.h>

int main(void) {
int* values = malloc(sizeof(int) * 5);
assert(values != NULL);

return 0;
}
``````

We reserve 5 times the size for an integer value in the memory.

If the memory allocation has failed, the returned value is `NULL`, you have to check the validity of the pointer before using it.

Now, we can set values for the array

``````values[0] = 2;
assert(values[0] == 2);
``````

### The `free` function

When you allocate some a memory block, you have to free the allocated block. Welcome in C memory management ! In high-level languages, the compiler is smart, so it knows when an allocated block has to be freed. But with C, you have to manage it by yourself in your code.

``````void free(void* pointer);
``````
``````#include <assert.h>
#include <stdlib.h>

int main(void) {
int* values = malloc(sizeof(int) * 5);
assert(values != NULL);

values[2] = 10;
assert(values[2] == 10);

free(values);
assert(values[2] != 10);

return 0;
}
``````

After calling `free` for a pointer, you cannot use it again (unless you want to have errors ?!)

### The `realloc` function

It attempts to resize the pointed memory block, previously allocated by `malloc`

``````void* realloc(void *pointer, size_t s);
``````

### Other memory functions

There are some more memory functions, but we will see that in a post talking about strings because they have a great role in this subject. Strings are just arrays with big memory management

### Common errors and debugging tools

If you have already played with the arrays and the memory allocation functions, you probably got a terrible error named "Segmentation fault" or "stack smashing detected", well something with "... (core dumped)".

With C, and because you have to manage the memory by yourself, you may often see this sort of errors.

There is a tool called "valgrind". It's an awesome tool to see what happens in memory during your program run.

``````#include <stdlib.h>

void foo(void) {
int* x = malloc(10 * sizeof(int));
x[10] = 0;
}

int main(void) {
foo();
return 0;
}
``````
``````gcc main.c -o program
valgrind ./program
``````
``````  ==19182== Invalid write of size 4
==19182==    at 0x804838F: foo (main.c:6)
==19182==    by 0x80483AB: main (main.c:11)
==19182==  Address 0x1BA45050 is 0 bytes after a block of size 40 alloc'd
==19182==    at 0x1B8FF5CD: malloc (vg_replace_malloc.c:130)
==19182==    by 0x8048385: foo (main.c:5)
==19182==    by 0x80483AB: main (main.c:11)
...
==19182== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
``````

The log is much more complete. You can see memory problems and know if you have freed all the allocated blocks.

## Note

``````int values[3] = {1, 2, 3};
assert(*values == 1);
assert(values[0] == 1);
``````

As we saw, an array is just a pointer to the beginning memory place for the values. So, by "getting the value" from a pointer with `*<identifier>`, it's doing the same than getting the first element.

## Exercises

1. Fix the following code :

`````` #include <stdio.h>

int main(void) {
int* values = {1, 2};
printf("%i\n", values[0]);

return 0;
}
``````

## Solutions

1. Fixing code

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

int main(void) {
int* values = malloc(sizeof(int) * 2);
values[0] = 1;
values[1] = 2;
printf("%i\n", values[0]);
free(values);

return 0;
}
``````