Amogh wrote:
Hi,
My question is related to setting freed pointers to NULL.
After freeing a pointer:
1) Should the freeing routine also be responsible for setting the
pointer to null?
2) Or, should the client/user code be responsible for doing it?
On what basis should a decision be made favouring either case ?
Most of the time, a freed pointer does not get set to null. Typically,
when the object is no longer necessary, it is freed, and then the
pointer itself is deallocated. This may occur with an explicit free
statement, or it may happen when the function returns and its automatic
variables are lost.
The following example code contains two "freeing routines". Neither the
routine itself, nor the client/user code actually sets any pointers to null.
Note that pointers are passed by value in C. If the freeing routine
wanted to set the caller's pointer to NULL, it would have to take a
pointer to that pointer. That seems like poor style to me.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct {
int year;
int month;
int day;
} Date;
Date *new_date(int year, int month, int day)
{
Date *d = malloc(sizeof *d);
if(!d) return NULL;
d->year = year;
d->month = month;
d->day = day;
return d;
}
void destroy_date(Date *d)
{
free(d);
/* There is no point setting 'd = 0' here, as
the value of d is lost when the function
returns anyway.
One would have to write the function as:
void destroy_date(Date **pd)
{
free(*pd);
*pd = NULL;
}
and the caller would call it as
destroy_date(&date);
that would actually set the caller's 'date' variable to null.
I don't recommend doing this.
*/
}
typedef struct {
char *name;
Date *birthdate;
} Person;
Person *new_person(const char *name, int year, int month, int day)
{
Person *p = malloc(sizeof *p);
if(!p) return NULL;
p->name = malloc(strlen(name) + 1);
if(!p->name)
{
free(p);
return NULL;
}
strcpy(p->name, name);
p->birthdate = new_date(year, month, day);
if(!p->birthdate)
{
free(p->name);
free(p);
return NULL;
}
return p;
}
void destroy_person(Person *p)
{
free(p->name);
destroy_date(p->birthdate);
free(p);
}
const char *ordinal(int n)
{
if(n % 100 == 11 || n % 100 == 12 || n % 100 == 13) return "th";
if(n % 10 == 1) return "st";
if(n % 10 == 2) return "nd";
if(n % 10 == 3) return "rd";
return "th";
}
const char *monthname(int n)
{
const char *names[] = {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"};
if(n >= 1 && n <= 12)
return names[n - 1];
else
return NULL;
}
void show_person(const Person *p)
{
printf("%s was born on the %d%s of %s, %d\n",
p->name,
p->birthdate->day,
ordinal(p->birthdate->day),
monthname(p->birthdate->month),
p->birthdate->year);
}
int main(void)
{
size_t i;
Person *family[5];
family[0] = new_person("Simon", 1982, 9, 6);
family[1] = new_person("Andrew", 1986, 2, 25);
family[2] = new_person("Thomas", 1987, 6, 5);
family[3] = new_person("Sue", 1957, 5, 27);
family[4] = new_person("Michael", 1953, 2, 6);
for(i = 0; i < sizeof family / sizeof *family; i++)
{
if(family[i])
{
show_person(family[i]);
destroy_person(family[i]);
}
}
return 0;
}
--
Simon.