return of pointer

  • Thread starter Sergey Koveshnikov
  • Start date
S

Sergey Koveshnikov

Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

Thanks a lot!
 
A

Andreas Kahari

Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,

Maybe not, but as long as you are consistent and document the
interface it works well.
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

You can't force someone to remember to call free().

Creating a foo_alloc() and a foo_free() function might help
though (untested):

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

int foo_alloc(char **p)
{
/* sanity checks of *p here */

*p = malloc(10);
if (*p == NULL) return 1;
strcpy(*p, "something");
return 0;
}

int foo_free(char **p)
{
/* sanity checks of *p here */

free(*p);
*p = NULL;

return 0;
}

void bar()
{
char *p;

foo_alloc(&p);
printf("foo: %s\n", p);

foo_free(&p);
}
 
S

Sergey Koveshnikov

i.e. No way to do automatic cleanup dynamic allocated memory, if it's
unnecessary anywhere, except context of 'bar()', isn't it?
 
A

Andreas Kahari

i.e. No way to do automatic cleanup dynamic allocated memory, if it's
unnecessary anywhere, except context of 'bar()', isn't it?

There is no built-in garbage collector in C, no.
 
S

Sergey Koveshnikov

But, what can I do if some foreign code expect from my function that it will
return char*, and it doesn't call free()? Do you know any 'save string'
library for ANSI C that provide self-destroyed strings?
May be it's possible to solve this problem with macros or 'static' type?

PS. Sorry if my questions are stupid, I'm new in the C.
 
I

Irrwahn Grausewitz

Sergey Koveshnikov said:
Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

Maybe it's a good idea to adopt the bevaviour of, for example, the
standard library string functions, and let the caller take the full
responsibility for memory allocation/deallocation. E.g.:

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

#define BIG_ENOUGH 50

char *foo( char *p )
{
if ( p != NULL )
strcpy( p, "something" );
return( p );
}

int main( void )
{
char *p = malloc( BIG_ENOUGH );
if ( foo( p ) != NULL )
printf( "%s\n", p );
free( p );
return 0;
}

Note: you may want foo() to take an additional argument specifying the
buffer size, in order to avoid buffer overflows.

OTOH, if you, for example, want to imitate the non-standard strdup
function, you of course have to allocate the memory inside the function,
document the behaviour and hopefully the user of the function will get
it right.

HTH
Regards
 
A

Andreas Kahari

But, what can I do if some foreign code expect from my function that it will
return char*, and it doesn't call free()? Do you know any 'save string'
library for ANSI C that provide self-destroyed strings?
May be it's possible to solve this problem with macros or 'static' type?

PS. Sorry if my questions are stupid, I'm new in the C.

You, as a library implementor, are not required to make sure
that the users of the library writes correct code.

Document the correct usage (whether to explicitly free() storage
or to call a special cleanup function), and that's the end of
your troubles.

It is possible to return a pointer to a static array, but you
will have to make sure that you point this out to the library
user as well, so that he/she doesn't wander off and tries to
free() that pointer, or so that he/she doesn't store its value
somewhere and gets confused when the data it points to suddenly
changes after the next call to your function.

My favourite solution is to provide two functions; one for
allocation and one for deallocation. This is a bit too involved
if it's just a question of a simple string and not a struct or
some opaque data type.
 
D

Dan Pop

In said:
Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

This is a perfectly valid approach. No matter where the memory is
dynamically allocated, someone may forget to release it. This is an
intrinsic issue with dynamically allocated memory.

The alternative is to pass to foo the address of the buffer. If the
buffer was not dynamically allocated, no need to release it:

#define STRING "something"

void foo(char *p)
{
strcpy(p, STRING);
}

void bar()
{
char p[sizeof STRING];
foo(p);
printf("%s\n", p);
}

Of course, this doesn't work if only the called function can evaluate
the size of the buffer.

Dan
 
M

Morris Dovey

Sergey said:
Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

Thanks a lot!

Sergey...

You may be able to write a wrapper for malloc() that keeps a list
of all allocations it makes, then write a function to call free()
for each of the allocations in that list. Refine as necessary.
 
J

James Hu

Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

Thanks a lot!

You can design a callback interface to someone that wants the
memory:

void foo(void (*cb)(char *))
{
char *p = malloc(10);
if (p)
strcpy(p, "something");
cb(p);
free(p);
}

void mycallback(char *p)
{
printf("%s", p);
}

void bar(char *p)
{
foo(mycallback);
}

-- James
 
D

Dan Pop

In said:
But, what can I do if some foreign code expect from my function that it will
return char*, and it doesn't call free()?

You only need to worry about the correctness of the code you write
yourself. No matter what you do or don't, someone may use your code
incorrectly. It's his problem, not yours. That is, assuming that you
have properly documented the correct usage of your code.
Do you know any 'save string'
library for ANSI C that provide self-destroyed strings?

There is no way to write such a library in C.
May be it's possible to solve this problem with macros or 'static' type?

The only way to solve this problem is by using automatic allocation in
the function that is calling your function and passing the address (and,
possibly, the size of the allocated block) to your function. The string
will self-destroy when the function that allocated it returns.

The other "solution", return the address of a statically allocated buffer
inside your function, which is reused at each invocation of your
function, has its own big caveat: if the caller forgets to make a local
copy of the buffer before calling the function again, he ends up with a
hard to find bug. Typical example: imagine that your function returns
a random string each time it's called, in a statically allocated buffer.
What happens to the following printf call:

char *randstr(void)
{
static char alnum[] = "0123456789abcdefghijklmnopqrstuvwxyz";
static char str[10];
int i;

for (i = 0; i < sizeof str - 1; i++)
str = alnum[rand() % strlen(alnum)];
return str;
}
....
printf("%s %s\n", randstr(), randstr());

Dan
 
A

Arthur J. O'Dwyer

If my function return a pointer on a memory area, where do I free it? [snip]
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget
to call free()?

You can design a callback interface to someone that wants the
memory:

[snip code example]
void bar(char *p)

ITYM void bar(void) here.
{
foo(mycallback);
}


Wow -- I'd never seen that approach before! It's... interesting,
but I can't really see myself ever using it. :)
[Just in case the OP didn't get it the first time around: here,
'bar' is the "main" function of the program, and 'foo' is the
function that encapsulates everything to do with a single dynamic
object. 'mycallback'/'cb' is a pointer to a function that says,
"After creating the object, do this and this and this; once that's
done, it's safe to free the object again."]
So to use my favorite example, we could take an image format
converter that looked like this [NOT REAL CODE]:

struct Im
{
unsigned char *data;
int w, h;
};

int main(int argc, char **argv)
{
struct Im *image;
ReadPGM(argv[1], &image);
WritePPM(argv[2], image);
free(image->data);
free(image);
return 0;
}

void ReadPGM(const char *fname, struct Im *im)
{
/* something like... */
im = malloc(sizeof *im);
im->w = im->h = 42;
im->data = malloc(im->w * im->h);
}


and transform it into this:

static const char *OutFileName = NULL;

int main(int argc, char **argv)
{
OutFileName = argv[2];
ProcessPGM(argv[1], write_it_out);
return 0;
}

void write_it_out(struct Im *im)
{
WritePPM(OutFileName, im);
}

void ProcessPGM(const char *fname, void (*cb)(struct Im *))
{
struct Im *image;
ReadPGM(argv[1], &image);
cb(image);
free(image->data);
free(image);
}


Uglier in this case, but possibly this could save a few
keystrokes and possible memory leaks down the road. :)

HTH,
-Arthur
 
J

James Hu

Arthur J. O'Dwyer said:
ITYM void bar(void) here.

Yes, thanks.
Wow -- I'd never seen that approach before! It's... interesting,
but I can't really see myself ever using it. :)

The original poster just asked if there was a solution that didn't
require the user of the interface to call free to reap the memory.
I just wanted to demonstrate that there was one that did not require
a garbage collection facility.

-- James
 
J

Joe Wright

Morris said:
Sergey said:
Hello, [ lots of snips ]
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

Thanks a lot!

Sergey...

You may be able to write a wrapper for malloc() that keeps a list
of all allocations it makes, then write a function to call free()
for each of the allocations in that list. Refine as necessary.
Morris,

I have done just that. I have a 'library' called GE for Garbage
Eliminator. With a little preprocessor magic it traps the *alloc() calls
and free(). GE manages a list of structures which hold the pointers to
allocated memory and the size of the allocation. A library function
'size_t size(void *p)' will look up p in the list and return its
allocated size (or 0 if p is not found). free(void *p) is trapped and
and looks up p and frees it and its entry in the list if found,
otherwise does nothing. A library function freeall() will free all
allocations including the list itself.
 
M

Morris Dovey

Joe said:
I have done just that. I have a 'library' called GE for
Garbage Eliminator. With a little preprocessor magic it traps
the *alloc() calls and free(). GE manages a list of structures
which hold the pointers to allocated memory and the size of
the allocation. A library function 'size_t size(void *p)' will
look up p in the list and return its allocated size (or 0 if p
is not found). free(void *p) is trapped and and looks up p and
frees it and its entry in the list if found, otherwise does
nothing. A library function freeall() will free all
allocations including the list itself.

Joe...

Damn I'm good! ( Too bad you beat me to it. :cool:

I particularly like your size() function. 'Xcuse me while I go
plagerize^H^H^H^H^H^H^H^H^H(ahem) make some notes...
 
G

Glen Herrmannsfeldt

Dan Pop said:
In <[email protected]> Sergey Koveshnikov

You only need to worry about the correctness of the code you write
yourself. No matter what you do or don't, someone may use your code
incorrectly. It's his problem, not yours. That is, assuming that you
have properly documented the correct usage of your code.
(snip)

The other "solution", return the address of a statically allocated buffer
inside your function, which is reused at each invocation of your
function, has its own big caveat: if the caller forgets to make a local
copy of the buffer before calling the function again, he ends up with a
hard to find bug. Typical example: imagine that your function returns
a random string each time it's called, in a statically allocated buffer.

(snip)

Or consider the ctime() C library function and a program to print the
creation, modification, and last access time for a file.

printf("%s %s %s\n",ctime(created),ctime(modified),ctime(accessed));

(yes, it actually happened to me. It didn't take long to figure it out, but
it did happen.)

-- glen
 
C

CBFalconer

Morris said:
Damn I'm good! ( Too bad you beat me to it. :cool:

I particularly like your size() function. 'Xcuse me while I go
plagerize^H^H^H^H^H^H^H^H^H(ahem) make some notes...

ALL those features are available in nmalloc.zip, available at:

<http://cbfalconer.home.att.net/download/>

which was written for the DJGPP system, and should work on any
system whose fundamental allocation scheme depends on sbrk and
deals with 8 bit bytes. The extension function memalign() is not
ready. An equivalent to the size function you mention is
trivially implemented, and could be added to the malldbg module.

The code is very close to standard C, with the principal deviation
being the use of GCC varargs macros for debugging purposes.
Because of the form of call these don't simply define away. Those
macros also use non-standard write calls, the purpose being to
allow them to function during initialization, at least under
DJGPP.
 
K

Keith Thompson

Glen Herrmannsfeldt said:
(snip)

Or consider the ctime() C library function and a program to print the
creation, modification, and last access time for a file.

printf("%s %s %s\n",ctime(created),ctime(modified),ctime(accessed));

(yes, it actually happened to me. It didn't take long to figure it out, but
it did happen.)

Another solution I've used in the past is to declare a static array of
objects of the result type, and rotate among the elements for each
call. For example:

#include <stdio.h>

char *twice(char *s)
{
#define RESULT_COUNT 6
static char result[RESULT_COUNT][100];
static int index = -1;

index ++;
if (index >= RESULT_COUNT) index = 0;

strcpy(result[index], s);
strcat(result[index], s);
return result[index];
}

int main(void)
{
printf("twice(\"foo\") = \"%s\", twice(\"bar\") = \"%s\"\n",
twice("foo"), twice("bar"));
return 0;
}

This lets me have up to RESULT_COUNT active calls to the function
without collisions, while not requiring the caller to allocate or
deallocate the result. It's not particularly pretty, and it can run
into problems if the caller saves a pointer to the result, but I found
it useful.

Probably the worst feature of this approach is that any problems are
likely to be rare, showing up only in unusual circumstances. It
handles the easy cases and doesn't do much for the really hard ones.
It also introduces the temptation of kludging around any problems by
increasing RESULT_COUNT.
 
M

Morris Dovey

CBFalconer said:
ALL those features are available in nmalloc.zip, available at:

<http://cbfalconer.home.att.net/download/>

which was written for the DJGPP system, and should work on any
system whose fundamental allocation scheme depends on sbrk and
deals with 8 bit bytes. The extension function memalign() is not
ready. An equivalent to the size function you mention is
trivially implemented, and could be added to the malldbg module.

The code is very close to standard C, with the principal deviation
being the use of GCC varargs macros for debugging purposes.
Because of the form of call these don't simply define away. Those
macros also use non-standard write calls, the purpose being to
allow them to function during initialization, at least under
DJGPP.

Sorry. I knew you had a pile of memory management functions on
the web - I just forgot.

Sergey, browse Chuck's site - he writes pretty good stuff...
 
G

goose

In said:
Hello,
If my function return a pointer on a memory area, where do I free it?
e.x.:
char *foo()
{
char *p;
p = malloc(10);
strcpy(p, "something");
return(p);
}
void bar()
{
char *p = foo();
printf("%s", p);
free(p);
}
But force anybody to calling free() after use foo() not elegant solution,
for my mind... How can I avoid posible memory leaks if somebody forget to
call free()?

This is a perfectly valid approach. No matter where the memory is
dynamically allocated, someone may forget to release it. This is an
intrinsic issue with dynamically allocated memory.

The alternative is to pass to foo the address of the buffer. If the
buffer was not dynamically allocated, no need to release it:

#define STRING "something"

void foo(char *p)
{
strcpy(p, STRING);
}

void bar()
{
char p[sizeof STRING];
foo(p);
printf("%s\n", p);
}

Of course, this doesn't work if only the called function can evaluate
the size of the buffer.

an alternative is to have the called function be able to
return the size of the buffer needed.

#define STRING "something"

size_t foo (char *p, size_t size) {
size_t needed_size = strlen (STRING) +1;
if (p==NULL || size < needed_size) {
return needed_size;
}
strcpy (p, STRING);
return 0;
}

void bar ()
char *the_string = NULL;
size_t size_of_the_string = 0;

/* get the amount of memory needed */
size_of_the_string = foo (NULL, 0);

the_string = malloc (size_of_the_string);
if (!the_string) {
/* report error!!! */
} else {
foo (the_string, size_of_the_string);
}
}


goose,
criticise away :)
 

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,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top