0

I have this program which stores lots of stuff in memory via pointers to memory areas (structures, arrays), and this user that can init the program at anytime. Upon init, the program needs to free previously used memory (if any, and that's the catch) and allocate new storage with a possibly different size.

Now upon the very first init I have no idea what my pointers are pointing at: especially, I don't know if they are garbage or not. Yet in case they aren't, I need to free what they are pointing at. How do I know?

unwind
  • 391,730
  • 64
  • 469
  • 606
Charles
  • 988
  • 1
  • 11
  • 28
  • 3
    You simply cannot. – George Jan 31 '17 at 08:34
  • @George I was afraid so. An idea just popped into my head : separate the first init with only mallocing and no freeing - as the system just freshly started and it's the first time and all - from further inits which I will call "reinits" and which will know that they come after a previous malloc and that they can free what's behind the pointers and malloc again. Stackoverflow sometimes brings answers through inspiration rather than through other people ... – Charles Jan 31 '17 at 08:37
  • You have to do "bookkeeping" of pointers. Whenever something is not needed anymore, free it and set the pointer to null. Then upon your init, anything not null is a valid pointer that must be freed. – Paul Ogilvie Jan 31 '17 at 08:37
  • Don't forget to validate your program against memory leaks with tools such as purify, etc. – Rishi Jan 31 '17 at 08:38
  • @PaulOgilvie Yes but what about the first init where pointers have undefined values ? See my new idea above. – Charles Jan 31 '17 at 08:39
  • 2
    There is one simple rule: you need to free what you have malloced. If you have a pointer and you don't know if it is valid or not, then you have a serious design error in your program. – Jabberwocky Jan 31 '17 at 08:42
  • @MichaelWalz: That's better than my answer. – Bathsheba Jan 31 '17 at 08:50
  • @MichaelWalz Yes exactly, my design (with simply an init) did not allow me to know whether there had been past inits or not. Now with init ("no past inits") differenciated from reinits ("must have been past inits/reinits") I know and can do things properly. – Charles Jan 31 '17 at 08:54
  • Charles, that is impossible if you initialize all pointer variables to null. Global variables will already be null so only automatic variables remain. – Paul Ogilvie Jan 31 '17 at 10:39
  • @PaulOgilvie Yes indeed I only have global static so they are initialized to NULL which saves me. – Charles Jan 31 '17 at 15:38

2 Answers2

4

Are we talking about globals here? Because they are automatically initialized to zero. In general, your program should be written in a way, that pointers never point at garbage, but either at valid data or have a value of NULL (free(NULl) is a no-op).

MikeMB
  • 20,029
  • 9
  • 57
  • 102
  • Yes, file-scoped, but that makes no difference. http://stackoverflow.com/questions/13251083/the-initialization-of-static-variables-in-c – Charles Jan 31 '17 at 10:00
3

With the exception that a pointer pointing to NULL does not point to anything, there is no way of checking if a given pointer points to something valid. It's your job to keep track of pointers that still point to dynamic memory. (Pointers can point to automatic and static variables and of course you must not attempt to free that.)

Plenty of folk set the pointer to NULL once they have freed the relevant memory and rely on the fact that the C standard defines free(NULL) as a no-op. So you could adopt that approach.

But over-reliance on that sort of code can be smelly as it can mask potential bugs. Just be more careful with your memory management.

Or you could build yourself one of these: https://en.wikipedia.org/wiki/Boehm_garbage_collector

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    It is common and perfectly safe practice to have code like for example `static int* ptr = NULL;` ... `void create_stuff (void) { free(ptr); ptr = malloc(...) }` ... `void cleanup (void) { free(ptr); ptr = NULL; }`. This means that those functions can be called at any time, in any order, and also multiple times throughout the execution. It allows more flexibility when creating and destroying objects and the code is always in a safe state. The same "design pattern" can also be used for other kinds of resources such as thread handles, file handles etc. All good practice, nothing smelly about it. – Lundin Jan 31 '17 at 09:28
  • Point taken. I've softened the cautionary tale a little. But don't use `NULL` as an excuse for writing sloppy code. – Bathsheba Jan 31 '17 at 09:33