2
votes

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!

5
"I am using Borland C++ 4.5 and Visual C++ 6.0 on Windows 98... [I] want to learn the very basic and early windows programming." This is almost certainly A Bad Idea. Both of those compilers are ancient; they were both released before C++ was standardized (in 1998). Early Windows programming (if the mid-90s could be called "early" for Windows programming) was a beating. Get a new compiler and IDE like Visual C++ 2010 Express (which is free!)James McNellis
Note also that the basics of C programming are very, very different from the basics of C++ programming. The syntax of the languages is very similar and they share some low-level details, but they are still fundamentally different. You should pick one and make sure you have either a good beginner C book or a good introductory C++ book.James McNellis
Also, and someone yell at me if I'm wrong, but what good does calling the free(struct) do? It is a pointer, yes, but not to a dynamically allocated space. It's late (in the UK) so please excuse me if I'm wrong. I second the comments for a more modern compiler.user257111
I am actually using Visual Studio 2010. I use C# to create add-ons for AutoCAD and Revit. But C# is managed code. So I have no experience with none managed. I also program in 8086 assembly using TASM and such, using DosBox. I just want to understand the low level hardware, and how memory is being manipulated. Well I guess you can tell that I really enjoy the challenge. And I agree that the old C and such is a pain in the ass.Daniel

5 Answers

4
votes

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.

4
votes

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;
}
1
votes

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().

0
votes

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);
0
votes

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.