Search code examples
cmallocmemcpyrealloc

Create Dynamic Array of Strings in C


I know there are multiple questions about creating dynamic arrays in C but they didn't really help me so let me ask in a different way.

My program needs to read in a variable number of command line arguments, each of variable length. This function takes the argv array passed into main and should return an array of char* containing only those arguments that are environment settings. (The program needs to replicate the UNIX env command.) Here is what I have now:

char** getEnvVariables(char* args[], int start) {
    int i = start;
    char** env_vars = (char **) malloc(1); 
    while (args[i]) {
        printf("size of env_vars: %d\n", sizeof(env_vars));
        if (isEnvironmentSetting(args[i])) {
            printf("arg: %s\n", args[i]);
            printf("size of arg: %d\n", sizeof(args[i]));
            printf("new size of env_vars: %d\n", (sizeof(env_vars) + sizeof(args[i])));

            env_vars = realloc(env_vars, (sizeof(env_vars) + sizeof(args[i])));
            memcpy(env_vars, args[i], sizeof(args[i]));
            i++;
        }
        else
            break;
    }

    return env_vars;
}

My idea was to create the array with malloc() and then use realloc() to allocate the space needed for each char* and memcpy() to add the new char* to the array. But the array isn't actually growing. At each iteration of the loop, it's size is 8 bytes. I'm still very new to C and the hands-on memory management so any help is appreciated.


Solution

  • You cannot copy the input C-strings to the output, unless you want to return a (char pointer) that points to all the strings concatenated together. To return an array of (char pointer) (or (char pointer pointer) ) you need to either malloc a new string and store the address of that in env_vars, or have env_vars store the address of args[i]. Here is an implementation of both approaches:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <string.h>
    
    bool isEnvironmentSetting(const char * string)
    {
       (void) string;
       return true;
    }
    
    char** getEnvVariables1(char* args[], int start) {
        int i = start;
        int num_args = 0;
        char** env_vars = NULL;
        char *string = NULL;
        printf("size of env_vars: %ld\n", num_args * sizeof(env_vars));
        while (args[i]) {
            if (isEnvironmentSetting(args[i])) {
                printf("arg: %s\n", args[i]);
                printf("size of arg: %ld\n", strlen(args[i]));
                num_args++;
                printf("new size of env_vars: %ld\n", num_args * sizeof(env_vars));
                env_vars = realloc( env_vars, sizeof(env_vars) * num_args );
                string = malloc(strlen(args[i]) + 1);
                strcpy(string,args[i]);
                env_vars[num_args - 1] = string;
                i++;
            }
            else
                break;
        }
        env_vars = realloc( env_vars, sizeof(env_vars) * (num_args + 1) );
        env_vars[num_args] = NULL;    
        return env_vars;
    }
    
    char** getEnvVariables2(char* args[], int start) {
        int i = start;
        int num_args = 0;
        char** env_vars = NULL;
        printf("size of env_vars: %ld\n", num_args * sizeof(env_vars));
        while (args[i]) {
            if (isEnvironmentSetting(args[i])) {
                printf("arg: %s\n", args[i]);
                printf("size of arg: %ld\n", strlen(args[i]));
                num_args++;
                printf("new size of env_vars: %ld\n", num_args * sizeof(env_vars));
                env_vars = realloc( env_vars, sizeof(env_vars) * num_args );
                env_vars[num_args - 1] = args[i];
                i++;
            }
            else
                break;
        }
        env_vars = realloc( env_vars, sizeof(env_vars) * (num_args + 1) );
        env_vars[num_args] = NULL;
        return env_vars;
    }
    
    int main(int argc, char *argv[])
    {
       (void) argc;
    
       char **envVars = getEnvVariables1(argv,1);
       int i = 0;
       while (envVars[i] != NULL)
       {
          printf("env var: %s\n",envVars[i]);
          i++;
       }
    
       envVars = getEnvVariables2(argv,1);
       i = 0;
       while (envVars[i] != NULL)
       {
          printf("env var: %s\n",envVars[i]);
          i++;
       }
    
    }