473,289 Members | 1,810 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,289 software developers and data experts.

Freeing memory for nested structures

Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could just
do:

if (pE != NULL)
free(pE);

Preposterously, it sometimes does work, but sometimes I also get a GPF.
Hence I assume that I am required to go the "awkward" way by using another
loop
in the destruction routine.
Or is this supposed to work by simply using the free routine from the
structure's base address?

-Andreas

Oct 28 '08 #1
25 4656

"Andreas Eibach" <ae*****@mail.comwrote in message
Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per
block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could
just
do:

if (pE != NULL)
free(pE);

Preposterously, it sometimes does work, but sometimes I also get a GPF.
Hence I assume that I am required to go the "awkward" way by using another
loop
in the destruction routine.
Or is this supposed to work by simply using the free routine from the
structure's base address?
Write a "kill" function.

void killentity_Stru_t(entity_Stru_t *e)
{
int i, ii;

if(e)
{
for(i=0;i<LASBLK;i++)
for(ii=0;ii<LASTLW;ii++)
free(e->block[i]->word[ii]):
free(e);
}
}

I think I've got this right. It becomes boilerplate code after a while. More
modern languages with garbage collection automate the process for you, but
in C you have to free everything by hand. Think of it as a little chore.

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Oct 28 '08 #2
"Andreas Eibach" <ae*****@mail.comwrites:
Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
pE = &entityStru_t , I assume.

By the way, if this is a Unix/POSIX system, AFAIK you are not supposed
to name things ending in _t ; they're reserved for the system.
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
I presume this is not your actual code, and that you really have
malloc(sizeof(unsigned long) * n) to allocate an array of n unsigned
longs. Allocating just one seems kind of weird, I suspect it wouldn't
be what you'd want.
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could just
do:

if (pE != NULL)
free(pE);
No. You must pass to free() exactly those pointers that were returned
from malloc(), and nothing else. free() does not know about your more
elaborate data structure and cannot dig down into it to find the things
you malloc'ed.
Preposterously, it sometimes does work, but sometimes I also get a GPF.
Hence I assume that I am required to go the "awkward" way by using another
loop
in the destruction routine.
Right.

However, if this really is right before exiting, it is probably not
necessary to free this stuff at all, as any sane operating system will
take care of it for you. See http://c-faq.com/malloc/freeb4exit.html .
It might still be a good idea to do it for maintainability reasons,
depending on your situation.
Or is this supposed to work by simply using the free routine from the
structure's base address?
No.
Oct 28 '08 #3
Andreas Eibach wrote:
Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
What you wrote is nonsense. I suspect that what you were trying to say
would be correctly expressed as:

entityStru_t *pE;
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could just
do:

if (pE != NULL)
free(pE);

Preposterously, it sometimes does work, but sometimes I also get a GPF.
You don't show us the code whereby pE acquires a value, so it's hard
to tell whether or not you should be able to safely call free(pE).
However, if you don't want to leak memory, you had better free(pE-
>block[i]->lword[j]) for all relevant values of "i" and "j", before
free()ing pE itself.
Hence I assume that I am required to go the "awkward" way by using another
loop
in the destruction routine.
Or is this supposed to work by simply using the free routine from the
structure's base address?
Was the memory for the structure itself allocated using malloc(),
calloc() or realloc()? You show no such allocation, so there's no way
for us to be sure. If it was, it can be free()d.
Oct 28 '08 #4

"Malcolm McLean" <re*******@btinternet.comwrote:
Write a "kill" function.

void killentity_Stru_t(entity_Stru_t *e)
{
int i, ii;

if(e)
{
for(i=0;i<LASBLK;i++)
for(ii=0;ii<LASTLW;ii++)
free(e->block[i]->word[ii]):
free(e);
}
}

I think I've got this right.
Indeed you got, yet when I asked, "do I have to go the awkward way", even
mentioning the word "loop" in the very same breath, I _had_ thought that the
readers will realize I do know *how* to do that :-)
But if I hate something it's trial-and_error beyond some certain extent;
hence I was just reflecting upon what I would start coding next ...
It becomes boilerplate code after a while. More
modern languages with garbage collection automate the process for you, but
in C you have to free everything by hand.
Well, I do know it that far. But I did not know *how* deeply (i. e. whether
C would "know" about sub-structures and stuff simply by creating a complex
chain of storage addresses or so---in this case, the base address would have
been sufficient; but apparently it does not)
>Think of it as a little chore.
Yes, thank you. So the loop thing has to do the trick then. :)

-Andreas

Oct 28 '08 #5
Andreas Eibach wrote:
Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
These loops look pretty strange. I *really* wish people with
code problems would post the actual code they're having trouble
with, and not "sort of like" paraphrases. We wind up debugging the
problems of the paraphrase, and not the actual problem -- which may
not even be present in the paraphrase.
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
Case in point: We can guess what the loops were supposed to be,
and we've been told that `pE' is a pointer to an entityStru_t, but
there's nothing to show us (1) how memory was allocated for `pE' to
point at, nor (2) how memory was allocated for each `pE->block[i]'.
Since your *entire* question is about memory management, hiding these
details behind a laconic "..." is not especially helpful. I can make
a lot of guesses about what the "..." might be concealing, but there's
no way for me to actually know what you've done wrong. Oh, sorry,
that last word is just a guess ...
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could just
do:

if (pE != NULL)
free(pE);
The test is harmless, but unnecessary.
Preposterously, it sometimes does work, but sometimes I also get a GPF.
Preposterously you haven't explained what you mean by "work," nor
what leads you to believe that it "worked."
Hence I assume that I am required to go the "awkward" way by using another
loop
in the destruction routine.
Or is this supposed to work by simply using the free routine from the
structure's base address?
The general rule: For each call malloc() there's a corresponding
call to free(). This isn't quite right all the time: You might allocate
something and just leave it allocated until program end, or you might
mix calloc() and realloc() into the picture. But the main observation
remains: One call to free() will not magically release memory obtained
from multiple calls to malloc().

--
Er*********@sun.com
Oct 28 '08 #6

"Nate Eldredge" <na**@vulcan.lanschrieb im Newsbeitrag
news:86************@vulcan.lan...
"Andreas Eibach" <ae*****@mail.comwrites:
Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per
block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)

pE = &entityStru_t , I assume.
yep.

entityStru_t * pE was the declaration, I'm often confusing them when I have
to word them, but I seem to have made it correctly, as pE->... does indeed
"find" the structure members ;-)
By the way, if this is a Unix/POSIX system, AFAIK you are not supposed
to name things ending in _t ; they're reserved for the system.
Heheh, yes it's a habit.

for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned
long));
>
I presume this is not your actual code,
You're right about that it's shortened a lot.
and that you really have
malloc(sizeof(unsigned long) * n) to allocate an array of n unsigned
longs.
Eh? I have a LASTLW amount of longs, and LASTLW is a #define'd constant, e.
g. 64. I do not use "hard-coded" numbers, it's a habit (but a good one this
time, I guess :))
Allocating just one seems kind of weird, I suspect it wouldn't
be what you'd want.
But I'm allocating LASTLW ones in a loop, you did notice the for() loop,
didn't you?
Come to think of it, I could get rid of the for loop and use n times the
ULONGs in the malloc, if that is what you mean.
free() does not know about your more
elaborate data structure and cannot dig down into it to find the things
you malloc'ed.
Yes, that was my suspicion and the same what Malcolm already pointed out.
Thanks to the both of you.
However, if this really is right before exiting, it is probably not
necessary to free this stuff at all [...]
It might still be a good idea to do it for maintainability reasons,
depending on your situation.
I'd always do it. Period. Never "rely" on how well the garbage collection
works.
(except for JAVA, the GC of which I do fully trust)

-Andreas

Oct 28 '08 #7
Andreas Eibach wrote:
....
But if I hate something it's trial-and_error beyond some certain extent;
You should hate it a whole lot more than you apparently do. When we're
talking about programming languages, the space you explore by trial
and error has both an huge volume and a very high dimensionality. It's
easy to get thoroughly lost in that space, and very difficult to find
out anything useful that way; finding what you're actually looking for
is practically impossible by that method. Reading the documentation,
reading text books, and asking for advice is the right way to go about
it.

....
Well, I do know it that far. But I did not know *how* deeply (i. e. whether
C would "know" about sub-structures and stuff simply by creating a complex
chain of storage addresses or so---in this case, the base address would have
been sufficient; but apparently it does not)
It doesn't matter what C "knows". What free(expression) is supposed to
do, if "expression" is not a null pointer, is to release the memory
pointed at by "expression"; something it can do if "expression" has a
value that matches one returned by a previous call to malloc(),
calloc() or realloc(). The behavior is undefined if you pass it any
other pointer value. It free()s the memory that was allocated by that
previous call - nothing more, nothing less.
Oct 28 '08 #8
On Tue, 28 Oct 2008 21:32:40 +0100, "Andreas Eibach"
<ae*****@mail.comwrote:
>Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could just
do:

if (pE != NULL)
free(pE);

Preposterously, it sometimes does work, but sometimes I also get a GPF.
Hence I assume that I am required to go the "awkward" way by using another
loop
in the destruction routine.
Or is this supposed to work by simply using the free routine from the
structure's base address?
Unfortunately, no. The rule is very simple; you need one call to
free for each call to malloc.

I assume that your sample code has typos, and that you really
mean to loop through the outer loop LASTBLK times and the inner
loop LASTLW times.

There are a number of things that you can do to decrease the
number of calls to malloc that you will need. In essence the
idea is to allocate a large block that holds many small blocks.
Here is an example:

Allocate a large block of longs, e.g.,

many_longs = malloc(LASTBLK*LASTLW*sizeof(long));
...
k = 0;
for (i=0;i<LASTBLK;i++) {
...
for (j=0; j<LASTLW;j++) {
pE->block[i]->lword[j] = many_longs + k++;
...
}
}

Incidentally, it seems rather odd that lword[j] is a pointer to a
long rather than simply a long. Did you mean to do this?

Richard Harter, cr*@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
Oct 28 '08 #9
Andreas Eibach wrote:
"Nate Eldredge" <na**@vulcan.lanschrieb im Newsbeitrag
news:86************@vulcan.lan...
"Andreas Eibach" <ae*****@mail.comwrites:
....|
typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;
>
This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.
>
Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
pE = &entityStru_t , I assume.

yep.
That still doesn't work. entitStru_t is a typedef for "struct
Entity". 6.5.3.2p1 says "The operand of the unary & operator shall be
either a function designator, the result of a [] or unary * operator,
or an lvalue that designates an object that is not a bit-field and is
not declared with the register storage-class specifier." The type
"struct Entity" fits none of those categories.
entityStru_t * pE was the declaration, I'm often confusing them when I have
to word them, but I seem to have made it correctly, as pE->... does indeed
"find" the structure members ;-)
Yes, but the code you've decided to not bother posting leaves us still
in the dark as to how the value of 'pE' is set. This is a critical
point in deciding whether or not your call to free() should actually
work.
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned
long));

I presume this is not your actual code,

You're right about that it's shortened a lot.
It's not just shortened, it's wrong. As written, both the inner and
outer loops are infinite, unless LASTBLK or LASTLW happens to be 0, in
which case the relevant loop doesn't execute at all. Re-check your
loop conditions.

....
Allocating just one seems kind of weird, I suspect it wouldn't
be what you'd want.

But I'm allocating LASTLW ones in a loop, you did notice the for() loop,
didn't you?

Come to think of it, I could get rid of the for loop and use n times the
ULONGs in the malloc, if that is what you mean.
Yes, that's precisely what you should be doing. There's usually a
small memory overhead, and a large time overhead, associated with
every call to malloc().
Oct 28 '08 #10
"Andreas Eibach" <ae*****@mail.comwrites:
"Nate Eldredge" <na**@vulcan.lanschrieb im Newsbeitrag
news:86************@vulcan.lan...
>"Andreas Eibach" <ae*****@mail.comwrites:
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned
long));
>>
I presume this is not your actual code,

You're right about that it's shortened a lot.
>and that you really have
malloc(sizeof(unsigned long) * n) to allocate an array of n unsigned
longs.

Eh? I have a LASTLW amount of longs, and LASTLW is a #define'd constant, e.
g. 64. I do not use "hard-coded" numbers, it's a habit (but a good one this
time, I guess :))
>Allocating just one seems kind of weird, I suspect it wouldn't
be what you'd want.

But I'm allocating LASTLW ones in a loop, you did notice the for() loop,
didn't you?
Come to think of it, I could get rid of the for loop and use n times the
ULONGs in the malloc, if that is what you mean.
You have an array of LASTLW pointers, and you set each of them to point
to a single (malloc'ed) unsigned long. It would be easier just to have
an array of LASTLW unsigned longs.
>
>free() does not know about your more
elaborate data structure and cannot dig down into it to find the things
you malloc'ed.

Yes, that was my suspicion and the same what Malcolm already pointed out.
Thanks to the both of you.
>However, if this really is right before exiting, it is probably not
necessary to free this stuff at all [...]
It might still be a good idea to do it for maintainability reasons,
depending on your situation.

I'd always do it. Period. Never "rely" on how well the garbage collection
works.
(except for JAVA, the GC of which I do fully trust)
This is a different thing from garbage collection. Garbage collection
relies on the compiler keeping track of all the pointers you malloc'ed,
knowing when they're no longer referenced, and freeing the memory when
needed. What I'm talking about is the operating system reclaiming every
byte of memory that belonged to your program, whether it was obtained by
malloc() or contained program code, all at one blow. There are no
subtleties and no wondering about how efficient it is. So as far as the
behavior of the program is concerned, that means that calling free()
just before exiting is a waste of code space, CPU time, and programmer
time.

Possible reasons why you might want to do it anyway:

1. Practice
2. In case you someday make the program do something more after the
structure is no longer needed, or repeat its process many times, or be
encapsulated in a library
3. In case you are using a primitive, embedded, or ancient system that
doesn't have a proper OS
Oct 28 '08 #11

"jameskuyper" <ja*********@verizon.netwrote:
Yes, but the code you've decided to not bother posting leaves us still
in the dark as to how the value of 'pE' is set. This is a critical
point in deciding whether or not your call to free() should actually
work.
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned
long));
>
I presume this is not your actual code,
You're right about that it's shortened a lot.

It's not just shortened, it's wrong. As written, both the inner and
outer loops are infinite, unless LASTBLK or LASTLW happens to be 0, in
which case the relevant loop doesn't execute at all. Re-check your
loop conditions.
Sometimes things are _that_ simple.
Fat fingers forgot about typing the '<'! Doh!

.... i <= LASTBLK ...
.... j <= LASTLW ...

Apologies.
Come to think of it, I could get rid of the for loop and use n times the
ULONGs in the malloc, if that is what you mean.

Yes, that's precisely what you should be doing. There's usually a
small memory overhead, and a large time overhead, associated with
every call to malloc().
Hmm. Good point, thanks again.

-Andreas

Oct 28 '08 #12
c...@tiac.net (Richard Harter) wrote:
"Andreas Eibach" <aeib...@mail.comwrote:
...I assume that I am required to go the "awkward"
way by using another loop in the destruction routine.
Or is this supposed to work by simply using the free
routine from the structure's base address?

Unfortunately, no. *The rule is very simple; you need
one call to free for each call to malloc.
It's unfortunate (for me) that C99 changed the semantics
of realloc in the case where the size argument is zero.
I have (C99 incompatible) code that used realloc to do
both the allocation and deallocation. Of course, you
still had to call the function to set the size of the
object to 'zero' to perform the deallocation.

--
Peter
Oct 28 '08 #13
"Andreas Eibach" <ae*****@mail.comwrote in message
>
Indeed you got, yet when I asked, "do I have to go the awkward way", even
mentioning the word "loop" in the very same breath, I _had_ thought that
the
readers will realize I do know *how* to do that :-)
The point I was making is that you should get into the habit of writing a
kill function for every structure that contains allocated pointers. You
should also write it defensively so it can be passed nulls. Normally you
will have a constructor to match it, often several constructors.

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Oct 28 '08 #14
Peter Nilsson <ai***@acay.com.auwrote:
>
It's unfortunate (for me) that C99 changed the semantics
of realloc in the case where the size argument is zero.
How do you think the semantics changed? The description was changed to
hopefully make them clearer, but there wasn't any deliberate change to
them that I remember.
--
Larry Jones

Somebody's always running my life. I never get to do what I want to do.
-- Calvin
Oct 29 '08 #15
lawrence.jo...@siemens.com wrote:
Peter Nilsson <ai...@acay.com.auwrote:
It's unfortunate (for me) that C99 changed the semantics
of realloc in the case where the size argument is zero.

How do you think the semantics changed?
For non null pointers: in C90, realloc(..., 0) freed the
block and returned a null pointer; in C99, it does a
malloc(0). It remains implementation defined whether
malloc(0) behaves as if a nonzero size was supplied.

--
Peter
Oct 29 '08 #16
On 28 Oct, 21:58, Nate Eldredge <n...@vulcan.lanwrote
re: freeing memory before returning from main():
>
Possible reasons why you might want to do it anyway:

1. Practice
2. In case you someday make the program do something more after the
structure is no longer needed, or repeat its process many times, or be
encapsulated in a library
3. In case you are using a primitive, embedded, or ancient system that
doesn't have a proper OS
4. So that tests (such as valgrind) report no memory leaks,
freeing the programmer from the need to determine that all
of the reported leaks are expected.
Oct 29 '08 #17
On 28 Oct, 22:05, "Andreas Eibach" <aeib...@mail.comwrote:
"jameskuyper" <jameskuy...@verizon.netwrote:
<snip>
* * *for (i 0; i = LASTBLK; i++)
* * *{ *...
* * * * * for (j= 0; j = LASTLW; j++)
* * * * *{ * ...
* * * * * * * * *pE->block[i]->lword[j] = malloc (sizeof(unsigned
long));
I presume this is not your actual code,
You're right about that it's shortened a lot.
It's not just shortened, it's wrong. As written, both the inner and
outer loops are infinite, unless LASTBLK or LASTLW happens to be 0, in
which case the relevant loop doesn't execute at all. *Re-check your
loop conditions.

Sometimes things are _that_ simple.
Fat fingers forgot about typing the '<'! Doh!

... i <= LASTBLK ...
... j <= LASTLW ...

Apologies.
YM
for (i = 0; i < LASTBLK; i++)

ie. no '=' needed

<snip>

--
Nick Keighley
Oct 29 '08 #18
In article <6m************@mid.uni-berlin.de>, "Andreas Eibach"
<ae*****@mail.comwrote:
Hi again,

one of the other big woes I'm having...

typedef struct perBlockStru /* (structure) Long words per block
*/
{
unsigned long *lword[LASTLW];
} lwperBlockStru_t;

typedef struct Entity /* (structure) Holds the whole thing */
{
perBlockStru_t* block[LASTBLK];
} entityStru_t;

This is a - fairly simplified - structure I'm using.
Of course there are more elements, but they are irrelevant here.

Far below, there's the obvious mem allocation happening:
(pE = *entityStru_t)
for (i 0; i = LASTBLK; i++)
{ ...
for (j= 0; j = LASTLW; j++)
{ ...
pE->block[i]->lword[j] = malloc (sizeof(unsigned long));
...
}
}

At the VERY bottom, shortly before exiting the app, I *thought* I could just
do:

if (pE != NULL)
free(pE);

Preposterously, it sometimes does work, but sometimes I also get a GPF.
Hence I assume that I am required to go the "awkward" way by using another
loop in the destruction routine.
Or is this supposed to work by simply using the free routine from the
structure's base address?
If free() freed the passed block AND all blocks the block contained
pointers to, how you free a block that pointed to other blocks you did NOT
want freed? As in

struct S { char* p; };

struct S* s1 = malloc( sizeof *s1 );
struct S* s2 = malloc( sizeof *s2 );

s1->p = malloc( 1234 );
s2->p = s1->p;

free( s1 ); /* how would it know not to free s1->p? */

s2->p [0] = 'X'; /* if the free above freed p, then this would fail */
Oct 29 '08 #19
Peter Nilsson <ai***@acay.com.auwrites:
lawrence.jo...@siemens.com wrote:
>Peter Nilsson <ai...@acay.com.auwrote:
It's unfortunate (for me) that C99 changed the semantics
of realloc in the case where the size argument is zero.

How do you think the semantics changed?

For non null pointers: in C90, realloc(..., 0) freed the
block and returned a null pointer;
Yes...
in C99, it does a malloc(0).
No. It is realloc(NULL, size) which behaves like malloc(size).

The only time C99 7.20.3.4 says realloc() can _free_ the old object is
when it returns a new object. NULL return is failure return only.
So it doesn't matter to realloc that C99 7.20.3 (Memory management
functions) says size=0 can give either NULL or a memory object.

Otherwise, realloc(ptr, 0) return NULL either after freeing and not
freeing the object - so the program couldn't tell if it should free the
object. But then it likely can't be sure anyway, since even if the
compiler says it's a C99 compiler, it may still be using a C89 library.

So, just don't use realloc(ptr, 0) anymore.
It remains implementation defined whether
malloc(0) behaves as if a nonzero size was supplied.
True but irrelevant to C99 realloc.

--
Hallvard
Oct 29 '08 #20
Hallvard B Furuseth <h.b.furus...@usit.uio.nowrote:
Peter Nilsson <ai...@acay.com.auwrites:
lawrence.jo...@siemens.com wrote:
Peter Nilsson <ai...@acay.com.auwrote:
It's unfortunate (for me) that C99 changed the
semantics of realloc in the case where the size
argument is zero.
>
How do you think the semantics changed?
For non null pointers: in C90, realloc(..., 0) freed
the block and returned a null pointer;

Yes...
in C99, it does a malloc(0).

No. *It is realloc(NULL, size) which behaves like
malloc(size).

The only time C99 7.20.3.4 says realloc() can _free_
the old object is when it returns a new object.
AFAICS, 7.20.3p1 applies.
>*NULL return is failure return only.
Why do you say that?

Note the C89 draft is similarly worded to C99 with
regards to the return value from realloc. The latter
is just more clear in saying the 'same' pointer may
be returned.
So it doesn't matter to realloc that C99 7.20.3
(Memory management functions) says size=0 can give
either NULL or a memory object.
I can't see how you can dismiss it.
Otherwise, realloc(ptr, 0) return NULL either after
freeing and not freeing the object - so the program
couldn't tell if it should free the object.
You've lost me. "If memory for the new object cannot
be allocated, the old object is not deallocated..."

So realloc(ptr, 0) does a malloc(0). If that fails, ptr
is returned; if it succeeds the old object is deallocated
and a new pointer is returned.

<snip>
So, just don't use realloc(ptr, 0) anymore.
I don't. But for different reasoning it seems. :)

--
Peter
Oct 29 '08 #21
Peter Nilsson writes:
Hallvard B Furuseth <h.b.furus...@usit.uio.nowrote:
>The only time C99 7.20.3.4 says realloc() can _free_
the old object is when it returns a new object.

AFAICS, 7.20.3p1 applies.
>>*NULL return is failure return only.

Why do you say that?

Note the C89 draft is similarly worded to C99 with
regards to the return value from realloc.
That is not the point. The point is: Look for when the standards say
realloc() may free the old object. realloc() can't free an object just
because it looks like a good idea, unless the standard says it can.

C89 explicitly says: "If size is zero and ptr is not a null pointer, the
object it points to is freed."

C99 says the old object is freed only when a new object is returned:
"The realloc function deallocates the old object pointed to by ptr and
returns a pointer to a new object that has the size specified by size.
If memory for the new object cannot be allocated, the old object is
not deallocated and its value is unchanged."

Therefore if C99 realloc(non-null, 0) returns NULL, this is a failure
return. OTOH if C99 realloc(NULL, 0) returns NULL, that can be
non-failure equivalent to malloc(0).
The latter is just more clear in saying the 'same' pointer may be
returned.
Except that NULL does not point to an object.
(..snip..)
>Otherwise, realloc(ptr, 0) return NULL either after
freeing and not freeing the object - so the program
couldn't tell if it should free the object.

You've lost me. "If memory for the new object cannot
be allocated, the old object is not deallocated..."

So realloc(ptr, 0) does a malloc(0).
No, because:
If that fails, ptr is returned;
No, if that fails realloc returns NULL and the object is unchanged.
if it succeeds the old object is deallocated
and a new pointer is returned.
If it succeeds the old object is deallocated, and it is
implementation-defined whether malloc(0) returns an object or NULL.

--
Hallvard
Oct 29 '08 #22
I wrote:
>So realloc(ptr, 0) does a malloc(0).
(...)
if it succeeds the old object is deallocated
and a new pointer is returned.

If it succeeds the old object is deallocated, and it is
implementation-defined whether malloc(0) returns an object or NULL.
I should have said, that is how it would be if it was defined to do
malloc(0).

--
Hallvard
Oct 29 '08 #23
On Wed, 29 Oct 2008 14:42:00 -0700, Peter Nilsson wrote:
Hallvard B Furuseth <h.b.furus...@usit.uio.nowrote:
>The only time C99 7.20.3.4 says realloc() can _free_ the old object is
when it returns a new object.

AFAICS, 7.20.3p1 applies.
I agree with Hallvard's reply to this, but would like to try expressing
this in a slightly different way: 7.20.3p1 does apply. It gives
implementations permission to unconditionally fail to realloc to 0 bytes.
Oct 30 '08 #24
Harald van Dijk writes:
On Wed, 29 Oct 2008 14:42:00 -0700, Peter Nilsson wrote:
>Hallvard B Furuseth <h.b.furus...@usit.uio.nowrote:
>>The only time C99 7.20.3.4 says realloc() can _free_ the old object is
when it returns a new object.

AFAICS, 7.20.3p1 applies.

I agree with Hallvard's reply to this, but would like to try expressing
this in a slightly different way: 7.20.3p1 does apply. It gives
implementations permission to unconditionally fail to realloc to 0 bytes.
I think that means you don't agree:-)
7.20.3p1's NULL is success return, while 7.20.3.4's is failure return.
On success return, the old object it deallocated. On failure return it
is not. Which is why realloc(non-null, 0) isn't allowed both - we
couldn't tell success from failure.

In any case, what matters for programming is that it's safest and
simplest to avoid realloc(non-null, 0).

--
Hallvard
Nov 4 '08 #25
On Tue, 04 Nov 2008 13:20:37 +0100, Hallvard B Furuseth wrote:
Harald van Dijk writes:
>On Wed, 29 Oct 2008 14:42:00 -0700, Peter Nilsson wrote:
>>Hallvard B Furuseth <h.b.furus...@usit.uio.nowrote:
The only time C99 7.20.3.4 says realloc() can _free_ the old object
is when it returns a new object.

AFAICS, 7.20.3p1 applies.

I agree with Hallvard's reply to this, but would like to try expressing
this in a slightly different way: 7.20.3p1 does apply. It gives
implementations permission to unconditionally fail to realloc to 0
bytes.

I think that means you don't agree:-) 7.20.3p1's NULL is success return,
while 7.20.3.4's is failure return.
In that case, I agree that we disagree, though the issue of disagreement
was not stated in your other message, which I continue to agree with. :-)
7.20.3p1's null pointer is a return value. It doesn't specify whether it
is a successful return or an indication of an error.
On success return, the old object
it deallocated. On failure return it is not. Which is why
realloc(non-null, 0) isn't allowed both - we couldn't tell success from
failure.
Right. 7.20.3p1 says realloc(non-null, 0) is allowed to always return a
null pointer. When realloc(non-null, 0) returns a null pointer, the old
object is not freed. I don't see how these are incompatible. It seems to
me to say that realloc(non-null, 0) is allowed to always ignore the
request and return a null pointer (without freeing anything).
In any case, what matters for programming is that it's safest and
simplest to avoid realloc(non-null, 0).
Definitely. If you want free, it has its own name. If you don't want free,
it doesn't usually make sense to pass a size of zero.
Nov 4 '08 #26

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: disco | last post by:
I am working on this example from a book "C Primer Plus" by Prata 4th edition - p. 672. There is no erata on this problem at the publisher's website. 1) Is it a violation of copyright laws to...
12
by: f.oppedisano | last post by:
Hi, i would like to allocate two structures making only one malloc call. So i do prt=malloc(sizeof(struct1)+sizeof(struct2)); After this operation i make two pointers one to the first struct...
9
by: Alfonso Morra | last post by:
Hi, I am having some probs with copying memory blocks around (part of a messaging library) and I would like some confirmation to make sure that I'm going about things the right way. I have...
15
by: yehoshua | last post by:
Is there anyway to explicitly tell the garbage collector you are done with an object? In my app I have a point where I am sure there should be no references to an set of objects (well i remove...
94
by: smnoff | last post by:
I have searched the internet for malloc and dynamic malloc; however, I still don't know or readily see what is general way to allocate memory to char * variable that I want to assign the substring...
171
by: Raman | last post by:
Hi All, Here is a small Code, int main(void) { char *p=(char *) malloc(100); strcpy(p,"Test1234567890"); p=p+10; free(p);
3
by: Amit_Basnak | last post by:
Dear Friends I have the follwoing function "tss_fe_get_own_info" which has the arguments as shows below tss_fe_get_own_info(char *user_id, tss_user_profile_t **p_buf_UserSecInfo, error_status_t...
6
by: Praetorian | last post by:
This is actually 2 questions: The first one: I have a function (FuncA) calling another (FuncB) with a set of parameters which also includes an int * initialized to NULL before the call. Now...
11
by: vivek | last post by:
Hello, I have a pointer to a main structure which again consists of structures, enums, char, int, float and again complex structures. When i free all the contents of the main structure, it...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.