C ++ - char ** argv против char * argv [] - PullRequest
49 голосов
/ 04 марта 2011

В чем разница между char** argv и char* argv[]int main(int argc, char** argv) и int main(int argc, char* argv[])?

Они одинаковы?Тем более, что первая часть не имеет [].

Ответы [ 7 ]

54 голосов
/ 04 марта 2011

Они полностью эквивалентны. char *argv[] должен читаться как массив указателей на char, а аргумент массива понижается до указателя, поэтому указатель на указатель на char или char **.

То же самое в C .

24 голосов
/ 04 марта 2011

Они действительно одинаковы.

Золотое правило массивов, которое нужно запомнить:

"Имя массива - указатель на первый элементмассива. "

Итак, если вы объявите следующее:

char text[] = "A string of characters.";

Тогда переменная" text "является указателем напервый символ в массиве символов, который вы только что объявили.Другими словами, «текст» имеет тип char *.Когда вы обращаетесь к элементу массива, используя [ index ], вы фактически добавляете смещение index к указателю на первый элемент массива, а затемразыменование этого нового указателя.Следовательно, следующие две строки будут инициализировать обе переменные как 't':

char thirdChar = text[3];
char thirdChar2 = *(text+3);

Использование квадратных скобок - это удобство языка, которое делает код намного более читабельным.Но то, как это работает, очень важно, когда вы начинаете думать о более сложных вещах, таких как указатели на указатели.char** argv совпадает с char* argv[], потому что во втором случае «имя массива является указателем на первый элемент в массиве».

Из этого следует такжебыть в состоянии понять, почему индексы массива начинаются с 0. Указатель на первый элемент - это имя переменной массива (снова золотое правило) плюс смещение ... ничего!

У меня были дебатыс моим другом, который лучше использовать здесь.С нотацией char* argv[] читателю может быть понятнее, что на самом деле это «массив указателей на символы», а не нотация char** argv, которая может быть прочитана как «указатель на указатель на символ».Мое мнение таково, что эта последняя нотация не передает столько информации читателю.

Хорошо знать, что они точно такие же, но для удобства чтения я думаю, что если намерение представляет собой массив указателейтогда запись char* argv[] передает это гораздо яснее.

3 голосов
/ 04 марта 2011

Для первой части вопроса:

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

Таким образом, вопрос в том, являются ли указатель на тип C и массив C [] одинаковыми. Они вообще не совсем, НО они эквивалентны при использовании в подписях .

Другими словами, в вашем примере нет разницы, но важно помнить разницу между указателем и массивом в противном случае.

3 голосов
/ 04 марта 2011

Для всех практических целей они одинаковы. Это связано с тем, что C / C ++ обрабатывает массивы, передаваемые в качестве аргументов, когда массив распадается на указатель.

2 голосов
/ 29 октября 2013

Форма в скобках полезна только в объявлениях операторов, таких как:

char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3

Поскольку она знает во время компиляции размер массива.Когда вы передаете форму скобки в качестве параметра функции (основной или какой-либо другой), компилятор не имеет представления о том, каким будет размер массива во время выполнения, поэтому он точно такой же, как char ** a.Я предпочитаю char ** argv, поскольку ясно, что sizeof не будет работать так, как в форме объявления оператора.

0 голосов
/ 06 мая 2016

Существует разница между TYPE * NAME и TYPE NAME[] в C и C ++. В C ++ оба типа не являются взаимозаменяемыми. Например, следующая функция недопустима (вы получите ошибку) в C ++, но недопустима в C (вы получите предупреждение):

int some (int *a[3]) // a is array of dimension 3 of pointers to int
{
    return sizeof a;
}

int main ()
{
    int x[3][3];
    std::cout << some(x)<< std::endl;
    return 0;
}

Чтобы сделать его легальным, просто измените подпись на int some (int (*a)[3]) (указатель на массив из 3-х дюймов) или int some (int a[][3]). Число в последних квадратных скобках должно быть равно аргументу. Преобразование из массива в массив указателей является незаконным. Преобразование из указателя в указатель в массив массивов тоже недопустимо. Но преобразование указателя в указатель на массив указателей является законным!

Итак, помните: Только ближайшая к разыменованию подпись типа не имеет значения, другие делают (в контексте указателей и массивов, конечно).

Предположим, у нас есть указатель as на указатель на int:

int ** a;
&a     ->     a    ->    *a    ->    **a
(1)          (2)         (3)          (4)
  1. Вы не можете изменить это значение, тип int ***. Может приниматься функцией как int **b[] или int ***b. Лучший int *** const b.
  2. Тип int **. Может приниматься функцией как int *b[] или int ** b. Скобки объявленного массива могут быть пустыми или содержать любое число.
  3. Тип int *. Может приниматься функцией как int b[] или int * b или даже void * b
  4. Должен быть принят в качестве параметра int. Я не хочу вдаваться в детали, как неявный вызов конструктора.

Ответ на ваш вопрос: реальный тип аргументов в основной функции равен char ** argv, поэтому его можно легко представить как char *argv[] (но не как char (*argv)[]) , Также argv название основной функции может быть безопасно изменено. Вы можете легко проверить это: std::cout << typeid(argv).name(); (PPc = указатель на стр. На символ)

Кстати: есть классная функция, передающая массивы в качестве ссылок:

void somef(int (&arr)[3])
{
    printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
}

Более того, указатель на что-либо может быть неявно принят (преобразован) функцией как указатель void. Но только один указатель (не указатель на указатель и т. Д.).

Дальнейшее чтение:

  1. Бьярн Страуструп, C ++, глава 7.4
  2. FAQ по указателям C
0 голосов
/ 04 марта 2011

Оба варианта одинаковы для вас, за исключением следующих незначительных различий:

  • Sizeof даст разные результаты для обоих
  • Также второй не может быть переназначен в новую область памяти, так как это массив
  • Со вторым вы можете использовать только те индексы, которые действительный. Это не определено в C / C ++, если вы пытаетесь использовать индекс массива за пределами длина массива Однако с char ** вы можете использовать любой индекс от 0 до ...
  • Вторая форма может использоваться только как формальные параметры функции. Хотя first может даже использоваться для объявления переменных в стеке.
...