[comp.lang.c] Functions using malloc

sslee@polyslo.CalPoly.EDU (Steven Lee) (06/23/91)

When you write a C function and it returns a pointer to some
structure, how should the function do this?  Many of the system
functions I know create a static area that gets rewritten when
the user makes multiple calls to it.  This avoids the problem
of allocating memory each time the function is called.

The possible solutions I have come up with are:
1. Force the user to malloc his own space and then call the function.
   I personally don't like this idea because the user should not have
   to worry about this. (User is defined to be the programmer using
   the particular function.)
2. The function mallocs space each time it is called.  It is up to
   the user to free (release) the memory.
3. Use the static technique as described above, however it will not
   work if a VARIABLE structure (one you don't know the size of)
   needs to be returned (ie say you need to return a pointer to a
   string but you don't know how long the string may be).
   a. Malloc a large enough memory so the structure is bound to fit.
      This would waste a lot of memory and it still may crash for
      unusual situations, so I don't like this idea.
   b. This is the best solution I have so far for a variable structure
      that needs to be returned.  Create a static pointer and initially
      set it to NULL.  Upon calling this function, it checks to see
      if the pointer is NULL.  If it isn't, it first deallocates
      the memory and then reallocates the amount needed.  This avoids
      malloc'ing memory and never returning it back upon multiple calls.


What I need to do is read the /etc/passwd file using the getpwent()
function.  I want to store all the information in a structure and return
a pointer back to the callee.  However, I don't want this structure
in memory more than once if it is called multiple times.

Steven Lee

barmar@think.com (Barry Margolin) (06/23/91)

In article <2864543c.3e48@polyslo.CalPoly.EDU> sslee@polyslo.CalPoly.EDU (Steven Lee) writes:
>When you write a C function and it returns a pointer to some
>structure, how should the function do this?
...
>The possible solutions I have come up with are:
>   b. This is the best solution I have so far for a variable structure
>      that needs to be returned.  Create a static pointer and initially
>      set it to NULL.  Upon calling this function, it checks to see
>      if the pointer is NULL.  If it isn't, it first deallocates
>      the memory and then reallocates the amount needed.  This avoids
>      malloc'ing memory and never returning it back upon multiple calls.

2c. Use a static pointer, as in 2b above.  Also create a static size_t
variable that contains the current allocation size of the structure.  Only
reallocate if the amount you need is larger than the current size.

Actually, if you just use realloc() rather than free()/malloc(), a
well-implemented memory manager should do this automatically.

3. Allow the caller optionally to provide his own pointer.  Accept a
pointer input argument; if it's null, the function allocates the structure
itself and returns the pointer to it.  In either case, it's the caller's
responsibility to free it.
-- 
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

greywolf@unisoft.UUCP (The Grey Wolf) (06/28/91)

/* <2864543c.3e48@polyslo.CalPoly.EDU> by sslee@polyslo.CalPoly.EDU (Steven Lee)
 * 
 * When you write a C function and it returns a pointer to some
 * structure, how should the function do this?  Many of the system
 * functions I know create a static area that gets rewritten when
 * the user makes multiple calls to it.  This avoids the problem
 * of allocating memory each time the function is called.
 *

I usually use #1 below, as I think that if the user requires some
information, (s)he should have a place to put it.

 * The possible solutions I have come up with are:
 * 1. Force the user to malloc his own space and then call the function.
 *    I personally don't like this idea because the user should not have
 *    to worry about this. (User is defined to be the programmer using
 *    the particular function.)

see above.

 * 2. The function mallocs space each time it is called.  It is up to
 *    the user to free (release) the memory.

This is a drag -- you might as well use #1.

 * What I need to do is read the /etc/passwd file using the getpwent()
 * function.  I want to store all the information in a structure and return
 * a pointer back to the callee.  However, I don't want this structure
 * in memory more than once if it is called multiple times.
 *

Are you trying to read the ENTIRE passwd file into a structure using
getpwent(), or are you just going through, entry by entry?

If you're just going through, entry by entry, you can save your breath.
getpwent() returns a static pointer (one whose location never changes);
the manual page even advocates that if you want to save the data you need
to copy it to someplace else, as the next call to getpwent() will overwrite
the data it just got.

If you're trying to read the ENTIRE passwd file into a structure,
save yourself some crazy work and allocate an array of struct passwds.

 * Steven Lee


-- 
# "Religion is a weapon invented by the sheep to keep the wolves in line."
# greywolf@unisoft.com

rh@smds.UUCP (Richard Harter) (06/29/91)

Steven Lee writes:

>   When you write a C function and it returns a pointer to some
>   structure, how should the function do this?  Many of the system
>   functions I know create a static area that gets rewritten when
>   the user makes multiple calls to it.  This avoids the problem
>   of allocating memory each time the function is called.

>   The possible solutions I have come up with are:
>   1. Force the user to malloc his own space and then call the function.

>   2. The function mallocs space each time it is called.  It is up to
>      the user to free (release) the memory.

These two choices reflect different modes of usage by the user.  Thus
(1) takes the view that the lifetime of the object specified by
the pointer is at most from one call to the function to the next.
On the other hand (2) essentially says that the user dictates the
lifetime of the object and is therefore responsible for its disposition.

Either view may be appropriate, depending on usage.  The problem is that
the function writer does not necessarily know what the users needs are.

For a bit of extra work you can accomodate both sets of needs.  Make a
package out of it.  The package has three entry points (public methods),
a get_instance, a reserve, and a release.  The get_instance returns a
pointer which is guaranteed until the next call.  The reserve makes the
object pointed to persistent until it is released.

Internally the package maintains a list of objects under management with
a private list of structures which track the objects.  For example
suppose the returned structure type is FOOBY.  The internal structure
looks like

	struct manager {
		struct manager *link;
		struct OBJECT *ptr;
		};

with private data 

	static struct manager *in_use = 0;
	static struct OBJECT *current = 0;

In a simple implementation (i.e. without multiple reserves and reference
counts) a get_instance reuses the current if it exists, otherwise it
mallocs one to create a current.  A reserve mallocs a manager struct,
puts the current in it, adds the manager struct to the in_use list, and
zeroes current.  A release searches the in_use list for the corresponding
manager struct, removes it, and either frees the contained OBJECT if
current is non zero else sets current to point to the contained object.
Finally it frees the manager struct space.

The above implementation requires extra mallocs and frees for reserved
objects.  An obvious modification is to add a current_mgr item which
eliminates the bulk of malloc/free cycles.  An more memory intensive
but more general method is to have a free list for manager structs.

A rather more general approach is to have a generic object manager
which can handle structures generically.  You can either use reference
counts or user reservation or both.  User reservation works like this:
The generic object manager package has an entry point which returns
a "user id".  The reserve function has two arguments, an object pointer
and a "user id".  There is a terminate_user function which releases
all objects reserved by the "user id".  This is a fair bit of work.
The simple implementation, however, is very easy and can be canned into
include file macros.
-- 
Richard Harter, Software Maintenance and Development Systems, Inc.
Net address: jjmhome!smds!rh Phone: 508-369-7398 
US Mail: SMDS Inc., PO Box 555, Concord MA 01742
This sentence no verb.  This sentence short.  This signature done.

john@iastate.edu (John Hascall) (06/30/91)

rh@smds.UUCP (Richard Harter) writes:
}Steven Lee writes:
}>   When you write a C function and it returns a pointer to some
}>   structure, how should the function do this?  Many of the system
}>   functions I know create a static area that gets rewritten when
}>   the user makes multiple calls to it.  This avoids the problem
}>   of allocating memory each time the function is called.

}>   The possible solutions I have come up with are:
}>   1. Force the user to malloc his own space and then call the function.

}>   2. The function mallocs space each time it is called.  It is up to
}>      the user to free (release) the memory.

}Either view may be appropriate, depending on usage.  The problem is that
}the function writer does not necessarily know what the users needs are.
}For a bit of extra work you can accomodate both sets of needs.  Make a
}package out of it.  [...big huge scheme...]

Or, a more modest solution is something like this:

#define ALLOC(type) ((type *)malloc(sizeof(type)))

struct woozy * get_woozy(wp)
	struct woozy *	wp;
{
	if (wp == NULL) {
		/* no woozy from user, get one for them */
		if ((wp == ALLOC(struct woozy)) == NULL) {
			/* can't get woozy:
			    fprintf, exit, return NULL,... as appropriate */
		}
	}
	/* ... etc ... */
	return (wp);
}

Or, possibly:

struct woozy * get_woozy(wp)
	struct woozy *	wp;
{
	static struct woozy	our_woozy;

	if (wp == NULL) {
		/* no woozy from user, use ours */
		wp = &our_woozy;
	}
	/* ... etc ... */
	return (wp);
}

John
-------------------------------------------------------------------------------
John Hascall                        An ill-chosen word is the fool's messenger.
Project Vincent
Iowa State University Computation Center                       john@iastate.edu
Ames, IA  50011                                                  (515) 294-9551