best way to return (char *)

T. William Wells bill at twwells.com
Fri Jun 23 22:41:49 AEST 1989


In article <2793 at solo8.cs.vu.nl> maart at cs.vu.nl (Maarten Litmaath) writes:
: joe at gistdev.UUCP writes:
: \...  Suppose I am writing a function that is
: \going to construct a character string, and is going to return a pointer to
: \that string.  What is the best way to do this so that your pointer is sure
: \to be valid when used?  I have seen several approaches to this problem:
: \
: \    .        Have the caller pass a (char *) and let the caller worry about
: \     allocating whatever space is needed.
:
: That's the way, I tell thee! But who am I, since this macro business?
:
: \    .        Have the routine malloc() space, and let the caller free() it when
: \     done with the returned pointer.
:
: In general you want to deal with the memory all on the same level.
: It simplifies administration.

No. In this kind of thing, it makes life much more complex. The
fundamental problem is this: if the caller makes the allocation
decisions, the caller may well be wrong. That involves complex error
recovery, or it is equivalent to fixed buffer sizes (as far as the
called routine is concerned).

The caller can not do the allocation, not if you want good code; the
called function must do the allocation. Let's consider what this
means. A not atypical function might be one that reads a string from
a file and returns the string in a buffer.

The simple method looks like this:

char *                          /* it gets allocated by mygets */
mygets(stream)
FILE    *stream;
{
}

	ptr = mygets(stdin);
	...
	free(ptr);

But this has several drawbacks: one is that the caller may well fail
to free the pointer, causing allocated memory to grow overmuch, and
there is the excessive number of malloc and free calls it requires,
another is that the caller can't do things like extend the string
without always doing yet another malloc, even though mygets may well
have allocated more space than needed.

A better method would be something like:

typedef struct XSTRING {
	char    *_xs_string;    /* pointer to the string */
	size_t  _xs_length;     /* bytes in the string */
	size_t  _xs_alloc;      /* allocate length, may be > _xs_length */
	int     _xs_ahint;      /* suggests method of extending the string */
} XSTRING;

(Why the underscores? So that macros like xs_string can be written to
access the structure members.)

int                             /* error result */
xs_gets(stream, xstring)
FILE    *stream;
XSTRING *xstring;

The caller would create an XSTRING by calling an xs_new function and
do all his string work with it. Repeated calls to xs_gets can use the
same XSTRING; there is no requirement to free the string after each
use. When one is done, one would call a dispose function for the
XSTRING; it would be responsible for getting rid of the XSTRING and
the associated string.

To make this really valuable, one should also have xs_* functions to
provide the functionality of the other functions in the C library
which return variable length strings.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill at twwells.com



More information about the Comp.lang.c mailing list