Передача двойного указателя в функцию - PullRequest
0 голосов
/ 20 февраля 2020

Я создавал программу со связанными списками в C. Я создал переменную head в функции main. Затем я передал его по ссылке на функцию insert_at_head(struct node **head).

У меня есть другая функция для вставки в хвост. В базовом состоянии, если мой список пуст, я хочу снова вызвать insert_at_head(struct node **head). Но я путаюсь в передаче фактического параметра. Должно ли это быть insert_at_head (&(*head)) или insert_at_head (head)?

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

Ответы [ 3 ]

1 голос
/ 20 февраля 2020

Что касается функции insert_at_head, вы должны помнить, что в C все аргументы передаются значением . Это означает, что значение скопировано в переменную аргумента. Внутри функции, если вы изменяете переменную аргумента (например, присваиваете ей), то вы изменяете только копию, а не оригинал.

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

Вот простой пример:

#include <stdio.h>

// Define two global variables
int a = 10;
int b = 20;

void change1(int *x)
{
    x = &b;  // Make x point to b
}

void change2(int **x)
{
    *x = &b;  // Make *x point to b
}

int main(void)
{
    // Define a pointer variable, and make it point to the global variable a
    int *pointer_to_a = &a;

    // Will print the value of a, i.e. 10
    printf("*pointer_to_a = %d\n", *pointer_to_a);

    // Try to change where pointer_to_a is pointing
    change1(pointer_to_a);

    // Here pointer_to_a is *still* pointing to a, it wasn't changed, will print the value 10
    printf("*pointer_to_a = %d\n", *pointer_to_a);

    // Do another attempt to change where pointer_to_a is pointing
    change2(&pointer_to_a);

    // Now pointer_to_a is no longer pointing to a, it points to b and 20 will be printed
    printf("*pointer_to_a = %d\n", *pointer_to_a);
}

Возвращение к insert_at_head функция (о функциональности которой мы можем только догадываться) Я предполагаю, что она добавит в начало связанного списка. Это будет сделано путем изменения того, куда указывает заголовок списка.

Как видно из приведенного выше примера, если мы не передадим указатель на указатель, назначения заголовку будут потеряны после завершения функции. И это решается использованием указателя на указатель и передачей указателя заголовка с использованием оператора адреса & при вызове функции.

0 голосов
/ 20 февраля 2020

На языке C вы не можете передать переменную по ссылке.

Однако вы можете передать указатель в вашу переменную. Конечно, указатель передается по значению. Например, если вы объявляете переменную head, которая является указателем на структуру node:

struct node* head;

, вы можете подготовить функцию для работы с такой переменной:

void insert_at_head(struct node** ptr);

Затем вы вызываете его с помощью:

insert_at_head(&head);

, где оператор & выдает указатель на вашу переменную, то есть значение типа struct node **. Это значение передается вызываемому объекту.

Конечно, другая функция, скажем:

void append_at_end(struct node** ptr);

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

void append_at_end(struct node** ptr)
{
    if(*ptr == NULL)          /* list is empty */
        insert_at_head(ptr);  /* the same pointer to a head pointer */
    else {
        /* other stuff */
    }
}
0 голосов
/ 20 февраля 2020

Предполагая, что тип head равен struct node **, вы можете передать его непосредственно в функцию, ожидающую параметр этого типа.

&(*head) в точности совпадает с head. Когда операнд оператора & является результатом унарного оператора *, они взаимно отменяют друг друга, и ни один из них фактически не вычисляется.

Это прописано в разделе 6.5.3.2p3 * Стандарт 1026 *, относящийся к операторам адреса и косвенности:

Унарный оператор & возвращает адрес своего операнда. Если операнд имеет тип '' type '', результат имеет тип '' указатель на тип ''. Если операнд является результатом унарного оператора *, ни этот оператор, ни оператор & не оцениваются, и результат такой, как если бы оба опущены, за исключением того, что ограничения на операторы все еще применяются и результат не является lvalue.

Так что, если head является указателем, выражения head и &(*head) эквивалентны.

...