Home > other >  Calling free() to release memory that is malloc(ed) by strdup() in multiple functions
Calling free() to release memory that is malloc(ed) by strdup() in multiple functions

Time:11-29

Wrote a program TroubleTicket which allows the user to create a trouble ticket with various parameters. Code is using struct ticket {} to store ticket data. Each a new_ticket is added to tkt_array. The code is rather lengthy so I posted the relevant files and the code snippet. This is not a school project but a personal interest in learning some C.

Anyhow, there are functions, create_ticket() and update_ticket() which use _strdup() to handle user inputs. It's my understanding that _strdup() uses malloc() and this requires call to free() the memory. My approach is to call free() at program exit with the assumption that this will release malloc()ed memory. This task is done by function free_tkt_arr().

The function create_ticket() uses _strdup() when setting name, problem, assigned_to and status pointers.

Function update_ticket() is also using _strdup() to update ticket name, problem, assigned_to and status.

Upon code exit, function free_tkt_arr() is called to release memory allocated by _strdup().

What I'd like to know if calling free_ticket() on system exit releases all memory that was allocated by calls to _strdup() in create_ticket() and update_ticket()?

struct ticket {
    int priority;
    int number;
    char *name;
    char *problem;
    char *assigned_to;
    char *status;
};

The function create_ticket() uses _strdup() when setting name, problem, assigned_to and status pointers:

struct ticket tkt_array[NUM_TICKETS];

void create_ticket() {
    char *ptr;
    struct ticket new_ticket;
    printf("Enter your name: ");
    new_ticket.name = _strdup(get_input(20));
    printf("Enter problem description: ");
    new_ticket.problem = _strdup(get_input(100));
    printf("Assigned to: ");
    new_ticket.assigned_to = _strdup(get_input(20));
    //printf("Enter ticket status: ");
    //using _strdup() in case status is updated using _strdup which requires call to free()
    ptr = "new";
    new_ticket.status = _strdup(ptr);
}

Function update_ticket() is also using _strdup() to update ticket name, problem, assigned_to and status.

void update_ticket() {
    printf("Enter ticket number:  ");
    ptr = get_input(8);
    sscanf_s(ptr, "%d", &ticket_num);

    if (*ptr == '1') {
        printf("Updating Status.\n");
        printf("Enter Status update:  ");
        tmp_ticket2.status = _strdup(get_input(20));
    } else
    if (*ptr == '2') {
        printf("Updating Problem description.\n");
        printf("Enter Problem description update.  ");
        tmp_ticket2.problem = _strdup(get_input(100));
    } else
    if (*ptr == '3') {
        printf("Updating Assigned to.\n");
        printf("Enter Assigned to update.  ");
        tmp_ticket2.assigned_to = _strdup(get_input(20));
    }
}

function free_tkt_array() is called when exiting code and should be freeing memory allocated by prior calls to _strdup()

void free_tkt_arr() {
    for (int i = 0; i <= tkt_count - 1; i  ) {
        free(tkt_array[i].assigned_to);
        free(tkt_array[i].name);
        free(tkt_array[i].problem);
        free(tkt_array[i].status);
    }
}

I thought about downloading and learning valgrind but maybe that's a bit over my head.

CodePudding user response:

Whether you should free the string or not depends on what get_input() does. If get_input() returns a block of allocated memory, there is no need to call strdup().

Note also that you should use strdup() instead of _strdup():

  • _strdup() is a Microsoft specific function that probably implements the same semantics as POSIX standard function strdup().

  • strdup() is available on Unix systems, specified in POSIX. It will be part of the upcoming C2x version of the C Standard (at last).

  • if strdup() is not available on your system, you can either use a macro of define it this way:

    #include <stdlib.h>
    #include <string.h>
    
    char *strdup(const char *s) {
        size_t size = strlen(s)   1;
        char *p = malloc(size);
        if (p) {
            return memcpy(p, s, size);
        } else {
            return p;
        }
    }
    

CodePudding user response:

You can free() the memory, but you have also to assing NULL to the pointers, if you are not releasing the memory associated to the struct (which seems to be the case). As you allocate in static global memory an array of structures, you will get all of them initialized to NULL, so no need to initialize pointers initially to check if they have been allocated. But that doesn't hold after a while, so you have better to memset(3) or bzero(3) your structures, once you don't use them. You don't show how do you distinguish a used record from an unused one, but if you are using a pointer field as a flag to mark it as unused, then you have to set it to NULL once you have released the ticket. Lacking to do that, makes your pointers to continue pointing to unallocated memory (possible assigned by malloc(3) to other means, and a disastrous thing for your program)

You know, free(ptr) cannot make the pointer ptr to change to NULL, as every parameter is passed by value in C. So, free(ptr);, followed by ptr = NULL; is a good bet.

BTW, having a Minimal, Reproducible Example would be fine to search for any other possible mistake.

  • Related