Intereting Posts
mmap () vs read () зацикливание значений enum Недопустимое чтение / запись размера 8 2 Как статически связывать библиотеку с другой статической библиотекой? Как создать поведение ipairs (в противоположность парам) в API C Перераспределение смежных 2D-массивов Почему в качестве части C99 не были введены новые параметры формата printf () для новых (с шириной)? выделение массива внутри функции ac Ошибка MISRA-C в инициализации массива структур Как запросить корневой сертификат? Сравните два текстовых файла – программу проверки орфографии в C Как создать матрицу в C с помощью malloc и избежать проблем с памятью? Как я могу использовать синтаксис C99 для передачи матрицы в функцию? Как хранятся значения массива в архитектуре Little Endian или Big Endian Символическая математическая библиотека в C / C ++ / Obj-C Secure C и университеты – обучены переполнению буфера

Понимание операторов разыменования, адреса и оператора массива в C

У меня argv [] определяется как char *. Используя следующие команды printf:

printf("%s\n",argv[1]); // prints out the entire string printf("%p\n",&argv[1]); // & -> gets the address printf("%c\n",argv[1][0]);// prints out the first char of second var printf("%c\n",*argv[1]); // 

Это последнее, что я не понимаю. Что означает печать *argv[1] ? почему это не так, как *argv[1][0] и почему вы не можете распечатать printf("%s\n",*argv[1]); , Кроме того, почему &*argv[1] имеет другой адрес, а затем &argv[1] ?

    Операция индексирования массива a[i] определяется как *(a + i) – задается адрес a , смещение i элементов (а не байтов ) из этого адреса и разыгрывает результат. Таким образом, заданный указатель p , *p эквивалентен *(p + 0) , что эквивалентно p[0] .

    Тип argvchar ** ; учитывая, что все следующее верно:

      Expression Type Value ---------- ---- ----- argv char ** Pointer to a sequence of strings *argv char * Equivalent to argv[0] **argv char Equivalent to argv[0][0] argv[i] char * Pointer to a single string *argv[i] char Same as argv[i][0] argv[i][j] char j'th character of i'th string &argv[i] char ** Address of the pointer to the i'th string 

    Поскольку тип argv[i][j] является char , *argv[i][j] не является допустимым выражением.

    Вот плохая визуализация последовательности argv :

      +---+ +---+ +---+ argv | | ---> argv[0] | | ---------------------------> argv[0][0] | | +---+ +---+ +---+ +---+ argv[1] | | -------> argv[1][0] | | argv[0][1] | | +---+ +---+ +---+ ... argv[1][1] | | ... +---+ +---+ +---+ argv[argc] | | ---

    … argv[0][n-1] | | +—+ +—+ +—+ argv[1][m-1] | | +—+

    Это может помочь объяснить результаты различных выражений.

     char *argv[] 

    argv – массив (1) указателей на символы. Таким образом, это обычный массив, так как каждый элемент массива является указателем. argv[0] – указатель, argv[1] и т. д.

    argv[0] – первый элемент массива. Поскольку каждый элемент массива является указателем на указатель, значение этого также является указателем на символ (как мы уже упоминали выше).

    *argv[1] – Теперь здесь argv[1] является вторым элементом в указанном выше массиве, но argv[1] также является указателем char. Применяя * просто разыщите указатель, и вы получите первый символ в строке, на которую указывает argv[1] . Вы должны использовать %c для печати, поскольку это всего лишь символ.

    argv[1][0] уже является первым символом второй строки в массиве, поэтому больше нет места для разыменования. Это по существу так же, как и предыдущее.


    (1), как указано, строго говоря, это указатель на указатель, но, возможно, вы можете «думать» об этом как о массиве указателей. В любом случае, больше информации об этом здесь: https://stackoverflow.com/a/39096006/3963067

    Если argv[1] является указателем на char , то *argv[1] разделяет указатель и выводит вам первый символ строки в argv[1] , так что это то же самое, что и argv[1][0] и печатается с спецификатором формата "%c" .

    argv[1][0] – это char , а не указатель, поэтому он не может быть заменен.

    1. Это не относится к char * .
    2. Вы можете упростить, в чем разница между * ptr и ptr [0].
    3. Нет никакой разницы, потому что ptr [0] является сахаром для * (ptr + 0) или * ptr, потому что + 0 бесполезен.

     // printf("%p\n", &argv[1]); is wrong you must cast to (void *) printf("%p\n", (void *)&argv[1]); 

    Поскольку спецификатор %p ожидает void * , в нормальном случае C автоматически продвигает ваш указатель в void * но printf() использует список аргументов переменных. В этом есть много правил, я хочу, чтобы вы прочитали документ, если хотите. Но char * wiil не будет поощряться к void * и, как я говорю printf() кроме void * поэтому у вас есть неопределенное поведение, если вы не бросите его самостоятельно.

    Последняя строка printf("%c\n",*argv[1]); является как разыменование argv и доступ к индексу массива 1 . Другими словами, это делает argv[1][0] , как и предыдущая строка, потому что доступ к индексу массива [1] имеет более высокий приоритет, чем оператор разыменования ( * ).

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

     printf("%c\n", (*argv)[1]); 

    Теперь, когда вы запускаете программу, последняя строка вывода будет argv[0][1] вместо [1][0] , то есть второй символ в командной строке, которую вы используете для выполнения программы.