Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ukma!uflorida!novavax!twwells!bill From: bill@twwells.com (T. William Wells) Newsgroups: comp.lang.c Subject: Re: best way to return (char *) Message-ID: <1989Jun23.124149.1374@twwells.com> Date: 23 Jun 89 12:41:49 GMT References: <7800013@gistdev> <2793@solo8.cs.vu.nl> Organization: None, Ft. Lauderdale, FL Lines: 79 In article <2793@solo8.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: : joe@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@twwells.com