C Указатели: как генерируется следующий вывод? - PullRequest
1 голос
/ 05 марта 2020
#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 \n", **++cpp);
    printf("%s \n", *--*++cpp+3);
    printf("%s \n", *cpp[-2]);      // line 3
    printf("%s \n", cpp[-1][-1]);   // line 4
    return 0;
}

Вывод:

TEST 
sQuiz 
QUIZ 
MCQ 

Может кто-нибудь объяснить, пожалуйста, вывод строки 3 и 4? Я понимаю вывод первых двух операторов printf , но строки 3 и 4 поразили меня!

Ответы [ 2 ]

3 голосов
/ 05 марта 2020

cpp указывает на cp в начале. Он увеличивается в два раза в первых 2 строках, поэтому он указывает на cp + 2 в строке 3. (cp + 2)[-2] равно *(cp + 2 - 2), что равно *cp. *cp равно c+3, что с другим * "QUIZ".

cpp все еще указывает на cp + 2 в строке 4, с индексом -1 даст cp[1], что c+2, снова индекс -1 дает c[1], что "MCQ".

1 голос
/ 05 марта 2020

Указатели массива, используемые в выражениях с редкими исключениями, преобразуются в указатели на свои первые элементы.

Таким образом, в этом объявлении

char ***cpp = cp;

указатель массива cp преобразуется в указатель на его первый элемент, который определяется выражением c+3.

В вызовах printf указатель cpp увеличивается в два раза. Первый раз в этом вызове

printf("%s \n", **++cpp);

и второй раз в этом вызове

printf("%s \n", *--*++cpp+3);

Поэтому внутри первого вызова указатель cpp после приращения указывает на второй элемент массив cp, то есть он указывает на элемент, инициализированный как c+2. Таким образом, разыменовывая указатель, мы получаем указатель на строковый литерал "TEST", который выводится.

Во втором вызове указатель cpp снова увеличивается. Таким образом, он указывает на элемент массива cp, который определяется выражением c + 1. Разыменовав этот указатель *++cpp, мы получаем указатель со значением c + 1. Уменьшая значение --*++cpp, мы получаем указатель со значением c, который указывает на первый элемент массива c. Разыменовывая указатель мы получаем указатель на первый элемент строкового литерала "GeksQuiz". Теперь, добавив число 4 к указателю *--*++cpp+3, мы получаем указатель, указывающий на четвертый символ строкового литерала. Таким образом, в этом вызове printf вывод будет "sQuiz"

Как было указано, указатель cpp теперь указывает на третий элемент массива cp после его увеличения в два раза. Таким образом, выражение cpp[-2] возвращает первый элемент атрибута cp со значением c+3. Таким образом, литерал "QUIZ" выводится в этом вызове

printf("%s \n", *cpp[-2]);      // line 3

Это выражение cpp[-1] возвращает второй элемент массива cp, который инициализируется как c+2. Используя выражение cpp[-1][-1], мы получаем указатель на второй элемент массива c, который является строковым литералом "MCQ", который выводится в этом вызове

printf("%s \n", cpp[-1][-1]);   // line 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...