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, чтобы преобразовать их на английский:

  • char *argv[]= объявить argv как массив указателя на char

  • char **argv= объявить argv как указатель на указатель на char

Ответ 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]);

Его о/р. Используя это, мы можем легко понять.