-
the basics of malloc
I've enjoyed many of your posts and decided to register and pick your minds if you don't mind.
Somehow I've managed to program for a LONG time and never bothered to understand some things. All too often I've done "just make it work" programming.
I'm working on a program now and noticing things I just think I should understand. For example, here's a line from a program:
note[ctr].nBody = (char *) malloc (100 * sizeof( char ) ) ;
The structure for note is:
Code:
typedef char *STRING
typedef struct noteinfo { /* structure of note */
int nSize; /* number of characters in note body */
STRING nBody; /* text of note */
STRING nExtra; /* area for extra info such as date string */
} NOTEINFO;
So, later when I'm ready to write the file I wanted to test the note body (note[ctr].nBody) to see if it was empty. I expected to be able to see if it was empty by using
Code:
if( note[ctr].nBody == NULL )
But it turns out that there are four chars in .nBody even though I've done nothing with it since the malloc and sizeof() also returns a size of 4.
Can anyone tell me what malloc puts in the string during malloc? And, how might I test note[ctr].nBody to see if it is empty? (Empty meaning nothing has been done to it since the malloc.) I've tested for content using lstrlen(), which returns 0. But that seems kinda sloppy.
Thanks,
Dale L
-
Using sizeof on a pointer will typically return 4 or 8, depending on the size of a pointer on the system. So in other words, you are getting the size of the pointer, and not the actual value or data stored there.
But if you do sizeof(*nBody), you will get 1 ( sizeof(char) ), because the compiler cannot know how many elements or how big the data block pointed to by the pointer is.
Malloc only returns NULL if it fails, so you can't check for NULL either.
Therefore, the better solution is to keep track of whether or not something has been written. But you do have a "nSize" variable, so use that (ie nSize == 0).
Also beware that typedefing a pointer may not be the greatest idea. It will probably introduce confusion, so avoid that.
And "n" isn't a typical prefix for a string. It's more of a prefix for numbers.
-
Elysia, thank you. As I read your reply I was banging my head and saying "I knew that." All too often I get caught in the act of thinking content or value rather than pointer. This probably comes from the many years (most of my first ten years of programming) of writing in REXX which is so forgiving that you rarely use pointers.
Thanks.
Now, I'll have to figure out a good way to phrase my questions on win32's WriteFile function when using structures. I remember quite quickly concluding "this is nuts" and going right back to fopen and fwrite and fputs and the likes.
Dale L
-
But fopen/fwrite are C standard functions, WriteFile is not. You would be sacrificing portability.
-
Elysia, agreed. Hence my copies of K&R and Petzold are pretty much resident on my desk. Going through Petzold it is obvious that he is trying to remain win32 compliant. So one day I get to playing with WriteFile and seems that things blow up.
For example, from the structure in the code above. Lets say I have
NOTEINFO note[NumberOfNotes] ;
NumberOfNotes may be pretty much any number: lets say 25.
Now, I want to drop all 25 of the notes to file using WriteFile. I remember playing with it for quite a while and got unexpected results. Probably forgot about pointers again.
It would seem that there would be a nice quick and easy one liner to write the 25 notes to file. Any chance you have that one liner on the tip of your tongue?
Dale L
-
For C:
fwrite(note, sizeof(note), 1, f);
Only works if note is defined in the same function where you write the file. Otherwise you're going to have to do something like:
fwrite(note, sizeof(*note) * num, 1, f);
-
Elysia, yes. Thanks. I've got it all working in standard C routines. I was curious as to how it would be done with win32's WriteFile. I pulled the following line from some old code that didn't work:
WriteFile (hFile, note[ctr], sizeof(note[ctr]), &dwBytesWritten, NULL) ;
Don't knock yourself out on this one. Just toying with things that I've done in the past in, perhaps, far less than professional style.
Dale L
-
Try this instead:
Code:
WriteFile (hFile, note, sizeof(note), &dwBytesWritten, NULL) ;
It's basically the same as the C code.
-
Bear in mind that writing a struct that contains pointers to a binary file is pretty useless, because if when you load the data next time, the pointers will not be valid [1]. You need to either:
1. Use fixed length strings in your note data.
This is by far the easiest to implement.
2. Write the data out in a different way (so you store the string pointed to by the pointer, rather than the pointer itself).
This is trickier, but also more flexible as it copes with any length body/extra, as you have to know how much data you have to read, so you first read the nSize, then allocate nSize bytes for nBody, and read nSize bytes into your new pointer, and finally you need to know the length of nExtra and do the same thing there.
[1] Of course, if you don't de-allocate the memory (or exit the application), it will still be valid if when you read it back - but the point of storing something is usually that you want to exit the application and then read it back when you start the application again.
--
Mats
-
Thanks for the input. While the WriteFile line I gave was not quite a real life example, your comments certainly did help shake the cobwebs and clear things up. Thanks.
Now, if you don't mind, another concern.
Somewhere I've read that after doing a malloc (or alloc) it is good to set the variable value to NULL such as:
Code:
note[ctr].nBody = malloc (300 * sizeof( char ) ) ;
note[ctr].nBody = NULL ;
Okay, that kinda makes sense. As I understand, it would leave the var pointing to nothing. Would this be done to help in the area of memory leaks? Is this a good practice? Would I really want to bother setting to NULL if I'm actually going to fill the nBody immediatly after the malloc?
Thoughts are appreciated.
Dale L
-
Yes, it's a good practice. However, you must free it first, otherwise you get a memory leak.
It allows you to see if it's a valid pointer or not, which is why it's such a good thing.
Don't do it right after malloc (your memory you just allocated will be lost!).
-
Let me make sure I understand: setting it to NULL will actually defeat the malloc? So if I set nBody to NULL before doing anything with it I would be defeating the malloc?
In other words, I would want to first do malloc on nBody and then not until after done using nBody, I would free it and then set it to NULL?
Dale L
-
-
>> Somehow I've managed to program for a LONG time and never bothered to understand some things. All too often I've done "just make it work" programming.
it's pointless to program in a language you don't understand so well. you will spend a lot of time debugging problems that would have never been an issue had you just consulted a good C programming book.
>> Okay, that kinda makes sense. As I understand, it would leave the var pointing to nothing. Would this be done to help in the area of memory leaks? Is this a good practice? Would I really want to bother setting to NULL if I'm actually going to fill the nBody immediatly after the malloc?
seriously.
-
Code:
note[ctr].nBody = malloc (300 * sizeof( char ) ) ;
Now do something with your 300 chars.
Then when you're done, you do this.
Code:
free( note[ctr].nBody );
note[ctr].nBody = NULL ;