Reputation: 33
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
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
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
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
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
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