Simplify Memory Management with goto Statements in C
- EN
- JA
Table of Contents
During development, you may encounter situations where you need to allocate multiple dynamic memory blocks within a function. If memory allocation fails, you’ll need to free any previously allocated memory, which can make error handling complex.
This article explains how to simplify error handling and manage memory deallocation by using the goto
statement.
#
What is the goto Statement?
The goto
statement is a syntax used to jump to a specified label within a function. It is used in the following format:
goto <label-name>;
The label name can be defined anywhere within the function, and the goto
statement jumps to that label’s location. Although goto
can complicate code flow and reduce readability and maintainability, when used correctly, it can actually improve simplicity, readability, and maintainability.
#
Complex Error Handling with Memory Deallocation
Here’s an example of code that manages multiple dynamic memory allocations.
int example(size_t num)
{
int *p1, *p2, *p3;
p1 = (int *)malloc(sizeof(int) * num);
if (p1 == NULL)
{
return -1;
}
p2 = (int *)malloc(sizeof(int) * num);
if (p2 == NULL)
{
free(p1);
return -1;
}
p3 = (int *)malloc(sizeof(int) * num);
if (p3 == NULL)
{
free(p1);
free(p2);
return -1;
}
/* Processing using p1, p2, and p3 */
free(p1);
free(p2);
free(p3);
return 0;
}
While this code works, each memory allocation and deallocation is handled individually, and freeing memory needs to be coded each time an error occurs. This makes the code redundant and increases the risk of memory leaks.
#
Simplify Memory Deallocation with goto
Using the goto
statement, you can centralize error handling and manage memory deallocation more simply.
int example(size_t num)
{
int ret = -1;
int *p1 = NULL, *p2 = NULL, *p3 = NULL;
p1 = (int *)malloc(sizeof(int) * num);
if (p1 == NULL)
{
goto cleanup;
}
p2 = (int *)malloc(sizeof(int) * num);
if (p2 == NULL)
{
goto cleanup;
}
p3 = (int *)malloc(sizeof(int) * num);
if (p3 == NULL)
{
goto cleanup;
}
/* Processing using p1, p2, and p3 */
ret = 0;
cleanup:
free(p1);
free(p2);
free(p3);
return ret;
}
In this example, goto cleanup
ensures that all memory is deallocated even if an error occurs. Since the free
function can safely take NULL
as an argument, this method allows for safe and efficient memory management.
#
Conclusion
The goto
statement, when misused, can harm readability and maintainability, but using it appropriately can keep code simple. In this example, we demonstrated the benefits of using goto for memory management, but it can also be effective in other situations. It’s essential to use it only in appropriate scenarios.