Разыменование указателя на указатель на указатель и т. Д. На языке Си - PullRequest
1 голос
/ 07 июня 2019

Задача в моей школе следующая:

Создайте функцию, которая будет принимать в качестве параметра ******str указатель на указатель на указатель на указатель на указатель на указатель char и устанавливает Follow the white rabbit! на указатель символа.

void mx_deref_pointer(char ******str);

Я новичок в C и очень смущен, хотя я узнал все, что мог найти об указателях .. (

Я придумал следующий код:

#include <stdio.h>
#include <stddef.h>

void mx_deref_pointer(char ******str) {
    char *pstr1, **pstr2, ***pstr3, ****pstr4, *****pstr5;
    str = &pstr5;
    pstr5 = &pstr4;
    pstr4 = &pstr3;
    pstr3 = &pstr2;
    pstr2 = &pstr1;
    pstr1 = "Follow the white rabbit!";
    printf("%s", pstr1);
}

int main() {
    char ******pstr6 = NULL;
    mx_deref_pointer(pstr6);
}

Он выводит «Follow the white rabbit», но я не думаю, что это правильно, поскольку комментирование большинства функций все равно дает тот же результат. Кроме того, я не знаю, как передать что-либо кроме NULL в mx_deref_pointer (). Некоторые из парней, которые учатся у меня, придумали другой mx_deref_pointer:

void mx_deref_pointer(char ******str) {
    str [0] [0] [0] [0] [0] [0] = "Follow the white rabbit!";
}

Кажется, это работает, однако никто из них не смог мне объяснить, как это работает. Я был бы чрезвычайно признателен, если бы кто-то смог предоставить для этого подходящий кусок кода и, что более важно, объяснить, что и как он делает!

Спасибо.

Ответы [ 2 ]

3 голосов
/ 07 июня 2019

Чтобы соответствовать аргументу вашей функции (6-кратный указатель на char), адрес 5-кратного указателя на символ может быть предоставленным аргументом от вызывающей стороны (или значение 6-кратного указателя на символ, вы ' повторный выбор, если они имеют в виду действительные данные). Таким образом, все эти составленные указатели принадлежат вызывающей стороне (main), а не функции. Короче говоря, функция и main должны выглядеть примерно так:

#include <stdio.h>

void mx_deref_pointer(char ******str)
{
    static char msg[] = "Follow the white rabbit!";
    *****str = msg;
}

int main() 
{
    char *ptr1 = NULL;
    char **ptr2 = &ptr1;
    char ***ptr3 = &ptr2;
    char ****ptr4 = &ptr3;
    char *****ptr5 = &ptr4;

    mx_deref_pointer(&ptr5);

    puts(ptr1);
    return 0;
}

выход

Follow the white rabbit!

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

void mx_deref_pointer(char ******str)
{
    *****str = "Follow the white rabbit!";
}

Но это плохая практика, так как вызывающая сторона может ожидать изменяемую строку. Строковый литерал недоступен для записи , и сохранение его в char * позволит коду писать в эту строку без какого-либо предупреждения, выдаваемого компилятором. Поэтому перед возвратом лучше скопировать литерал в массив для записи.

Относительно того, как работает цепочка разыменования синтаксиса массива, учитывая некоторый указатель не пустого типа p, они эквивалентны:

p[n] == *(p+n)

И поэтому они эквивалентны:

p[0] == *(p+0)

Но *(p+0) - это просто *p. Поэтому это:

void mx_deref_pointer(char ******str)
{
    static char msg[] = "Follow the white rabbit!";
    *****str = msg;
}

эквивалентно этому:

void mx_deref_pointer(char ******str)
{
    static char msg[] = "Follow the white rabbit!";
    str[0][0][0][0][0] = msg;
}
2 голосов
/ 07 июня 2019

в соответствии с

https://www.programiz.com/c-programming/c-pointers-arrays

x [0] эквивалентно * x.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...