Динамически создавать массив Char* в C

Я пытаюсь динамически создать массив char* для execv. Количество параметров известно только во время выполнения. Это мой код:

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);

Когда я компилирую код, у меня разные предупреждения:

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";
....

Я пытался следовать различным учебникам, но я не понимал, как я могу это решить. Спасибо.


person mani    schedule 07.10.2019    source источник
comment
char* может указывать на одну строку. Это не массив строк. Изучите массивы и указатели, прежде чем пытаться работать со строками.   -  person Lundin    schedule 07.10.2019


Ответы (2)


Вам нужен массив строк, массив массивов символов, указатель на указатель на символ.

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;

Это становится яснее, когда вы используете sizeof(*variable), который более удобочитаем, менее подвержен ошибкам и более понятен. Также части const char *string = "some string"; malloc(strlen(string) + 1); strcpy можно упростить, просто вызвав 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;

Не забудьте освободить память.

Или, в зависимости от вашей модели владения памятью, возможно, вы не хотите дублировать память и просто назначать указатели. Затем просто выделите память для массива указателей на char и назначьте указатели. Вы можете выделить память для строковых литералов в стеке.

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;

Или вы даже можете внимательно прочитать спецификацию execv (см. этот пост) и передать указатели на строковые литералы в execv и игнорировать квалификатор const, так как execv все равно не изменит массив.

# 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);
person KamilCuk    schedule 07.10.2019
comment
Спасибо, это работает. мой вопрос был не ясен? - person mani; 07.10.2019
comment
массив строк char* arr[x], массив массивов символов char arr[x][y] и указатель на указатель на символ char** ptr оказываются тремя разными, не обязательно связанными вещами. ОП, вероятно, достаточно запутан, не размывая всю терминологию. - person Lundin; 07.10.2019

Вы пытаетесь сохранить char * в char, вы должны использовать указатель указателя:

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

Строковые литералы — это const char[] (статический эквивалент const char *).

person Nathanael Demacon    schedule 07.10.2019