Почему временный аргумент char ** незаконен?
У меня есть функция f(char **p)
, и я хотел вызвать ее как можно проще.
Я старался
char ** p = {"a", "b"};
f(p);
и получил:
скалярному объекту требуется один элемент в инициализаторе
поэтому я изменил это в
char * p[2] = {"a", "b"};
f(p);
и это прошло хорошо [было бы также хорошо с просто char * p[]
].
Почему я не могу создать массив указателей на лету, как показано ниже?
f({"a", "b"});
Ответы
Ответ 1
Это дает предупреждение:
char ** p = {"a", "b"};
потому что p
не массив.
Это тоже не законно:
f({"a", "b"});
поскольку фигурные скобки сами по себе не допускаются в выражении (но могут использоваться как инициализатор).
Можно создать массив на лету, используя составной литерал:
f((char *[]){"a", "b"});
Вы также можете использовать составной литерал для инициализации временного:
char ** p = (char *[]){"a", "b"};
В отличие от первого утверждения, это допустимо, потому что литерал является массивом типа char *[2]
и будет распадаться на char **
который можно использовать для инициализации переменной этого типа.
См. Раздел 6.5.2.5 стандарта C для более подробной информации о составных литералах.
Ответ 2
Это объявление char ** p = {"a", "b"};
вызывает предупреждение, потому что C не знает, как интерпретировать содержание {
}
фигурные скобки:
- Тип объявления
char**
предполагает наличие единого указателя на указатель на символ - Содержимое
{
}
определяет два элемента.
Вы должны указать C, что вы инициализируете указатель на указатель указателем на начальный элемент анонимного массива, указывая тип перед фигурными скобками:
char ** p = (char*[]){"a", "b"}
Эта конструкция называется "составной литерал". Его можно использовать в объявлении, но он также работает как выражение.
Примечание: если вы планируете передать подобный массив функции, вам нужно указать способ определения размера массива. Один из подходов состоит в том, чтобы передать NULL
для "завершения" массива, например так:
void f(char **p) {
int i = 0;
while (*p) {
printf("%d:%s\n", i++, *p++);
}
}
int main(void) {
f((char*[]){"a", "b", NULL});
return 0;
}
Demo.
Ответ 3
C99 и позже добавили составные литералы для точной цели: создание массива и структур на лету
Пример:
struct foo {int a; char b[2];} structure;
structure = ((struct foo) {1, 'a', 0});
int *y = (int []) {1, 2, 3};
int *z = (int []) {1};
Помимо стандартного C99 и более поздних, GCC также предоставляет эту функцию в качестве расширения.
В вашем случае это будет работать
f((char *[]){"a","b"});
(char *[]){"a","b"}
является составным литералом, который создает массив из 2 указателей на char
на лету.