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.

3
  • How did you tried to access the rest of the components with fileList in the caller? Commented May 26, 2020 at 8: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. Commented May 26, 2020 at 8: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’ Commented May 26, 2020 at 12:36

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

6 Comments

Interesting. I didn´t know this method before. - But I think it´s great that we learned something from each other.
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).
@RobertSsupportsMonicaCellio, yes I suppose, I might as well leave a comment there.
@RobertSsupportsMonicaCellio, just to quibble a bit :) memory allocation also has its downsides, it's quite expensive, static allocation is much faster.
Yes, I guess we just can pick the most optimal way, doesn't mean it is optimal. :-)
|
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

4 Comments

Returning a variable with static storage is not a bad prectice, at least not to my knowledge stackoverflow.com/a/30621826/6865932
@anastaciu In the comments regarding this comment is discussed why returning a pointer to a static function-local object might not be the best way to go.
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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.