freeing allocated memory

B

binaya

Dear all,

Say I allocate a block of memory using the command malloc.I
have a question. Can I deallocate certain portion of it only during
runtime ?

For eg:

Say I allocate 5 pointers to int as below.

link=(int*)malloc(5*sizeof(int))



But during runtime, I find that I only need the front 3 of them.ie
I only need link,link+1 and link+2.

If I don't need link+3 and link+4, can I free these last two
pointers to int using the command free(link+3) ?



If not, then what is the best way to do so ?
Thanking you in advance.
 
J

James Hu

Say I allocate a block of memory using the command malloc.I
have a question. Can I deallocate certain portion of it only during
runtime ?

If you want to shrink the amount of memory you initially allocated,
you can use realloc().

-- James
 
R

Robert Stankowic

binaya said:
Dear all,

Say I allocate a block of memory using the command malloc.I
have a question. Can I deallocate certain portion of it only during
runtime ?

For eg:

Say I allocate 5 pointers to int as below.

link=(int*)malloc(5*sizeof(int))



But during runtime, I find that I only need the front 3 of them.ie
I only need link,link+1 and link+2.

If I don't need link+3 and link+4, can I free these last two
pointers to int using the command free(link+3) ?



If not, then what is the best way to do so ?
Thanking you in advance.

#include <stdlib.h>

int main(void)
{
int *tmp;
int *my_array = malloc(5 * sizeof *my_array);

if(my_array)
{
my_array[0] = 100;
my_array[1] = 200;
my_array[2] = 300;
/*now you find out, you need just 3 ints*/
tmp = realloc(my_array, 3 * sizeof *my_array);
if(tmp)
{
my_array = tmp;
/*use the array here, it's now just 3 ints long, however, the
content of the first three ints of the original array are preserved*/
}
else
{
/*realloc failed, but your allocated 5 ints are still available*/
}
}
else
{
/*your request failed, take some sensible action*/
return EXIT_FAILURE;
}
free(my_array);
return EXIT_SUCCESS;
}

HTH
Robert
 
A

Arthur J. O'Dwyer

If you want to shrink the amount of memory you initially allocated,
you can use realloc().

But you can only shrink it from the front. That is, you can do

int *p = malloc(5 * sizeof *p); /* allocate 5 ints */

p = realloc(p, 3 * sizeof *p); /* shrink to only first 3 ints */

but you absolutely *cannot* do

int *p = malloc(5 * sizeof *p); /* allocate 5 ints */

p = realloc(p+2, 3 * sizeof *p); /* shrink to last 3 ints */

because the pointer 'p+2' didn't come from a call to malloc() --
only the pointer 'p' itself did. If you want to copy from the
end of the array, you have to do it explicitly via memcpy() or
the like:

int *p, *t;
p = malloc(5 * sizeof *p);

t = malloc(3 * sizeof *t);
memcpy(t, p, 3 * sizeof *t); /* copy last 3 ints into t */
free(p); /* avoid a memory leak */
p = t;


Note that in all the examples above, I left out the proper
error checking. After each call to malloc or calloc, remember
to check the returned pointer for NULL:

int *p;

p = malloc(n * sizeof *p);
if (p == NULL)
printf("Whoops! Out of memory!\n");
else
(...)
free(p);

And remember that if realloc() returns NULL, the original block
of memory is *still* *allocated* -- so use a temporary variable!

int *p, *t;

p = malloc(n * sizeof *p);
if (p != NULL) {
t = realloc(p, k * sizeof *p);
if (t != NULL)
p = t;
else
printf("No memory for realloc, but p is still valid!\n");
}
free(p);


HTH,
-Arthur
 
I

Irrwahn Grausewitz

(e-mail address removed) (binaya) wrote:

Others have already responded; however, one note:
Say I allocate 5 pointers to int as below.

You don't.
link=(int*)malloc(5*sizeof(int))

You allocate memory to hold five ints.

Consider:

/* allocate memory for five ints: */
int *foo;
foo = malloc( 5 * sizeof *foo );

/* allocate memory for five pointers to int: */
int **bar;
bar = malloc( 5 * sizeof *bar );

Regards
 
M

Martin Ambuhl

binaya said:
Dear all,

Say I allocate a block of memory using the command malloc.I
have a question. Can I deallocate certain portion of it only during
runtime ?

If you allocate a block of memory using the function [not 'command']
malloc, you can resize the allocation with the function realloc.
Deallocation (for which the function free is used) of part of it is not
possible.
For eg:

Say I allocate 5 pointers to int as below.

link=(int*)malloc(5*sizeof(int))

It is better to use a form like
link = malloc(5 * sizeof *link);
The cast is useless and can mask errors and the sizeof(int) can bite you
should the type of link change. In fact, it has already bitten you, since
you claim that you are allocating 5 pointers to int, while your form
allocates a space for 5 ints and stores 1 pointer to it in link.

It would be better, of course, to find a way to turn the literal 5 into a
symbolic value.

But during runtime, I find that I only need the front 3 of them.ie
I only need link,link+1 and link+2.

recapitulation: Then reallocate with realloc.
If I don't need link+3 and link+4, can I free these last two
pointers to int using the command free(link+3) ?

recapitulation: No. Reallocate with realloc.
If not, then what is the best way to do so ?

recapitulation: Reallocate with realloc.
 
P

pete

binaya said:
Dear all,

Say I allocate a block of memory using the command malloc.I
have a question. Can I deallocate certain portion of it only during
runtime ?

For eg:

Say I allocate 5 pointers to int
But during runtime, I find that I only need the front 3 of them.

/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>

/**
#define OPTIONAL
/*/
#undef OPTIONAL
/**/

#define TOTAL 5
#define FIRST 3
#define str(s) # s
#define xstr(s) str(s)

int main(void)
{
int **pointer, **temp_pointer;
size_t index, size;

size = TOTAL;
do {
pointer = malloc(size * sizeof *pointer);
} while (!pointer && --size != 0);
if (!pointer) {
fputs("This isn't going to work\n", stderr);
exit(EXIT_FAILURE);
}
putchar('\n');
for (index = 0; size > index; ++index) {
pointer[index] = malloc(sizeof *pointer[index]);
if (!pointer[index]) {
printf("\nmalloc(sizeof *pointer[index]) "
"failed allocation attempt %d\n\n", index + 1);
while (size > ++index) {
pointer[index] = 0;
}
break;
} else {
*pointer[index] = index;
}
}
for (index = 0; size > index; ++index) {
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
}

#ifdef OPTIONAL
putchar('\n');
index = size;
while(index-- > FIRST) {
free(pointer[index]);
pointer[index] = 0;
}
for (index = 0; TOTAL > index; ++index) {
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
}
#endif

temp_pointer = pointer;
pointer = realloc(pointer, FIRST * sizeof *pointer);
if (pointer) {
printf("\npointer was reallocated from %d"
" elements, to " xstr(FIRST) " elements.\n", size);
index = FIRST;
while(index--) {
free(pointer[index]);
}
} else {
pointer = temp_pointer;
index = TOTAL;
while(index--) {
free(pointer[index]);
}
}
free(pointer);
return 0;
}

/* END new.c */
 
P

pete

pete said:
/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>

/**
/**/

#define OPTIONAL
/*/
#undef OPTIONAL
/**/
#ifdef OPTIONAL
putchar('\n');
index = size;
while(index-- > FIRST) {
free(pointer[index]);
pointer[index] = 0;
}
for (index = 0; TOTAL > index; ++index) {
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
}
#endif

Upon further consideration,
the OPTIONAL part, is really mandatory.
Whatever you allocate, you should free.
 
P

pete

pete wrote:
Upon further consideration,
the OPTIONAL part, is really mandatory.
Whatever you allocate, you should free.

/* BEGIN allocation.c */

#include <stdio.h>
#include <stdlib.h>

#define TOTAL 5
#define FIRST 3
#define str(s) # s
#define xstr(s) str(s)

int main(void)
{
int **pointer, **temp_pointer;
size_t index, size;

size = TOTAL;
do {
pointer = malloc(size * sizeof *pointer);
} while (!pointer && --size != 0);
if (!pointer) {
fputs("This isn't going to work\n", stderr);
exit(EXIT_FAILURE);
}
putchar('\n');
for (index = 0; size > index; ++index) {
pointer[index] = malloc(sizeof *pointer[index]);
if (!pointer[index]) {
printf("\nmalloc(sizeof *pointer[index]) "
"failed allocation attempt %d\n\n", index + 1);
while (size > ++index) {
pointer[index] = 0;
}
break;
} else {
*pointer[index] = index;
}
}
for (index = 0; size > index; ++index) {
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
}
putchar('\n');
index = size;
while(index-- > FIRST) {
free(pointer[index]);
pointer[index] = 0;
}
for (index = 0; size > index; ++index) {
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
}
temp_pointer = pointer;
pointer = realloc(pointer, FIRST * sizeof *pointer);
if (pointer) {
printf("\npointer was reallocated from %d"
" elements, to " xstr(FIRST) " elements.\n", size);
index = FIRST;
while(index--) {
free(pointer[index]);
}
} else {
pointer = temp_pointer;
index = size;
while(index--) {
free(pointer[index]);
}
}
free(pointer);
return 0;
}

/* END allocation.c */
 
P

pete

pete wrote:
int main(void)
{
int **pointer, **temp_pointer;
size_t index, size;

It's full of bugs.
The simplest way to fix the printf calls,
is to declare index and size as type int:

int **pointer, **temp_pointer, size_t index, size;
printf("\nmalloc(sizeof *pointer[index]) "
"failed allocation attempt %d\n\n", index + 1);
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
}
if (pointer[index]) {
printf("*pointer[%d] is %d\n", index, *pointer[index]);
} else {
printf(" pointer[%d] is NULL\n", index);
}
if (pointer) {
printf("\npointer was reallocated from %d"
" elements, to " xstr(FIRST) " elements.\n", size);
index = FIRST;
while(index--) {
free(pointer[index]);
}
 
J

James Hu

But you can only shrink it from the front.

I initially thought about mentioning something about this, but I thought
that any such sentence can be misinterpreted, and figured the intention
of realloc() would be clear to the OP once he/she read the appropriate
documentation about realloc(). Just looking at the sentence above, it
is not clear what the sentence means.

The information in your post is good, but presented a little strangely.
I think it is much better to just cut to the chase:

The the first argument to realloc must be a value returned from a
previous call to malloc(), calloc(), or realloc(), and must not yet
have been freed by a call to free() or realloc(). If the first
argument is NULL, it behaves like malloc(). realloc() may return NULL,
which means the reallocation did not succeed, but the contents of the
passed in pointer are unchanged.

But all the above should have been found in the OP's C language
reference or compiler documentation.

If I had more time when I initially responded to the poster, I would
have provided a wrapper function. I have the time now, so:

static void * shrink_x(void *p, size_t sz, size_t offset, size_t len);

/*
* Deallocate the specified range from an allocated object.
*
* p - the allocated object
* sz - size of the allocated object
* offset - the starting point of the deallocation
* len - the number of bytes to deallocate
*
* Returns 0 if the deallocation fails, otherwise returns a pointer
* to the shrunken object.
*/
void *
shrink(void *p, size_t sz, size_t offset, size_t len)
{
if (p == 0) {
return realloc(p, (offset+len > sz ? offset+len : sz));
}
if (offset+len > sz) {
return 0;
}
if (offset+len == sz) {
return realloc(p, offset);
}
return shrink_x(p, sz, offset, len);
}

static void *
shrink_x(void *p, size_t sz, size_t offset, size_t len)
{
char buf[len];
char *q = p;
void *t;
memcpy(buf, q+offset, len);
memmove(q+offset, q+offset+len, sz-offset-len);
t = realloc(p, sz-len);
if (t == 0) {
memmove(q+offset+len, q+offset, sz-offset-len);
memcpy(q+offset, buf, len);
}
return t;
}

I'll leave it as an exercise to the reader to find a way to do the
memory copies without using an extra array.

-- James
 

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

Members online

No members online now.

Forum statistics

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

Latest Threads

Top