Often in projects, complex structures are used, e.g., like the one below:
struct opts {
char* server;
char* port;
int protocol;
void* protocol_data;
};
And to free such structures, till today I adopted the routines as below:
void free_proto1(struct opts* opt);
void free_proto2(struct opts* opt);
void free_opts(struct opts** opt) {
free((*opt)->server);
free((*opt)->port);
if ((*opt)->protocol == PROTOCOL1) {
free_proto1(*opt);
}
else if ((*opt)->protocol == PROTOCOL2) {
free_proto2(*opt);
}
else
free((*opt)->protocol_data);
free(*opt);
*opt = NULL;
}
But If I have another struct opts
pointer like struct opts* opts2 = opts1
, another call to free_opts(&opt2)
after calling free_opts(&opt1)
would definitely result in a program crash. I know a good habit of coding is to avoid such calls. But is there by any chance, I could detect that the memory is already freed? I am interested in even looking into Process Control Block
(That is where I think all the program information resides). Can I scrutinize the PCB structures, before performing a free()
'ing operations, so that I can avoid free()
'ing the memory twice?
Unfortunately, C has no support for smart pointers like f.e. C++ has.
In C, you always have to be careful to not cause memory leaks.
Anyway, You can f.e. provide another parameter in the manner of reference counting. This has the downside that you need to pass the amount of reference pointers to the allocated memory as argument everytime you call free_opts
and the amount have to be fixed, but it is an approach to help you out.
The memory is only freed, if all references have been "pseudo-freed".
All passed reference pointers, except the last one, are just made a null pointer and the pointed memory is in fact not freed until the last reference pointer has been past.
int free_opts (struct opts** opt, int ref) {
static int cnt = 0;
cnt++;
if ( cnt != ref ) {
*opt = NULL;
return 0;
}
free((*opt)->server);
free((*opt)->port);
if ((*opt)->protocol == PROTOCOL1) {
free_proto1(*opt);
}
else if ((*opt)->protocol == PROTOCOL2) {
free_proto2(*opt);
}
else
free((*opt)->protocol_data);
free(*opt);
return 1;
}
Whether the memory is actually freed or not, is indicated by the return value.