Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

using free() to free memory cause crash

I’m trying to make a small library to handle strings as it’s abnormally complicated to handle them in C.

I have a structure defined as such:

typedef struct _String
{
    unsigned int size;
    char *string;
} String;

It’s quite simple, and allow me to dynamically change the array size (provided i use it correctly).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I have a function that’s dedicated to creating this structure,
as well as a function to free memory using a pointer to a String.

String *create_string(char *chr)
{
    String *str = calloc(1, sizeof(unsigned int) + sizeof(chr));
    str->string = chr;
    str->size = strlen(chr);

    return str;
}

void destroy_string(String *str)
{
    free(str);
}

But anyway, i’m having issues making a concatenation function which is defined as such:

bool concat_string_char(String *str, char *chr)
{
    // No use to continue since the passed String isn't initialized
    if (str->string == NULL) return false;

    // Storing the previous string pointer
    char *ptr = str->string;
    
    // Final size after concat
    int final_size = str->size + strlen(chr);

    // Allocating a new block of memory of size final_size * sizeof(char)
    str->string = calloc(1, final_size * sizeof(char));

    // Append each characters of orignal string
    for (int i = 0; i != str->size; i++)
    {
        str->string[i] = ptr[i];
    }

    // append each character of chr
    for (int i = 0; i != strlen(chr); i++)
    {
        str->string[str->size++] = chr[i];
    }

    // Free the memory allocated by the previous string -> Crash
    free(ptr);

    return true;
}

As i commented, a crash happen when i free the memory at the pointer used by the original string.

Includes:

#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

you can try using the 3 functions above as follow (provided you comment free():

int main(void)
{
    String *str = create_string("Original");
    concat_string_char(str, " Concatenated");
    printf("%s\n", str->string);
    destroy_string(str);
    return 0;
}

replit: https://replit.com/@Mrcubix-Mrcubix/String-test#main.c

/EDIT: The Output string is indeed the one expected, the only issue here is to free this old pointer to not leak memory. END/

I tried using gdb to see if i could debug anything but as always, debugger have only ever been useful in cases where i couldn’t find the location of crashes, never to figure out issues.

But anyway, it anyone would like to point out my mistake and explain in further details why it’s wrong, i think it would improve my understanding of pointer in these kind of situations.

>Solution :

This is what you’ve got wrong:

String *create_string(char *chr)
{
    String *str = calloc(1, sizeof(unsigned int) + sizeof(chr));
    str->string = chr;
    str->size = strlen(chr);

    return str;
}

The first problem is here:

String *str = calloc(1, sizeof(unsigned int) + sizeof(chr));

You are allocating memory for the whole struct, including str->string. I get it, this prevents heap fragmentation but it also complicates manipulation.

Caling free on str->string will cause a segmentation fault because that address is invalid. You can only call free on str.

Second:

str->string = chr;

This is not copying the string, this is just assigning the pointer. That’s plain wrong. You must copy using memcpy or similar:

memcpy(res->string, value, res->size);

Third: This may work:

String *create_string(char *chr)
{
    String *str = malloc(sizeof(String));
    str->size = strlen(chr);
    str->string = malloc(str->size);
    memcpy(res->string, value, res->size);
    return str;
}

And, if you want to add the terminating NULL character, try this:

void destroy_string(String *str)
{
    free(str->string);
    free(str);
}

Finally: You are not setting a terminating NULL character, have this in mind when printing (eg: using standard print functions).

If you want to add the terminating NULL character, change the constructor to this.

String *create_string(char *chr)
{
    String *str = malloc(sizeof(String));
    str->size = strlen(chr);
    str->string = malloc(str->size+1);
    memcpy(res->string, value, res->size);
    str->string[str->size] = '\0';
    return str;
}

Of course you need to take this into consideration in the concat function.

Note: You can avoid the second assignment by copying the null character from the source string, as all strings in C ar NULL-terminated (Thanks @0___________):

    memcpy(res->string, value, res->size+1);

Update: You are using calloc incorrectly:

str->string = calloc(1, final_size * sizeof(char));

The correct use is:

str->string = calloc(final_size, sizeof(char));
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading