Hello!
Recently I've been working on a project which requires an API, the user supplies a function pointer which returns a specific value, this function needs a list of string arguments, similar to what you may find in the "main" function. I first thought maybe some sort of linked list but that would be inefficient so I decided on this. I first didn't really know how to implement it but after some fiddling I managed to implement this procedure to return a char** with the specified strings.

#include <stdarg.h>
char **new_argv(int count, ...)
{
    va_list args;
    int i;
    char **argv = malloc((count+1) * sizeof(char*));
    char *temp;
    va_start(args, count);
    for (i = 0; i < count; i++) {
        temp = va_arg(args, char*);
        argv[i] = malloc(sizeof(temp));
        argv[i] = temp;
    }
    argv[i] = NULL;
    va_end(args);
    return argv;
}

It is a variadic function (can accept a variable amount of arguments, ...) it accepts the amount of strings given, and the strings.

Example use:

void example()
{
    char **argv = new_argv(4, "This", "is", "a", "test");
    // argv[0] == "This"
    // argv[2] == "a"
}

I'm mainly posting this for two reasons, for people to test it and give feedback, mainly about memory efficiency, and to demonstrate it if other people need something similar in their projects.

Github Gist

Thanks for reading!

Edited 2 Years Ago by NardCake: Made adjustments suggested by Ancient Dragon

To be similar to argv in main argument you need to allocate one more than count pointers, the last pointer is NULL. That will also let you pass argv to other functions without needing to also pass the number of strings it contains.

Next, argv needs to have it's own copy of all strings so that the pointers do not get invalidated when the origianal strings are destroyed.

You also need to rename the function because it conflicts with argv array name.

#include <stdarg.h>
char **makeArgv(int count, ...)
{
    va_list args;
    int i;
    char **argv = malloc((count+1) * sizeof(char*));
    char *temp;
    va_start(args, count);
    for (i = 0; i < count; i++) {
        temp = va_arg(args, char*);
        argv[i] = malloc(sizeof(temp+1));
        strcpy(argv[i],temp);
    }
    argv[i] = NULL;
    va_end(args);
    return argv;
}

Edited 2 Years Ago by Ancient Dragon

Oh I see... Wasn't aware of this, thanks for the help. I will make the change.

Line 11 argv[i] = malloc(sizeof(temp)); or the modified form argv[i] = malloc(sizeof(temp+1)); does not allocate enough memory.

temp is a char* and has a fixed size 4 bytes (or maybe 8 depending on platform) so these 2 lines respectively allocate either 4 or 5 bytes of data. You then strcpy what temp points to into the location pointed to by argv[i]. This is likely to be a larger copy than the allocated memory.

You need to allocate memory for what temp points to not temp itself, the easiest (if not most secure) way is to use strlen and add 1 for the terminator.

argv[i] = malloc(strlen(temp)+1);
Comments
Right :)

Pointers was a bit complicated topic for me. But here I could grasp the coding easily. I have excuted the program, also I have tried out the code argv[i] = strdup(temp); by replacing strcpy() line. Now the pointers is becoming interesting for me.

This article has been dead for over six months. Start a new discussion instead.