Advice on how to return a list of values

R

Remo D.

Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible for
handling the memory. The drawback is that my function will have to rely
on the correctness of such pointer to work properly.

- My function allocates the array and returns it. This is similar to
strdup(). Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended. The good is that I'm free from
allocation/freeing problem. The bad is that the return values will be
overwritten at each call; if the user wants to keep the return values
for subsequent use he has to copy and store them somewhere. Another
drawback is that it consumes memory even if the function will never be
called.

In my specific case, I was leaning toward the third option but I'd like
to hear your opinion on pitfalls, things that I've missed or alternative
approaches that could work better.

Thanks,
Remo.D.
 
I

Ian Collins

Remo said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible for
handling the memory. The drawback is that my function will have to rely
on the correctness of such pointer to work properly.

- My function allocates the array and returns it. This is similar to
strdup(). Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended. The good is that I'm free from
allocation/freeing problem. The bad is that the return values will be
overwritten at each call; if the user wants to keep the return values
for subsequent use he has to copy and store them somewhere. Another
drawback is that it consumes memory even if the function will never be
called.

In my specific case, I was leaning toward the third option but I'd like
to hear your opinion on pitfalls, things that I've missed or alternative
approaches that could work better.
The first would be my choice.

There are standard C (time functions for example) and many POISX
networking functions return a pointer to shared internal data. The
biggest drawback with this is it can cause chaos in threaded
applications. So they (POSIX) also provide another version which accept
the data to be written as a parameter.
 
R

Remo D.

Ian Collins ha scritto:
Remo said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. [...]

- My function allocates the array and returns it. [...]

- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended. [...]
The first would be my choice.

There are standard C (time functions for example) and many POISX
networking functions return a pointer to shared internal data. The
biggest drawback with this is it can cause chaos in threaded
applications. [...]


Thanks Ian, that's a very good reason not to go with the third option: I
don't know if my function will be used in a threaded application!

I'll go with the first one.

Thanks again,
Remo.D.
 
K

Keith Thompson

Remo D. said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible
for handling the memory. The drawback is that my function will have to
rely on the correctness of such pointer to work properly.

That's probably ok if you clearly document the requirement for the
caller.
- My function allocates the array and returns it. This is similar to
strdup(). Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

Again, document the requirement. It does make your function a little
harder to use, but not impossibly so.
- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves
this way, so I guess it's not reccomended. The good is that I'm free
from allocation/freeing problem. The bad is that the return values
will be overwritten at each call; if the user wants to keep the return
values for subsequent use he has to copy and store them somewhere.
Another drawback is that it consumes memory even if the function will
never be called.

Several functions in the standard library return pointers to static
objects: setlocale, localeconv, getenv, strerror, asctime, ctime (I
don't know whether that's a complete list).
In my specific case, I was leaning toward the third option but I'd
like to hear your opinion on pitfalls, things that I've missed or
alternative approaches that could work better.

Since your list is limited to 64 elements, you could return a
structure containing 64 pointers and an integer that specifies how
many of them are valid. Since structures are passed and returned by
value [*], this is simpler, but it could be inefficient both in time
(copying the data rather than passing a pointer to it) and in space
(since you allocate the entire structure even if fewer than 64
elements are valid).

[*] All types are passed and returned by value; the difference is,
unlike for arrays, (a) you can declare a struct parameger, and (b)
there's no implicit conversion to pointer for structs.
 
P

Paul Hsieh

Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char.

What is the lifetime of the pointers? Are they simply already
existing pointers or are they to be created by the function according
to some restrictions?
[...] I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible for
handling the memory. The drawback is that my function will have to rely
on the correctness of such pointer to work properly.

Well you can enforce type safety by passing in a pointer to a
structure of 64 char * pointers. I don't suppose there is a way to
prove that your caller is being correct. In Bstrlib I do it with a
few consistency checks and provide a complete API for managing
bstrings, so there's no reason for the bstring to be corrupted except
by external incidental means. But either way, this way allows you to
amortize your allocation costs by virtue of being intrinsically
hoisted upwards.
- My function allocates the array and returns it. This is similar to
strdup(). Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

This is fine too, except it may introduce performance problems from
allocation if its called very often. You can't reuse an allocation
pool, for example.
- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended.

Are you kidding me? Look through the time functions in C. Its as if
they could find no other way of solving this kind of problem. But of
course, you've just prevented yourself from having even *two* such
live lists in your program (let's not even start with
multithreading). If this is even possible then its hard to justify
even writing a function routine to do this. Why not just inline it
straight into your code?
[...] The good is that I'm free from allocation/freeing problem.

The first solution is a superset of functionality versus this
solution. It can declare (static char *list [64])'s as well. In fact
it might even declare them non-static and make many of them.
[...] The bad is that the return values will be
overwritten at each call; if the user wants to keep the return values
for subsequent use he has to copy and store them somewhere. Another
drawback is that it consumes memory even if the function will never be
called.

In my specific case, I was leaning toward the third option but I'd like
to hear your opinion on pitfalls, things that I've missed or alternative
approaches that could work better.

Well, there is the iterator function solution. I.e.:

enum itstate { LIST_START, LIST_ITERATE, LIST_DONE };
char * getListNext (void * ctxParms, enum itstate *);

You would just call getListNext() over and over to get each list
element one at a time until your itstate is LIST_DONE (or the char *
returned is NULL.) In some cases you can simplify this to just use the
char * in place of an enum itstate. I.e., since you are going to
treat the thing as a list anyways, rather than requiring a specific
separate creation step, you could create it on the first pass. If you
intend to walk it more than once, you can allocate an array to cache
it from the call site.
 
R

Remo D.

Keith Thompson ha scritto:
Remo D. said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:
[...]
In my specific case, I was leaning toward the third option but I'd
like to hear your opinion on pitfalls, things that I've missed or
alternative approaches that could work better.

Since your list is limited to 64 elements, you could return a
structure containing 64 pointers and an integer that specifies how
many of them are valid. Since structures are passed and returned by
value [*], this is simpler, but it could be inefficient both in time
[...] and in space [...]

Thanks for the suggestion Keith. That's surely another option I didn't
consider. Acutally I've never felt comfortable in returning structs and,
as you point out, it seems to imply a level of inefficiency that is not
entirely balanced by the benefits.

I think I'll implement the first option I had and reconsider your
suggestion if I will decide to provide an interface that requires no
pointer passing from the caller to my function.

Remo.
 
R

Remo D.

Paul Hsieh ha scritto:
What is the lifetime of the pointers?
Pointers returned are pre-existing and created outside my function.
[...] I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. [...]

Well you can enforce type safety by passing in a pointer to a
structure of 64 char * pointers. I don't suppose there is a way to
prove that your caller is being correct. [...]
- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended.

Are you kidding me? Look through the time functions in C. Its as if
they could find no other way of solving this kind of problem.
Also Ian and Keith mention library functions that return pointer to
internal static variables. I guess this proves my lack of knowledge of
the library function :).
But of course, you've just prevented yourself from having even
> *two* such live lists in your program (let's not even start with
multithreading).
Yes, this is the major issue, I think. As you suggest later, I'll
implement the first option and reconsider allocating the array
statically (or returning a struct) at a later stage.

[...]
Well, there is the iterator function solution.
I see, but I already know the caller will want use the return array as
an arry (e.g. if (ret[k][0] > ret[j][0]) ) it will be hard to justify
an iterator approach. Thanks for the suggestion anyway.


Remo.D
 
P

pete

Remo said:
Ian Collins ha scritto:
Remo said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. [...]

- My function allocates the array and returns it. [...]

- I'll have a "static char *ret[64]"
in my function and will return
ret. I've not been able to think of a library function
that behaves this
way, so I guess it's not reccomended. [...]
The first would be my choice.

There are standard C (time functions for example) and many POISX
networking functions return a pointer to shared internal data. The
biggest drawback with this is it can cause chaos in threaded
applications. [...]

Thanks Ian, that's a very good reason
not to go with the third option: I
don't know if my function will be used in a threaded application!

I'll go with the first one.

The first one is much more robust than the others.
With the first one,
you can use either automatic, static, or allocated memory
at the discretion of the calling function.
 
B

Bartc

Remo said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible
for handling the memory. The drawback is that my function will have
to rely on the correctness of such pointer to work properly.

Let the caller provide a pointer to an array of 64 *unassigned* and NULL
pointers. Perhaps also a number to indicate how many of the 64 have been
provided, if there could be any doubt. The array could be static or
allocated; it doesn't matter and it's not your problem.

Then allocate each pointer in your code and store in the array. Presumably
the caller doesn't know how long these strings are so could not preallocate
anyway.

The caller would have to free the strings when it's done with it. That
requires no knowledge on behalf of the caller beyond that it has a list of
64 pointers to free. Or provide an extra function (or extra option on your
one function) to clean up.

Your idea to return a pointer to a static block of pointers in your code is
full of pitfalls, unless you know your function will only be called once in
the caller's code. More than once, the block will get overwritten -- unless
your function will always put the same values there each call.
 
C

christian.bau

The usual method goes like this:

The caller passes a pointer to storage that it provides, and the size
of available storage. The called function provides the data, and
returns how much data is available. If the pointer passed in is a null
pointer then the callee just provides the amount of data available,
without calling anything. If the pointer passed is not null, but the
size is not enough then the callee doesn't write more data than
storage available.

That makes it quite clear what the callee has to do. For the caller,
there are two strategies: If you know an amount of data that is
usually enough, then do a call with a limited amount of local data
first; if this fails then the caller will know how much storage is
needed and will malloc it. Alternatively, if there is no reasonable
guess about the data size, pass a null pointer in the first call, then
make a second call with the storage properly allocated.
 
R

Richard Tobin

Remo D. said:
Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:
- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible for
handling the memory. The drawback is that my function will have to rely
on the correctness of such pointer to work properly.

A problem with this method is that it relies on the fact that you will
return at most 64 pointers. Why 64? Might you want to increase the
number in the future? If so you will have to add a new function, so
that old code that passes only 64 does not break.

Is the 64 a real constant of the problem, or is it just something like
the 64 best results? If the latter, I suggest you allow the caller to
provide an array along with its size, and you fill in the appropriate
number of values.
- My function allocates the array and returns it. This is similar to
strdup().

This is the obvious solution if the number of values varies. Even
with a maximum of 64, it might be wasteful to allocate space for 64
every time, regardless of how many are really needed.

The overhead of malloc() is likely to be small if you are dealing with
as many as 64 pointers.
Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

Whatever interface you provide, you'll have to rely on the caller
to use it properly. Calling free() or a similar function should
not be beyond your users' capabilities :)

As others have pointed out, your third alternative causes problems if
you might want two sets of results at the same time, and can be
particularly frustrating (and hard to track down) if someone uses your
code in a multi-threaded program.

-- Richard
 
R

Richard Harter

Hi! I'm writing a function that returns an array of (at maximum) 64
pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of 64
pointers. Similarly to sprintf(), the caller is entirely responsible for
handling the memory. The drawback is that my function will have to rely
on the correctness of such pointer to work properly.

- My function allocates the array and returns it. This is similar to
strdup(). Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended. The good is that I'm free from
allocation/freeing problem. The bad is that the return values will be
overwritten at each call; if the user wants to keep the return values
for subsequent use he has to copy and store them somewhere. Another
drawback is that it consumes memory even if the function will never be
called.

In my specific case, I was leaning toward the third option but I'd like
to hear your opinion on pitfalls, things that I've missed or alternative
approaches that could work better.

There is no single best answer - what to do depends upon how your
function is to be used and what kind of tradeoffs you want to
make.

Here are some questions to think about:

(1) Is the function a general service routine that can be called
from many places or is it only used in one application? In other
words, is it idiosyncratic? If it is a general service routine
you had best (IMNSHO) make it thread safe. If it is
idiosyncratic you can take certain liberties.

(2) Does it have to be recursion-safe and/or thread-safe? Your
option three is very dangerous. Here is what can happen:

while (some_condition) {
data = your_function();
do_something_clever();
process(data);
}

If do_something_clever calls your_function the ball game is over;
data has been scribbled on.

(3) Will the function be called sporadically or will it be called
in a loop? If it is in a loop you can reuse the data space from
the previous iteration, e.g.,

T * data = 0;
...
/* Optionally allocate space for data here */
while (more_to_do) {
data = your_function(data);
...
}
free(data);

Notice that we pass in the data pointer and return it; this is a
fairly common technique. Now what you can do is allocate space
within your_function if the data pointer is null. As a further
refinement, if the loop normally terminates with a no more data
condition you can use this code

T * data = 0;
...
while (data = your_function(data)) {
...
}

In this case your_function frees the space and returns a null
pointer when it reaches termination. It reallocates space as
needed. This kind of usage pattern is a special case but it is
quite common.

A caveat is that if a instance of the data has a greater life
time than the loop cycle you will need to make a copy of it.

Incidentally passing in the data pointer and returning it is good
form; it preserves flexibility.

(4) Is the data being returned bounded in space or unbounded?
If bounded, is the data expected to be much smaller than the
bound? If the data has a reasonable space bound then you may as
well allocate that much space and be done with it. Otherwise you
will have an error condition to deal with. When the data space
is bounded it is simpler to let the caller provide it because it
can then come from automatic storage. Thus in your case we might
do

char * data_array[64];
...
your_function(data_array);

Here we don't have to allocate and deallocate the data space; it
is handled cheaply and automatically for us. If, however, the
data array were very large we might not want to do this; the
stack (automatic storage) is small compared to the size of the
heap (allocatable storage).

(5) When the data size can be variable do we do automatic
resizing or user controlled resizing? User controlled resizing
is "safer" but more cumbersome; it requires extra code and
decisions on the calling side. Automatic resizing is more
convenient but more prone to bugs, e.g., dangling pointers and
erroneous deallocations.

(6) How do we determine the end of data when it can be variable
sized? There are two basic ways to do this; on is to return
(somehow) the size, and the other is to put a sentinel value at
the end of the data, typically some kind of null value. There
are arguments for each choice. Sometimes it does matter; most of
the time it is a matter of preferred style. However the choice
does impact your function's API and how you allocate storage.

If you go the sentinel route you have to allocate extra space for
the sentinel. Thus, in your case, you would say

char * data_array[65];

or, more generally,

#define NDATA 64
...
data_array[NDATA+1];

On the other hand, if you go the "return size of data" you have
the problem of how to return it. The problem is that C has no
good way to return two distinct things. What you have is a
choice of hacks and kludges. Here are some:

(a) You can pass the address of the size in the calling
sequence, e.g.,

data = your_function(data, &size);

This works and is compact, which is about the best that can be
said for it. Function design is cleaner if the inputs come in
through the calling sequence and outputs are returned and never
the twain are confused.

(b) We can turn (a) around and return the size. In this case
the call looks like:

size = your_function(data);

This form can be quite convenient if we have a loop that
terminates when we run out of data and if the data size is
bounded. This time the code looks like:

char *data[NDATA];
...
while (your_function(data) > 0) {
...
}

(c) You can return a structure that holds both the data and its
size. For example:

struct T_descr {
char *data[NDATA];
int size;
};
...
T_descr descr;
...
descr = your_function(&descr);
for (i = 0; i< descr.size;i++) {
/* do stuff with descr.data */
};

This makes the code more cumbersome; however it treats the data
as an object with properties, which may be a better way to handle
the data.

(d) You can pass a structure that holds the data and its size
but return the data. This looks slightly different:

struct T_descr {
char *data[NDATA+1];
int size;
};
...
T_descr descr;
char ** data;
...
data = your_function(&descr);
for (i = 0; i< descr.size;i++) {
/* do stuff with data */
};

Ordinarily data would point to descr.data but could be set to
null on no data. An advantage of this form is that we can, so to
speak, have our cake and eat it too. That is, we can put in a
sentinel and use either sentinel based code or index based code,
depending on which is more convenient.

(e) An "industrial grade" version of (d) hides information in the
structure, e.g.,

struct T_descr {
void * private;
int size;
};
...
T_descr descr = {0,0};
char ** data;
...
data = your_function(&descr);

The point of this form is that your_function can handle
allocation and deallocation behind the scenes and the user does
not have to do anything about. Within your_function private
points to a structure that holds data that is held from one call
to the next.

My apologies if this is a bit on the long winded size; however I
thought it worthwhile to go through some of the alternatives and
issues.
 
C

CBFalconer

Remo D. said:
Hi! I'm writing a function that returns an array of (at maximum)
64 pointers to char. I have thought of three possibility:

- The caller passes a pointer to a previously allocated array of
64 pointers. Similarly to sprintf(), the caller is entirely
responsible for handling the memory. The drawback is that my
function will have to rely on the correctness of such pointer to
work properly.

- My function allocates the array and returns it. This is similar
to strdup(). Here I will have to rely on the caller function to
properly free the array, which is something I'm not very
comfortable with.

- I'll have a "static char *ret[64]" in my function and will
return ret. I've not been able to think of a library function
that behaves this way, so I guess it's not reccomended. The good
is that I'm free from allocation/freeing problem. The bad is
that the return values will be overwritten at each call; if the
user wants to keep the return values for subsequent use he has
to copy and store them somewhere. Another drawback is that it
consumes memory even if the function will never be called.

I would use the 'strdup like' option. My reason is that this is
the only means that makes the function completely independent,
re-entrant, and reusable anywhere. You document that the assigned
array needs eventual freeing, and there are no more worries.
Everything else can be misused.
 
I

Ian Collins

CBFalconer said:
I would use the 'strdup like' option. My reason is that this is
the only means that makes the function completely independent,
re-entrant, and reusable anywhere. You document that the assigned
array needs eventual freeing, and there are no more worries.
Everything else can be misused.
The main drawback of that approach over the first option is it forces
the user to use dynamic memory.
 
T

Tim Smith

- My function allocates the array and returns it. This is similar to
strdup(). Here I will have to rely on the caller function to properly
free the array, which is something I'm not very comfortable with.

Use garbage collection and let the garbage collector deal with it.
Here's a garbage collector for C:

said:
- I'll have a "static char *ret[64]" in my function and will return
ret. I've not been able to think of a library function that behaves this
way, so I guess it's not reccomended. The good is that I'm free from
allocation/freeing problem. The bad is that the return values will be
overwritten at each call; if the user wants to keep the return values
for subsequent use he has to copy and store them somewhere. Another
drawback is that it consumes memory even if the function will never be
called.

You mentioned that 64 is the largest size you'll need. What you might
consider, if you go with the static approach, is to have more than 64
available:

static char * ret[1024];

for example. Use that as a circular pool to return items from. So, the
first caller gets &ret[0] returned. If he need 12 pointers returned,
the next caller would get his pointers starting at &ret[12], and so on.

Values still get overwritten, but it no longer will be on every call.
If you can sufficiently analyze the need of the code that will call
this, you may even be able to determine a pool size that will be able to
delay overwriting long enough that callers will always be done by time
their data is overwritten.
 
I

Ian Collins

Tim said:
Values still get overwritten, but it no longer will be on every call.
If you can sufficiently analyze the need of the code that will call
this, you may even be able to determine a pool size that will be able to
delay overwriting long enough that callers will always be done by time
their data is overwritten.
Until it gets used in a different context and the users start reporting
bizarre data corruption problems.
 
R

Remo D.

Tim Smith ha scritto:
Use garbage collection and let the garbage collector deal with it.
Here's a garbage collector for C:

I'd love to use a Garbage Collector but I can't include in the project a
dependency over another piece of software. Thanks for the suggestion,
anyway.
You mentioned that 64 is the largest size you'll need. What you might
consider, if you go with the static approach, is to have more than 64
available:
[...]
Values still get overwritten, but it no longer will be on every call.
If you can sufficiently analyze the need of the code that will call
this, you may even be able to determine [...][an appropriate][...] pool
size [...]

Unfortunately I don't have (nor I want to have) any control on how the
caller will call my function.

If I'll go to the static route (which is what I'm using for testing now,
but will likely change in the future) it is reasonable that I specify
that the returned values will only be valid between two subsequent
calls. It will be up to the caller to save his own copy of the values
if he needs them.

Thanks everybody for this discussion, every message helps me refining
the approach.

Remo.D.
 
S

SM Ryan

"Remo D." <rdentato> wrote:

# - The caller passes a pointer to a previously allocated array of 64

# - My function allocates the array and returns it. This is similar to

# - I'll have a "static char *ret[64]" in my function and will return

Â¥ You can pass a fixed size array in and out of function if you
put it inside a struct.

Â¥ If the program only requires a few resources relative what you
have on your system (for example a mere megabyte on a gigabyte vm),
and the system recovers all resources on exit, malloc without freeing.
The waste will not be signficant.

¥ÊGet a garbage collecting allocator. Allocate in the function
and let the allocator free it when it is no longer accessible.
 
C

CBFalconer

SM said:
Remo D. said:
- The caller passes a pointer to a previously allocated array of
- My function allocates the array and returns it. This is similar
- I'll have a "static char *ret[64]" in my function and will

You can pass a fixed size array in and out of function if you
put it inside a struct.

If the program only requires a few resources relative what you
have on your system (for example a mere megabyte on a gigabyte
vm), and the system recovers all resources on exit, malloc
without freeing. The waste will not be signficant.

Get a garbage collecting allocator. Allocate in the function
and let the allocator free it when it is no longer accessible.

Very good. Take a simple problem, add a gigabyte of code with
various incompatibilities and bugs, thus avoiding a free() call.
This is an ideal method of writing easily understandable and
maintainable software, and should be recommended to all.
Advertising it in a message with non-normal quote marks will
enhance its viability. Brack.
 
S

SM Ryan

# SM Ryan wrote:
# > "Remo D." <rdentato> wrote:
# >
# >> - The caller passes a pointer to a previously allocated array of
# >> - My function allocates the array and returns it. This is similar
# >> - I'll have a "static char *ret[64]" in my function and will
# >
# > You can pass a fixed size array in and out of function if you
# > put it inside a struct.
# >
# > If the program only requires a few resources relative what you
# > have on your system (for example a mere megabyte on a gigabyte
# > vm), and the system recovers all resources on exit, malloc
# > without freeing. The waste will not be signficant.
# >
# > Get a garbage collecting allocator. Allocate in the function
# > and let the allocator free it when it is no longer accessible.
#
# Very good. Take a simple problem, add a gigabyte of code with

Linking in libc is pretty much unavoidable.

# various incompatibilities and bugs, thus avoiding a free() call.
# This is an ideal method of writing easily understandable and
# maintainable software, and should be recommended to all.

Yes it is easier to understand and maintain. Thank you.
 

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

Staff online

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top