return a string

T

Tim Rentsch

Keith Thompson said:
I've used a variant of this. I had a function returning char* that
declared two local static variables, an array of arrays of char (for
the results), and an index. On each call, it would cycle the index
through the array and use a fresh sub-array for the result. This
allowed, say, half a dozen distinct calls to be active simultaneously.
It's not pretty, and it still forces you to decide in advance both how
big the result can be and how many distinct results you need, but it's
a bit more flexible than using a single static array.

A single function can do this for lots of other functions:

const char *
semi_permanent_copy( const char * s ){
static char buffer[ SOME_SIZE ];
static size_t next = 0;
size_t needed;

if( s == NULL ) return NULL; /* a plausible choice */

if( (needed = strlen(s) + 1) > SOME_SIZE ) die( "no space" );

if( needed > SOME_SIZE - next ) next = 0;

next += needed;
memcpy( & buffer[ next - needed ], s, needed );
return & buffer[ next - needed ];
}

Client functions would have their own local (auto) buffers, and use

return semi_permanent_copy( local_buffer );

to return "semi-permanent" results.

Allocating out of a single buffer means there can be more strings if
they are shorter, or longer strings if there aren't as many. Also,
with all the clients sharing a single buffer, it's easier to feel good
about having a generously sized buffer, which will reduce the chance
of exceeding a fixed limit.

The return type being 'const' helps make sure strings in the buffer
aren't mistakenly overwritten, and increases the likelihood that the
results won't be held on to for too long. If a non-const version is
desired, just wrap one function around another:

char *
semi_permanent_writeable_copy( const char *s ){
... as above ...
}

const char *
semi_permanent_copy( const char *s ){
return semi_permanent_writeable_copy( s );
}

Following what I think is good practice, the safer version has the
shorter, easier name. Strictly speaking, the second function here
isn't necessary, because return results that are 'const' will
automatically convert if the writeable version is used. But having
the safer 'const' version be the default increases the chance that
clients will make conscious and considered decisions and use the
writeable version only where really necessary.

Disclaimer: I've used code much like this, but what's here is just
typed in, not compiled or tested.
 
M

Michael Wojcik

Actually, it seems to me that #2 is the most flexible technique. It
allows the function itself to determine exactly how much memory it
needs, and imposes minimal complexity on the call (apart from the need
to free the allocated memory).

I can think of at least one case where #3 provides added flexibility:
when you want the output inserted into the middle of an already-
allocated buffer. Then you can pass a pointer to that offset and the
length of the remaining area in the buffer, and avoid the allocation
and copying required with #2.

Obviously this is just another case where the optimal method depends
on the application, as I believe we all agree.

--
Michael Wojcik (e-mail address removed)

Art is our chief means of breaking bread with the dead ... but the social
and political history of Europe would be exactly the same if Dante and
Shakespeare and Mozart had never lived. -- W. H. Auden
 
D

Daniel Haude

On Mon, 02 May 2005 18:45:30 GMT,
in Msg. said:
Why does tucking it away in some library imply that you need to
support an alternative allocation function? There may be (or may not)
an issue for functions that are part of the standard library <OT>and
kernel code may not be able to use malloc()</OT>, but in most cases
there's no reason a library function can't use malloc().

There's nothing wrong with it unless you use some malloc() wrapper for
debugging purposes which would result in a mixture of buffers created
by the "native" malloc (as returned by our library) and those created by
the debugging wrapper. Of course if this is an issue, nothing keeps us
from adding a malloc/free registering function to the library for those
that want it. IIRC libcurl has such a feature.

--Daniel
 
D

Dave Thompson

On Sat, 30 Apr 2005 08:27:42 +0200, "Emmanuel Delahaye"

(To the gurus : [C99] shouldn't the 'restrict' keyword used here by the
compiler to generate some warning ?)

The standard does not _require_ a diagnostic for 'restrict' parameters
(or pointers generally) that improperly overlap. It does provide
information that a compiler could use in at least some simple cases
like this one to provide such a diagnostic as a good-QoI matter.

However there are many (important) cases where no compiler could
detect the error at compile time (and the "spirit" of C is not to
impose the cost of doing so at run time) so there is the risk, as with
other 'easy case' warnings, that programmers get 'lazy' and come to
expect and rely on the compiler to detect certain problems.

- David.Thompson1 at worldnet.att.net
 

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
474,164
Messages
2,570,901
Members
47,439
Latest member
elif2sghost

Latest Threads

Top