Подтвердить что ты не робот

С++ - char ** argv vs. char * argv []

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

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

Ответ 1

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

Это то же самое в C.

Ответ 2

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

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

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

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

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

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

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

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

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

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

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

Ответ 3

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

Ответ 4

В первой части вопроса:

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

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

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

Ответ 5

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

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

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

Ответ 6

В C и С++ существует разница между TYPE * NAME и TYPE NAME[]. В С++ оба типа не являются взаимозаменяемыми. Например, следующая функция является незаконной (вы получите ошибку) в С++, но легальная в 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]). Число в последних квадратных скобках должно быть равно аргументу. Преобразование из массива массивов в массив указателей является незаконным. Преобразование из указателя в указатель на массив массивов также является незаконным. Но преобразование указателя на указатель на массив указателей является законным!

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

Рассмотрим, что у нас есть указатель на указатель на int:

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

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

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

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

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

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

Ответ 7

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

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