-2

I am trying to create a char* array dynamically for execv. The number of parameters is known only at runtime. This is my code:

char *id_array= malloc((size_array) * sizeof(char));
int length = 4 + groupId_list.nr; //groupId_list.nr know only at runtime
id_array= realloc(id_array,sizeof(char)*length);

id_array[0] = "/usr/bin/java";
id_array[1] = "-jar";
id_array[2] = "pathToFile/jar";

for (int j = 0; j < groupId_list.nr; j++) {
    id_array[j+3] = groupId_list.items[j].string;
}
id_array[size_array-1] = (char*)0; //terminator need for execv

execv("/usr/bin/java",&id_array);

When I compile the code i am having different warnings:

warning: incompatible pointer to integer conversion assigning to 'char' from 'char [14]'
 id_array[0] = "/usr/bin/java";
warning: incompatible pointer to integer conversion assigning to 'char' from 'char [5]'
 id_array[1] = "-jar";
....

I tried to follow different tutorials but i didn't understand how i can solve it. Thanks.

mani
  • 3
  • 6
  • A `char*` can point at a single string. It is not an array of strings. Study arrays and pointers before attempting strings. – Lundin Oct 07 '19 at 13:20

2 Answers2

2

You want an array of strings, an array of arrays of characters, a pointer to a pointer to a char.

int length = 4 + groupId_list.nr;
char **id_array= malloc(sizeof(char*) * length);

const char *str1 = "/usr/bin/java";
id_array[0] =  malloc(sizeof(char) * (strlen(str1) + 1));
strcpy(id_array[0], str1);

const char *str2 = "-jar";
id_array[1] =  malloc(sizeof(char) * (strlen(str2) + 1));
strcpy(id_array[1], str2);

const char *str3 = "pathToFile/jar";
id_array[2] =  malloc(sizeof(char) * (strlen(str3) + 1));
strcpy(id_array[2], str3);

for (size_t j = 0; j < groupId_list.nr; ++j) {
    id_array[j + 3] = malloc(sizeof(char) * (strlen(groupId_list.items[j].string) + 1));
    strcpy(id_array[j + 3], groupId_list.items[j].string);
}

id_array[length - 1] = NULL;

It get's clearer when you use sizeof(*variable), which is way more readable and less error prone, and more clearer. Also the parts const char *string = "some string"; malloc(strlen(string) + 1); strcpy can be simplified with just a call to strdup.

char **id_array= malloc(sizeof(*id_array) * 4);
id_array[0] = strdup("/usr/bin/java");
id_array[1] = strdup("-jar");
id_array[2] = strdup("pathToFile/jar");
for (int j = 0; j < groupId_list.nr; j++) {
    id_array[j + 3] = strdup(groupId_list.items[j].string);
}
id_array[length - 1] = NULL;

Remember to free the memory.

Or depending on your memory ownership model, maybe you don't want to duplicate the memory and just assign pointers. Then just allocate the memory for array of pointers to char and assign pointers. You could allocate memory for string literals on stack.

char **id_array = malloc(sizeof(*id_array) * length);
id_array[0] = (char[]){"/usr/bin/java"};
id_array[1] = (char[]){"-jar"};
id_array[2] = (char[]){"pathToFile/jar"};
for (....) { 
   id_array[j + 3] = groupId_list.items[j].string;
}
id_array[length - 1] = NULL;

Or you could even carefully read execv specification (see this post) and pass pointers to string literals to execv and ignore the const qualifier, as execv will not modify the array anyway.

# string literals are constant
const char **id_array = malloc(sizeof(*id_array) * length);
id_array[0] = "/usr/bin/java";
id_array[1] = "-jar";
id_array[2] = "pathToFile/jar";
for (....) { 
   id_array[j + 3] = groupId_list.items[j].string;
}
id_array[length - 1] = NULL;

# explicitly remove the const qualifier, which is safe, because we 
# know from the documentation that execv will not modify the array contents
execv(...., (void*)id_array);
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Thanks, It works. is the my question was not clear ? – mani Oct 07 '19 at 12:48
  • "an array of strings" `char* arr[x]`, "an array of arrays of characters" `char arr[x][y]` and "a pointer to a pointer to a char" `char** ptr` happen to be 3 different, not necessarily related things. The OP is probably confused enough without making all terminology a blur. – Lundin Oct 07 '19 at 13:23
0

You are trying to store a char * in a char, you must use a pointer of pointer:

char **id_array = malloc((size_array) * sizeof(char *));

String literals are const char[] (static equivalent of const char *).

Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
Nathanael Demacon
  • 1,169
  • 7
  • 19