0

Here is an example of continuous memory allocation:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <type.h>
#define HASH_MAXSIZE  193
#define HASH_NODE_MAXSIZE  65535

struct code_info
{
    char infos[256];
    uint8_t code;
};

struct hash_node
{
    struct code_info* infos;
    struct hash_node* next;
};

struct hash_table
{
    struct hash_node* table;
};

struct myobject
{
    struct hash_table* code_table;
    struct hash_node* node_buffer;
    struct code_info* info_buffer;
};

int main(int argc, char** argv)
{
    struct myobject * my = (struct myobject*)malloc(sizeof(struct myobject));
    // an error may occur in allocating memeory

    my->code_table = (struct hash_table*)malloc(HASH_MAXSIZE * sizeof(struct hash_table));
    // an error may occur in allocating memeory
    my->node_buffer = (struct hash_node*)malloc(HASH_NODE_MAXSIZE * sizeof(struct hash_node));
    // an error may occur in allocating memeory
    my->info_buufer = (struct code_info*)malloc(HASH_NODE_MAXSIZE * sizeof(struct code_info)); 
    // an error may occur in allocating memory 
    return 0;
}

I learned that when a memory allocation failure occurs, it is not only necessary to prompt an error message and return it, but also to free up the allocated memory space. But there are too many memory allocation places, each memory allocation need to use conditional statements to judge and then prompt and release the allocated memory? Code is not concise enough!

Is there any good way to solve this problem? thank you!

Da Wang
  • 100
  • 7
  • 1
    https://stackoverflow.com/questions/27451220/how-can-i-correctly-handle-malloc-failure-in-c-especially-when-there-is-more-th something like this? – Gnqz Jul 26 '23 at 13:43
  • Why should `malloc` fail at all? You're not actually allocating very much. Or is your system tight on memory? – Paul Sanders Jul 26 '23 at 20:10

1 Answers1

3

free(NULL); has been defined to mean "no action", therefore it is perfectly safe to do. Thus, provided that you have initialized all pointers to null pointer before a set of mallocs then you can use the same cleanup code for them all with goto:

    struct myobject * my = (struct myobject*)malloc(sizeof(struct myobject));
    if (! my) {
        // no cleanup necessary in this case since nothing was allocated
        return FAIL;
    }

    my->code_table = NULL;
    my->node_buffer = NULL;
    my->info_buffer = NULL;

    my->code_table = malloc(HASH_MAXSIZE * sizeof(struct hash_table));
    if (! my->code_table) goto error;

    my->node_buffer = malloc(HASH_NODE_MAXSIZE * sizeof(struct hash_node));
    if (! my->node_buffer) goto error;

    my->info_buffer = malloc(HASH_NODE_MAXSIZE * sizeof(struct code_info));
    if (! my->info_buffer) goto error;

    // here everything went fine....

    ....
    return SUCCESS;

error:
    free(my->code_table);
    free(my->node_buffer);
    free(my->info_buffer);
    free(my);
    return FAIL;

Otherwise you could use multiple labels:

clean_up_node_buffer:
    // clean up node buffer here...

    free(my->node_buffer);

clean_up_code_table:
    // ...
    free(my->code_table);

clean_up_my:
    //...
    free(my);
    return FAIL;