malloc and free

K

Kelvin Leung

If I allocate a block of memory
char *p = (char*)malloc(sizeof(char)*10);
afterward I want to free a number of them, say the first 3 blocks, how do I
do so? If I tried free(p), the whole 10 blocks are being freed. Is there a
method to free only the first few blocks without having to malloc a new
block and copy the remaining ones?

Thank you
 
E

Eric Sosman

Kelvin said:
If I allocate a block of memory
char *p = (char*)malloc(sizeof(char)*10);
afterward I want to free a number of them, say the first 3 blocks, how do I
do so? If I tried free(p), the whole 10 blocks are being freed. Is there a
method to free only the first few blocks without having to malloc a new
block and copy the remaining ones?

No.
 
A

Arthur J. O'Dwyer

If I allocate a block of memory
char *p = (char*)malloc(sizeof(char)*10);

char *p = malloc(10 * sizeof *p);

is the more idiomatic way to do that. Or for 'char'
specifically, if you're actually using the pointer to
point to a string (and thus not expecting 'char' to
change to 'short' or 'int' in future code reviews),

char *p = malloc(10);

as I do below.
(See the FAQ and Google Groups for reasons why.)
afterward I want to free a number of them, say the first 3 blocks, how do I
do so? If I tried free(p), the whole 10 blocks are being freed. Is there a
method to free only the first few blocks without having to malloc a new
block and copy the remaining ones?

Nope. Sorry.
To free the first three 'char's, write:

{
char *p = malloc(10); /* NB: sizeof(char) is 1 by definition */
char *temp;

if (p == NULL) exit(EXIT_FAILURE);

temp = malloc(7);
if (temp == NULL) exit(EXIT_FAILURE);

memcpy(temp, p, 7);
free(p);
p = temp;

[...]

free(p);
}

HTH,
-Arthur
 
C

Christopher Benson-Manica

Arthur J. O'Dwyer said:
To free the first three 'char's, write:
{
char *p = malloc(10); /* NB: sizeof(char) is 1 by definition */
char *temp;
if (p == NULL) exit(EXIT_FAILURE);
temp = malloc(7);
if (temp == NULL) exit(EXIT_FAILURE);
memcpy(temp, p, 7);
free(p);
p = temp;

free(p);
}

Is that preferable to the following (untested) code?

{
const int size=10;
char *p=malloc( size );
char *tmp=p;

if( !p ) exit( EXIT_FAILURE );

memmove( p, p+3, size-3 ); /* assumes p has at least four members */
if( (tmp=realloc(p,size-3)) == NULL ) {
free( p ); /* not strictly necessary */
exit( EXIT_FAILURE );
}
...
free( p );
}
 
T

Thomas Stegen

Arthur said:
is the more idiomatic way to do that. Or for 'char'
specifically, if you're actually using the pointer to
point to a string (and thus not expecting 'char' to
change to 'short' or 'int' in future code reviews),

char *p = malloc(10);

This is just as bad as using
char *p = malloc(10 * sizeof char);

You are in both cases explicitly relying on the type of p.

In the first case you might be said to implicitly explicitly
rely on the type of p. :p
 
D

Dan Pop

In said:
If I allocate a block of memory
char *p = (char*)malloc(sizeof(char)*10);

The right way of doing it is:

char *p = malloc(10);

The cast is a bad idea and the size of a char is not going to change from
1 anytime in the foreseeable future.
afterward I want to free a number of them, say the first 3 blocks, how do I
do so? If I tried free(p), the whole 10 blocks are being freed. Is there a
method to free only the first few blocks without having to malloc a new
block and copy the remaining ones?

They are called "bytes", not "blocks". You can either free the whole
block (by calling free()) or the last part of it (by calling realloc()).

There is no way of freeing the beginning of the block, while preserving
the data at its end. What you can do is use memmove() to move the data
at the beginning of the block and free its last part, with a realloc call.
Note, however, that if the realloc() call succeeds, the remaining smaller
block may be moved to a new address (but its contents is preserved).

Dan
 
I

Irrwahn Grausewitz

Kelvin Leung said:
If I allocate a block of memory
char *p = (char*)malloc(sizeof(char)*10);

Better:

char *p = malloc(10);

The cast is spurious and may hide errors, and sizeof(char) equals 1 by
definition.

Even better:

char *p = malloc(10 * sizeof *p);

This way you don't even have to care about the malloc expression when
the type p points to is ever going to change in the future.
afterward I want to free a number of them, say the first 3 blocks, how do I
do so? If I tried free(p), the whole 10 blocks are being freed. Is there a
method to free only the first few blocks without having to malloc a new
block and copy the remaining ones?

No, but you may use the realloc function to cut off the tail, so to say.

Regards
 
C

Christopher Benson-Manica

Irrwahn Grausewitz said:
No, but you may use the realloc function to cut off the tail, so to say.

Considering that OP wanted to free the *first* three elements, realloc()
can't do the job alone.
 
K

Keith Thompson

Christopher Benson-Manica said:
Considering that OP wanted to free the *first* three elements, realloc()
can't do the job alone.

Which is probably why Irrwahn's answer started with "No, but".
 
E

E. Robert Tisdale

Dan said:
Kelvin Leung writes:




The right way of doing it is:

char *p = malloc(10);

The cast is a bad idea
and the size of a char is not going to change from 1
anytime in the foreseeable future.

This is bad advice if you need to compile with a C++ compiler:
> cat malloc.c
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
const
int n = 10;
int* p = malloc(n*sizeof(int));
for (int j = 0; j < n; ++j)
p[j] = j;
for (int j = 0; j < n; ++j)
fprintf(stdout, "%2d = p[%2d]\n", p[j], j);
return 0;
}
> g++ -x c++ -Wall -ansi -pedantic -O2 -o malloc malloc.c
malloc.c: In function `int main(int, char**)':
malloc.c:7: warning: invalid conversion from `void*' to `int*'
 
R

rihad

Dan said:
The cast is a bad idea

This is bad advice if you need to compile with a C++ compiler:
cat malloc.c
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
const
int n = 10;
int* p = malloc(n*sizeof(int));
for (int j = 0; j < n; ++j)
p[j] = j;
for (int j = 0; j < n; ++j)
fprintf(stdout, "%2d = p[%2d]\n", p[j], j);
return 0;
}
g++ -x c++ -Wall -ansi -pedantic -O2 -o malloc malloc.c
malloc.c: In function `int main(int, char**)':
malloc.c:7: warning: invalid conversion from `void*' to `int*'

So what? C++ programs should be using the `new' operator anyway. And C++ is
offtopic in c.l.c.
 
C

Charles Harrison Caudill

Christopher Benson-Manica said:
Arthur J. O'Dwyer <[email protected]> spoke thus:
Is that preferable to the following (untested) code?
{
const int size=10;
char *p=malloc( size );
char *tmp=p;

if( !p ) exit( EXIT_FAILURE );
memmove( p, p+3, size-3 ); /* assumes p has at least four members */
if( (tmp=realloc(p,size-3)) == NULL ) {
free( p ); /* not strictly necessary */
exit( EXIT_FAILURE );
}
...
free( p );

I'm assuming that here you mean free(tmp);


I havn't been able to make it core dump but shouldn't it?
When you realloc to a large enough size that you have to create a
whole new area, shouldn't the vm_struct be destroyed and memory be
copied on write to the new region? Assuming linux is posix compliant
for realloc, then it *should* apply in a similar manner to all other
posix compliant os's. I'm not certain about linux's functionality,
my book is at home.
 
E

E. Robert Tisdale

rihad said:
E. Robert Tisdale said:
Dan said:
Kelvin Leung writes:

char *p = (char*)malloc(sizeof(char)*10);

The cast is a bad idea

This is bad advice if you need to compile with a C++ compiler:
cat malloc.c
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
const
int n = 10;
int* p = malloc(n*sizeof(int));
for (int j = 0; j < n; ++j)
p[j] = j;
for (int j = 0; j < n; ++j)
fprintf(stdout, "%2d = p[%2d]\n", p[j], j);
return 0;
}
g++ -x c++ -Wall -ansi -pedantic -O2 -o malloc malloc.c
malloc.c: In function `int main(int, char**)':
malloc.c:7: warning: invalid conversion from `void*' to `int*'

So what?
C++ programs should be using the `new' operator anyway.
And C++ is offtopic in c.l.c.

I don't want to discuss C++.
But *real* C programmers can't afford to ignore C++.
They must write C code which can be compiled by C++ compilers
as well as by C compilers.
 
R

Richard Heathfield

E. Robert Tisdale said:
This is bad advice if you need to compile with a C++ compiler:

If you need to compile with a C++ compiler, you're in the wrong newsgroup.
 
T

Thomas Stegen

E. Robert Tisdale said:
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
const
int n = 10;
int* p = malloc(n*sizeof(int));
for (int j = 0; j < n; ++j)
p[j] = j;
for (int j = 0; j < n; ++j)
fprintf(stdout, "%2d = p[%2d]\n", p[j], j);
return 0;
}

I made the obvious fix and it _still_ would not compile with my
Fortran compiler. To add insult to injury the above is not even
valid Perl syntax. And I though any kind of line noise would go
in Perl.

Well, I guess my multilingual skills are not what they should
be.
 
D

Default User

E. Robert Tisdale said:
I don't want to discuss C++.
But *real* C programmers can't afford to ignore C++.


*Real* newsgroup trolls can't keep from mentioning it either,
apparently.




Brian Rodenborn
 
A

Arthur J. O'Dwyer

Well, I didn't think of your way, but both ways work. :)
I think the use of 'memmove' instead of 'memcpy' is a little
more obscure, and I personally try to avoid 'realloc' in
general, just because of the contortions through which one
has to go in order to do proper error-checking.
But your (Chris's) way works, and I bet there are sane
people out there who prefer it over mine.
I'm assuming that here you mean free(tmp);

Probably Chris meant to insert an

else { p = tmp; }

three lines up, instead.
I havn't been able to make it core dump but shouldn't it?

Of course not!
When you realloc to a large enough size that you have to create a
whole new area,

Strictly speaking, you may never *ever* have to "create a whole new
area." malloc() could just give you these really gi-normous blocks
of memory to begin with. :)
shouldn't the vm_struct be destroyed

C has no concept of "vm_struct", unless you, the programmer,
decide to define one in your own code.
and memory be
copied on write to the new region? Assuming linux is posix compliant
for realloc,

Linux is off-topic for c.l.c. So is POSIX. And as far as I know,
the behavior of 'realloc' is not defined or extended in any way by
POSIX anyway. [No, I *don't* care.]
then it *should* apply in a similar manner to all other
posix compliant os's. I'm not certain about linux's functionality,
my book is at home.

Turns out you don't need it in this newsgroup; the Book here
is K&R2, and the Final Authority is the ISO standard. You wanna
talk POSIX or vm_structs or whatever, go to a newsgroup where
people talk about that stuff.

HTH,
-Arthur
 
A

Arthur J. O'Dwyer

This is just as bad as using
char *p = malloc(10 * sizeof char);

Not quite as bad, because it's less verbose. (Also, because
it does compile; but I'm sure you meant to add parentheses
around 'char' in your example. If you really didn't, then I
would strongly disagree that my version is "as bad." ;-)
You are in both cases explicitly relying on the type of p.

Yes, that is correct. However, C does several clever things
with arrays of 'char' that it doesn't do with any other type
of array, so if you're going to start passing 'p' to 'strlen'
or 'fputs', odds are that the type of 'p' isn't going to
change anytime in the foreseeable future (to steal Dan Pop's
phrase).
In the first case you might be said to implicitly explicitly
rely on the type of p. :p

If the next line of the function is

strcpy(p, "hello");

then IMHO that assumption is perfectly justifiable.

-Arthur
 
K

Keith Thompson

E. Robert Tisdale said:
I don't want to discuss C++.

Then don't.
But *real* C programmers can't afford to ignore C++.
They must write C code which can be compiled by C++ compilers
as well as by C compilers.

That's complete nonsense, as I'm sure you know.
 
M

Mark Gordon

Well, I didn't think of your way, but both ways work. :)
I think the use of 'memmove' instead of 'memcpy' is a little
more obscure,

I don't find memmove any more obscure than memcpy, if anything I find it
less obscure because it gives defined results then memcpy invokes UB and
when memcpy does not invoke UB memmove behaves the same.
and I personally try to avoid 'realloc' in
general, just because of the contortions through which one
has to go in order to do proper error-checking.

Write a realloc wrapper, then you only have to worry about this once.
But your (Chris's) way works, and I bet there are sane
people out there who prefer it over mine.


Probably Chris meant to insert an

else { p = tmp; }

three lines up, instead.

<snip>

The advantage I see in the memmove/realloc version written by
Christopher over the memcpy/malloc/free version written by Arthur is
that it potentially has lower memory requirements and may fragment
memory less. After all, if you have only 5 bytes available for mallocing
by the C environment the malloc(10) will fail but the realloc(p,size-3)
could succeed since it does not need any more memory.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Alternative to Malloc in C 0
malloc 40
malloc and maximum size 56
a fast malloc/free implementation & benchmarks 0
malloc()/free() question 20
malloc() question... 18
using my own malloc() 14
malloc and free? 20

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top