C Memory Mistakes
Common Memory Mistakes
In the previous chapters, you learned how to allocate, use and free memory. C gives you a lot of control over memory, but it does not check if you use it correctly.
Memory mistakes are some of the most common bugs in C. The compiler usually does not warn you, and the program may even seem to work. But later, it can print wrong values, or suddenly crash.
In C, this is called undefined behavior: the result cannot be predicted, and it can be different every time you run the program.
In this chapter, you will learn the most common memory mistakes, and how to avoid them.
Writing Outside an Array
An array has a fixed size. If an array has 3 elements, the indexes are 0, 1 and 2. C does not stop you if you use index 3, so the program writes to memory that does not belong to the array:
Example
int numbers[3];
int i;
for (i = 0; i <= 3; i++) {
numbers[i] = i * 10; // numbers[3] is outside the array
}
This is called a buffer overflow. It can change the value of other variables, or crash the program.
The fix: make sure the index stays inside the array. Use i < 3, not i <= 3:
Example
int numbers[3];
int i;
for (i = 0; i < 3; i++) {
numbers[i] = i * 10;
}
for (i = 0; i < 3; i++) {
printf("%d\n", numbers[i]);
}
Try it Yourself »
The same can happen with strings. "Christopher" needs 12 characters (11 letters and the \0), so it does not fit in a string of 5:
Example
char name[5];
strcpy(name, "Christopher"); // Too long for name
Make sure the string is big enough for all the characters and the \0:
Example
char name[20];
strcpy(name, "Christopher");
printf("%s\n", name);
Try it Yourself »
Using Memory After free()
After you free memory, it no longer belongs to your program. The pointer still holds the old address, but the memory may already be used for something else:
Example
int *ptr = malloc(sizeof(*ptr));
*ptr = 20;
free(ptr);
printf("%d\n", *ptr); // The memory is already freed
A pointer that points to memory that is no longer valid is called a dangling pointer.
The fix: set the pointer to NULL after free(), like you learned in the Deallocate Memory chapter. Then you can check if the pointer is NULL before you use it:
Example
int *ptr = malloc(sizeof(*ptr));
*ptr = 20;
printf("%d\n", *ptr);
free(ptr);
ptr = NULL;
if (ptr != NULL) {
printf("%d\n", *ptr);
} else {
printf("The memory is freed\n");
}
Try it Yourself »
Returning the Address of a Local Variable
A local variable only exists while its function runs (see Scope). When the function ends, the variable is removed, so its address is no longer valid:
Example
int *getNumber() {
int number = 10;
return &number; // number is removed when the function ends
}
The pointer that getNumber() returns is a dangling pointer.
The fix: if you need the memory after the function ends, allocate it with malloc(). Remember to free it when you are done:
Example
int *getNumber() {
int *ptr = malloc(sizeof(*ptr));
if (ptr != NULL) {
*ptr = 10;
}
return ptr;
}
int main() {
int *number = getNumber();
if (number != NULL) {
printf("%d\n", *number);
free(number);
}
return 0;
}
Try it Yourself »
Tip: If you only need the value, return the value itself (int instead of int *).
Freeing Memory Twice
Calling free() two times on the same memory can crash the program:
Example
int *ptr = malloc(sizeof(*ptr));
free(ptr);
free(ptr); // The memory is already freed
The fix: set the pointer to NULL after free(). Calling free() with NULL does nothing, so the second call is safe:
Example
int *ptr = malloc(sizeof(*ptr));
free(ptr);
ptr = NULL;
free(ptr); // Safe: free(NULL) does nothing
printf("The program is still running\n");
Try it Yourself »
Summary
| Mistake | How to avoid it |
|---|---|
| Writing outside an array (buffer overflow) | Make sure the index is between 0 and the size minus 1, and that strings have room for the \0 |
Using memory after free() |
Set the pointer to NULL after free(), and check for NULL before you use it |
| Returning the address of a local variable | Use malloc(), or return the value itself |
| Freeing memory twice | Set the pointer to NULL after free() |
| Forgetting to free memory (memory leak) | Free memory when you no longer need it (see Deallocate Memory) |