3

So the problem I am facing is the following:

On one component, I read file names and store them in an array. There can be a maximum of 100 names of maximum 20 characters in length. This is defined as follows:

static Char_t fileList[100][20] = {};

where

fileList[1]= "name1" 
fileList[2]= "name2"  and so on.

By creating a function that returns a pointer to it I want to have access to this array of strings from another component of my code:

Char_t** getAllFiles(void)
{
    return &fileList;
}

And I assign the pointer like this:

Char_t **fileList = getAllFiles();

This does not seem to work. The best I have achieved is to get the pointer to the first component of the array. But I cannot get the rest of the components.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
Asan
  • 327
  • 3
  • 17
  • How did you tried to access the rest of the components with `fileList` in the caller? – RobertS supports Monica Cellio May 26 '20 at 08:50
  • That is the problem. When I tried to debug, I don't know how to tell the program to go to the 2nd, 3rd... component. If I would have: Char_t *fileList = getAllFiles(); and return fileList, I would only get the address of the first component. – Asan May 26 '20 at 08:54
  • 1
    All you need is the address of the first component. The matrix is contiguous in memory, so to access the ith row you need to use ‘p+columnSize*i’ – Enosh Cohen May 26 '20 at 12:36

2 Answers2

2

One simple option is to use pointer to array return type.

Here is a reproducible example:

#include <stdio.h>

char (*getAllFiles())[];

int main(void)
{
    char (*str_array)[20] = getAllFiles();
    printf("%s %s", str_array[0], str_array[1]); //test print
}

char (*getAllFiles())[]
{
    static char fileList[100][20] = {"name1", "name2"};
    return fileList;
}

If you don't want/need to use static storage, you can use the same type but with memory allocation, this will allow you to free the memory reserved for your array when you no longer need it. Note that using static storage can have its disadvantages as @RobertS supports Monica Cellio pointed out.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char (*getAllFiles())[];

int main(void)
{
    char (*str_array)[20] = getAllFiles();
    printf("%s %s", str_array[0], str_array[1]); //test print
    free(str_array); //free the allocated memory after it's used
}

char (*getAllFiles())[]
{
    //allocating space for an array of type char, which is always 1 byte, 
    //you must allocate memory according to the array type
    //for instance malloc(sizeof(Char_t) * 100 * 20);
    char (*fileList)[20] = malloc(100 * 20);

    strcpy(fileList[0], "name1");
    strcpy(fileList[1], "name2");

    return fileList;
}

Output in both cases:

name1 name2
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • 1
    Interesting. I didn´t know this method before. - But I think it´s great that we learned something from each other. – RobertS supports Monica Cellio May 26 '20 at 14:51
  • 1
    One side note: `malloc(100 * 20)` is clever but what if the type of `fileList` changes - a not to underestimating scenario - and remember that the OP might use this technique for other times where the type is different. `malloc(sizeof(char) * (100 * 20))` is more clear for others to read and with that I guess more safe. Also consider that OP is using mysterious `Char_t` which might not be equivalent to `char` in terms of size -> `sizeof(char) != sizeof(Char_t)`. – RobertS supports Monica Cellio May 26 '20 at 14:51
  • @RobertSsupportsMonicaCellio, yes I suppose, I might as well leave a comment there. – anastaciu May 26 '20 at 15:02
  • @RobertSsupportsMonicaCellio, just to quibble a bit :) memory allocation also has its downsides, it's quite expensive, static allocation is much faster. – anastaciu May 26 '20 at 15:08
  • 1
    Yes, I guess we just can pick the *most* optimal way, doesn't mean it is optimal. :-) – RobertS supports Monica Cellio May 26 '20 at 15:25
  • @RobertSsupportsMonicaCellio indeed. – anastaciu May 26 '20 at 15:38
1

Probably the better way is to allocate the array dynamically, because you are able to deallocate the array after it isn´t needed anymore.

To point to function-local objects from outside of the function is also considered as "bad practice", because it is f.e. not thread-safe.

In detail, allocate an array of 20 pointer to Char_t first and assign it to **fileList. Then allocate memory of 100 Char_t for each pointer.

Return fileList and assign it to a pointer to pointer to Char_t in the caller.

After that you can simply use file_list[i] to access the specific strings.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char** getAllFiles (void);

typedef char Char_t;

int main (void)
{
    Char_t** file_list = getAllFiles();

    printf("%s\n", file_list[0]);
    printf("%s", file_list[1]); 

    for (int i = 0; i < 20; i++)
    {
        free(file_list[i]);     // deallocate pseudo-rows of 100 Char_t.
    }

    free(file_list);            // deallocate pointer array.

}

char** getAllFiles (void)
{
    Char_t** fileList = malloc (sizeof (*fileList) * 20);

    for (int i; i < 20; i++)
    {
        fileList[i] = malloc (sizeof (**fileList) * 100);
    }

    strcpy(fileList[0], "name1");
    strcpy(fileList[1], "name2");

    return fileList;
}

Output:

name1
name2
  • Returning a variable with static storage is not a bad prectice, at least not to my knowledge https://stackoverflow.com/a/30621826/6865932 – anastaciu May 26 '20 at 14:04
  • @anastaciu In the comments regarding [this](https://stackoverflow.com/questions/4570366/how-to-access-a-local-variable-from-a-different-function-using-pointers#comment5014770_4570374) comment is discussed why returning a pointer to a static function-local object might not be the best way to go. – RobertS supports Monica Cellio May 26 '20 at 14:13
  • 1
    If you really want to allocate memory you can also do it for a `(*arr)[]` pointer to array type, it's simpler code, only one allocation and deallocation is needed, the only advantage I can see is that you can free the memory whereas a static variable lifetime is the same as the program. They both live in the heap. – anastaciu May 26 '20 at 14:16
  • I can see the downsides, the OP is using it already, it's certainly important to point out the disadvantages of using it, I wouldn't go so far as to say it's a bad practice, but, I respect the opinion, everyone is entitled to have one. – anastaciu May 26 '20 at 14:21