Function that returns an array of strings C


Is there a way to return an array of strings from a function without using dynamic memory allocation? The function goes something like this:

char** modify(char original[1000][1000]){ 
    char result[1000][1000];
    // some operations are applied to the original
    // the original is copied to the result
    return result;
}
- - Source

Answers

answered 5 day ago Eric Postpischil #1

In C, an object has one of four storage durations (also called lifetimes): static, thread, automatic, and allocated (C 2018 6.2.4 1).

Objects with automatic duration are automatically created inside a function and cease to exist when execution of the function ends, so you cannot use these that is created inside your function to return a value.

Objects with allocated storage duration persist until freed, but you have asked to exclude those.

Thread storage duration is either likely not applicable to your situation or is effectively equivalent to static storage duration, which I will discuss below.

This means your options are:

  • Let the caller pass you an object in which to return data. That object may have any storage duration—your function does not need to know since it will neither allocate nor release it. If you do this, the caller must provide an object large enough to return the data. If this size is not known in advance, you can either provide a separate function to calculate it (which the caller will then use to allocate the necessary space) or incorporate that into your function as a special mode in which it provides the size required without providing the data yet.
  • Use an object with static storage duration. Since this object is created when the program starts, you cannot adjust the size within your function. You must build a size limit into the program. A considerable problem with this approach is the function has only one object to return, so only one can be in use at a time. This means that, once the function is called, it should not be called again until the caller has finished using the data in the object. This is both a severe limitation in program design and an opportunity for bugs, so it is rarely used.

Thus, a typical solution looks like this:

size_t HowMuchSpaceIsNeeded(char original[1000][1000])
{
    … Calculate size.
    return SizeNeeded;
}

void modify(char destination[][1000], char original[1000][1000])
{
    … Put results in destination.
}

A variation for safety is:

void modify(char destination[][1000], size_t size, char original[1000][1000])
{
    if (size < amount needed)
        … Report error (possibly by return value, or program abort).
    … Put results in destination.
}

Then the caller does something like:

size_t size = HowMuchSpaceIsNeeded(original);
char (*results)[1000] = malloc(size);
if (!results)
    … Report error.
modify(results, size, original)
… Work with results.
free(results);

As Davistor notes, a function can return an array embedded in a structure. In terms of C semantics, this avoids the object lifetime problem by returning a value, not an object. (The entire contents of the structure is the value of the structure.) In terms of actual hardware implementation, it is largely equivalent to the caller-passes-an-object method above. (The reasoning here is based on the logic of how computers work, not on the C specification: In order for a function to return a value that requires a lot of space to represent, the caller must provide the required space to the called function.) Generally, the caller will allocate space on the stack and provide that to the called function. This may be faster than a malloc, but it may also use a considerable amount of stack space. Usually, we avoid using sizable amounts of stack space, to avoid overflowing the stack.

answered 5 day ago TheNoobHunter66 #2

You can use a linked list starts with the first string and ends with the last string .

answered 5 day ago Inline #3

You can't return pointers to the local variables, because lifetime of the memory to which they point is limited to the scope.

Basically result is a pointer to the stack-allocated array first element, so returning it and dereferencing it later will result in undefined behavior.

To bypass this issue, there are few work-arounds.

One of those, I saw in couple of projects, but I don't recommend it, because it is unsafe.

char** modify(char original[1000][1000]){ 
    // `result` is static array, which lifetime is equal to the lifetime of the program
    // Calling modify more than one time will result in overwriting of the `result`.
    static char result[1000][1000]; 
    return result;
}

Another approach will be to receive result pointer as function argument, so the caller will allocate storage for it.

void modify(char original[1000][1000], char (*result)[1000]){ 
    result[0][1] = 42; 
    //...
}
void main() {
    char result[1000][1000];
    modify(someOriginal, result);
}

Anyway, I recommend you to read some decent book about C language and how a computer memory works.

answered 5 day ago Vlad Rusu #4

You cannot return a pointer to memory allocated inside a function without dynamic allocation. In your case, you will allocate result[1000][1000] on the stack in a zone which will be deallocated once the function returns. Besides dynamic allocation, you have the option of passing a buffer as an argument to your function:

void modify(char original[1000][1000], char result[][]) { ... }

Now the result matrix has to be allocated outside the modify function and its lifetime will not depend on the function's lifetime. Basically you pass the function an already allocated matrix where the result will be written.

answered 5 day ago Davislor #5

Although you cannot return an array type in C, you can return a struct containing one:

#include <string.h>

#define NSTRINGS 100
#define STR_LEN 100

typedef struct stringtable {
  char table[NSTRINGS][STR_LEN];
} stringtable;

stringtable modify ( const stringtable* const input )
{
  stringtable result;

  memcpy( &result, input, sizeof(result) );

  return result;
}

I would generally recommend that you use Eric Postpischil’s solution, however. One way this might not be efficient is if you need to write to a specific variable or location. In that case, you could pass in its address, but here, you would need to create a large temporary array and copy it.

comments powered by Disqus