Я пытаюсь выучить указатели на Си и беру викторину для этой цели.Вот вопрос:
#include <stdio.h>
char *c[] = {"GeksQuiz", "MCQ", "TEST", "QUIZ"};
char **cp[] = {c+3, c+2, c+1, c};
char ***cpp = cp;
int main()
{
printf("%s ", **++cpp);
printf("%s ", *--*++cpp+3);
printf("%s ", *cpp[-2]+3);
printf("%s ", cpp[-1][-1]+1);
return 0;
}
Результат строки:
printf("%s ", *cpp[-2]+3);
смущает меня, но позвольте мне шаг за шагом объяснить, как я это понимаю.
char *c[]
- это массив указателей на char . char **cp[]
- это массив указателей, которые указывают на указатель на char (я считаю,это как оболочка для *c[]
в обратном порядке). char ***cpp
- это указатель на указатель, который указывает на указатель на char (я считаю это оболочкой для **cp[]
выполнять изменения на месте).
**++cpp
- поскольку cpp
указывает на cp
, тогда ++cpp
будет указывать на cp+1
, что составляет c+2
, поэтому двойное разыменование будетprint TEST
.
*--*++cpp+3
- поскольку теперь cpp
указывает на cp+1
, тогда ++cpp
будет указывать на cp+2
, что составляет c+1
, и следующая операция --
будетдайте нам указатель на c
, так что при последнем разыменовании будет напечатано sQuiz
.
Здесь возникает путаница:
cpp[-2]
- так как теперь cpp
указывает на cp+2
, чтоя могу подтвердитьс помощью
printf("%p\n", cpp); // 0x601090
printf("%p\n", cp+2); // 0x601090
здесь я печатаю адреса указателей в c
printf("c - %p\n", c); // c - 0x601060
printf("c+1 - %p\n", c+1); // c+1 - 0x601068
printf("c+2 - %p\n", c+2); // c+2 - 0x601070
printf("c+3 - %p\n", c+3); // c+3 - 0x601078
, поэтому при разыменовании, подобном этому *(cpp[0])
или **cpp
, я ожидаю получить значение MCQ
из c+1
printf("%p\n", &*(cpp[0])); // 0x601068
но когда я скажу *(cpp[-2])
, я получу QUIZ
, но я бы предпочел получить какое-то мусорное значение.
Итак, мои вопросы:
Как работает магия с *--*++cpp+3
, я имею в виду то, что модифицируется частью --
, которая позволяет мне получить MCQ
вместо TEST
при разыменовании, подобном этому **cpp
, Я предполагаю, что этот указатель *++cpp+3
сохраняет состояние после применения --
, но пока не может представить, как он работает.
Почему следующее работает так, как работает (cpp[-2]
часть):
printf("%p\n", &*cpp[1]); // 0x601060 -> c
printf("%p\n", &*(cpp[0])); // 0x601068 -> c+1
printf("%p\n", &*(cpp[-1])); // 0x601070 -> c+2
printf("%p", &*(cpp[-2])); // 0x601078 -> c+3
Кажется, что он имеет обратный порядок, я могу принять &*(cpp[0])
, указывая на c+1
, но я ожидал бы &*cpp[1]
укажите c+2
и &*(cpp[-1])
до c
.Что я нашел в этом вопросе: Разрешены ли отрицательные индексы массива в C?
Я, очевидно, путаю многие вещи и могу назвать что-то указателем, который на самом деле не один, я хотел бы понять концепцию указателя, поэтому буду рад, если кто-то покажет мне, где я неправ.