Daniel
Daniel

Reputation: 33

C dynamic struct (malloc and free)

I am trying to learn the basics of C, C++ programming, so I've started with "C". I have lots of experience programming with Java and VB. But "C" is what I want to learn. So I'm having an issue, trying to understand the "malloc" and "free" functions.

I am using Borland C++ 4.5 and Visual C++ 6.0 on Windows 98. - (Just a testing environment, want to learn the very basic and early windows programming).

Refer to this code:

struct String
{
 char *value;
 int length;
};
char *initString(const char *value)
{
 char *str = (char*)malloc( strlen(value)+1 );
 strcpy(str, value);
 return str;
}

struct String *InitString(const char *text)
{
 struct String *str = (struct String*)malloc( sizeof(struct String) );

 str->value = initString(text);
 str->length = strlen( str->value );
 return str;
}
void freeString(struct String *str)
{
 free(str->value);
 free(str);
 str = NULL;
}
int main(int argv, char *argc[])
{
 struct String *theString = InitString("Testring string struct");

 printf("String: %s\n", theString->value);
 printf("String Length: %d\n", theString->length);

 freeString(theString);

 printf("\nData: %s", theString->value);

 return 0;
}

When this program runs, the result is correct.
After I call "freeString(theString)", the function does free the memory and set the struct to NULL inside the "freeString()" function, that should free the "theString" inside "main()" as I pass in the pointer to "theString", but when the function returns: "theString" is not "NULL".

On Borland 4.5 I can still call the "printf" with "theString->value" and it prints the string. On Visual C++ the program crashes when calling "printf" - BUT "theString" is still not "NULL". When I trace the program in debug mode, the "struct" is being freed inside the "freeString()" function and the struct is set to NULL, but when the function returns the "theString" is not NULL and the "value" is still usable on Borland, but not on Visual C++.

So I'm trying to understand, what is going on here? Is there some de-reference that should be done?

Thank you in advance!

Upvotes: 2

Views: 10624

Answers (5)

nos
nos

Reputation: 229342

You're looking at undefined behavior (you're using a value after it has been free'd), so really - anything could happen. It could crash, or it could operate "normally"

What's likely happening is msvc, atleast in debug mode, zeros out or writes a special byte pattern to the memory you free so the str->value pointer becomes invalid and crash when you dereference it, while borland just releases the memory back to a memory pool but leaves it untouched.

Your str=NULL in the function

void freeString(struct String *str)
{
 free(str->value);
 free(str);
 str = NULL;
}

has no real effect. It just sets the local str value to NULL, the caller is not affected.

If you want to set the pointer of the caller to NULL you have to pass in a pointer to that pointer, or in the case of C++, pass a reference to the pointer.

void freeString(struct String *&str) //c++
{
 free(str->value);
 free(str);
 str = NULL;
}


void freeString(struct String **str) //c, call it as freeString(&theString);
{
 free((*str)->value);
 free(*str);
 *str = NULL;
}

Upvotes: 4

Mahesh
Mahesh

Reputation: 34665

You are trying to access a field that is released. And that results an undefined behavior. You are able to access the value despite being released on some compilers because that particular field isn't reset by any other running application. Even on X-Code this runs happily but not on Visual Studio Compiler.

Upvotes: 0

jfm3
jfm3

Reputation: 37872

C is call by value. What would get set to NULL if you called freeString(anotherFunction(theString))?

You must to pass in a pointer to a pointer, if you want to have a function have a side effect upon the referent of that pointer.

Idiomatic C99 would just omit the assignment of str = NULL within freeString().

Upvotes: 1

user140053
user140053

Reputation:

In fact who have to pass in argument the address of the pointer and not only the pointer

void freeString( struct String **str)
{
  ...
  *str=NULL;
}

Otherwise you set to NULL a copy of the pointer str not str itself...

And into main() don't forget to test NULL pointer to avoid crash :

if (theString!=NULL)
  printf("\nData: %s", theString->value);

Upvotes: 0

Otávio Décio
Otávio Décio

Reputation: 74320

That's one of the reasons you should never, ever, use a pointer after the memory it points to is released. The behavior is undefined and that is exactly what you are seeing here.

Upvotes: 4

Related Questions