C разница между * [] и **
Это может быть немного основной вопрос, но в чем разница между написанием char * [] и char **? Например, в основном я могу иметь char * argv []. В качестве альтернативы я могу использовать char ** argv. Я предполагаю, что между этими двумя обозначениями должна быть какая-то разница.
Ответы
Ответ 1
В сложившихся обстоятельствах нет никакой разницы. Если вы попытаетесь использовать тип массива в качестве параметра функции, компилятор будет "настраивать" это вместо типа указателя (т.е. T a[x]
как параметр функции означает то же самое, что: T *a
).
При правильных обстоятельствах (т.е. не как параметр функции), может быть разница между использованием нотации массива и указателя. Один общий - в объявлении extern
. Например, предположим, что у нас есть один файл, который содержит что-то вроде:
char a[20];
и мы хотим сделать это видимым в другом файле. Это будет работать:
extern char a[];
но это не будет:
extern char *a;
Если мы сделаем вместо него массив указателей:
char *a[20];
... то же самое остается правдой - объявление внешнего массива отлично работает, но объявление указателя extern не выполняется:
extern char *a[]; // works
extern char **a; // doesn't work
Ответ 2
Зависит от контекста.
В качестве параметра функции они означают одно и то же (с компилятором), но запись его char *argv[]
может помочь сделать очевидным для программистов, что передаваемый char**
указывает на первый элемент массива char*
.
Как объявление переменной, они означают разные вещи. Один - указатель на указатель, другой - массив указателей, а массив - неопределенного размера. Итак, вы можете сделать:
char * foo[] = {0, 0, 0};
И получите массив из трех нулевых указателей. Три char*
- это совершенно другая вещь из указателя на char*
.
Ответ 3
Вы можете использовать cdecl.org, чтобы преобразовать их на английский:
Ответ 4
Я думаю, что это немного больше, чем синтаксический сахар, он также предлагает способ выразить семантическую информацию о (добровольном) контракте, подразумеваемом каждым типом декларации.
С char*[]
вы говорите, что это предназначено для использования в качестве массива.
С char**
вы говорите, что можете использовать это как массив, но не так, как предполагалось, чтобы он использовался.
Ответ 5
Это действительно зависит от контекста того, где происходят объявления.
Вне определения параметра функции объявление
T a[];
объявляет a
как массив T неизвестного размера; тип массива является неполным, поэтому, если a
не определен в другом месте (либо в этой единицы перевода, либо в другой единицы перевода, которая привязана), тогда для него не выделяется память (и вы, вероятно, получите ошибку "undefined reference" если вы попытаетесь связать, хотя я думаю, что поведение gcc по умолчанию - это определение массива с 1 элементом). Он не может использоваться как операнд для оператора sizeof
. Он может использоваться как операнд оператора &
.
Например:
/**
* module1.c
*/
extern char *a[]; /* non-defining declaration of a */
void foo()
{
size_t i = 0;
for (i = 0; a[i] != NULL; i++)
printf("a[%lu] = %s\n", (unsigned long) i, a[i++]);
}
module1.c использует неопределяющее объявление a
, чтобы ввести имя, чтобы его можно было использовать в функции foo
, но поскольку размер не указан, в нем нет места для хранения Блок. Самое главное, выражение a
не является типом указателя; это неполный тип массива. Он будет преобразован в тип указателя при вызове printf
по обычным правилам.
/**
* module2.c
*/
char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */
int main(void)
{
void foo();
foo();
return 0;
}
module2.c содержит определяющее объявление для a
(размер массива вычисляется из числа элементов в инициализаторе), что заставляет хранилище выделяться для массива.
Заметка стиля: никогда не пишите такой код.
В контексте объявления параметра функции T a[]
является синонимом T *a
; в обоих случаях a
- тип указателя. Это справедливо только в контексте объявления параметра функции.
Ответ 6
Как сказал Павел в комментарии выше, это синтаксический сахар. Оба типа char * и char [] - это один и тот же тип данных. В памяти они оба будут содержать адрес char.
Обозначение массива/индекса эквивалентно нотации указателя, как в декларации, так и в доступе, но иногда гораздо более интуитивно понятной. Если вы создаете массив указателей char, вы можете написать его так или иначе, чтобы уточнить ваше намерение.
Изменить: не рассмотрел случай Джерри, упомянутый в другом ответе. Взгляните на это.
Ответ 7
Как уже упоминалось в других ответах, char*[]
объявляет массив указателей на char, char**
объявляет указатель на указатель на char (который может использоваться как массив).
Одно отличие состоит в том, что массив является постоянным, а указатель - нет.
Пример:
int main()
{
char** ppc = NULL;
char* apc[] = {NULL};
ppc++;
apc++; /* this won't compile*/
return 0;
}
Ответ 8
char *ptr[2]={"good","bad"}; //Array of ptr to char
char **str; //Refer ptr to ptr to char
int i;
//str = &ptr[0]; //work
str = ptr;
for(i=0;i<2;i++) printf("%s %s\n",ptr[i],str[i]);
Его о/р. Используя это, мы можем легко понять.