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