ste3e
ste3e

Reputation: 1045

Why does freeing copied memory affect the copy?

I have this code to reproduce the problem I am having elsewhere. The problem is that I think I am creating an independent copy of a set of characters and providing an independent pointer to them, but for some reason I do not understand the compiler is certain that the pointer is pointing to the source of the copy.

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

typedef struct Str{
    size_t len;
    char* ptr;
}Str;

Str* newStr(char* str);
Str* cpyStr(Str* str);

int main(int argc, char *argv[]){
    Str* a = newStr("This is a string");    
    printf("Returned string a is %s\n", a->ptr);

    Str* b = cpyStr(a);
    //free(a->ptr);
    //free(a);

    if(b == NULL) puts("Error getting b");
    else printf("Returned string b is %s\n", a->ptr);

    return 0;
}

Str* newStr(char* str){
    size_t len = strlen(str) + 1;
    if(len == 0) return NULL;

    Str* toret = malloc(sizeof(Str));
    if(toret == NULL) return NULL;

    toret->len = len;
    toret->ptr = malloc(len * sizeof(char));
    if(toret->ptr == NULL) return NULL;

    strncpy(toret->ptr, str, len);      

    return toret;
}

Str* cpyStr(Str* str){
    Str* toret = malloc(sizeof(Str));
    if(toret == NULL) return NULL;

    toret->len = str->len;
    printf("Len is %d\n", toret->len);

    toret->ptr = malloc(toret->len * sizeof(char));
    if(toret->ptr == NULL) return NULL;
    strncpy(toret->ptr, str->ptr, toret->len);  

    return toret;
}

If I do not comment out the free(a->ptr) I get a string consisting of a square box and some random character as opposed to "This is a string".

This is C compiling on mingw64.

Upvotes: 1

Views: 75

Answers (2)

harmic
harmic

Reputation: 30597

The answer to the question "why does freeing copied memory affect the copy" is "it doesn't". If you are seeing this it almost certainly means you have a stray pointer somewhere - either you aren't really making a copy, or your copy is becoming corrupted some other way.

Your example (although I'm sure it doesn't really reflect your problem) provides a good example - you are actually printing the wrong variable. This:

else printf("Returned string b is %s\n", a->ptr);

Should be

else printf("Returned string b is %s\n", b->ptr);

In such cases I often find it useful to print out the pointer itself, to make sure it really is pointing to the buffer I think it is. For example:

printf("Returned string a(%p) is %s\n", a->ptr, a->ptr);
...
else printf("Returned string b(%p) is %s\n", b->ptr, b->ptr);

That way you can compare not only the contents but the addresses of that a->ptr and b->ptr are pointing to.

Upvotes: 2

tristan
tristan

Reputation: 4332

else printf("Returned string b is %s\n", a->ptr);

should it be b->ptr?

Upvotes: 2

Related Questions