Разница между struct * и struct ** в заголовке функции - PullRequest
1 голос
/ 10 апреля 2019

Я пытаюсь решить мою домашнюю работу на C, которая просит меня создать функцию, которая помещает значение char в правильное место в отсортированном связанном списке.на самом деле я не понимаю разницу в заголовке функции между struct typedef name *struct и struct typedef name **struct.

Когда я смотрю на решение моего учителя, она сделала это с ** и не понимаетсмысл этого.

void insert_in_sorted_list(Node *lst, char x) {
    Node *temp;
    while (lst) {
        if (x > lst->value && x < lst->next->value) {
            temp = (Node*)malloc(sizeof(Node));
            temp->value = x;
            temp->next = lst->next;
            lst->next = temp;
        }
        else lst = lst->next;
    }
}

Ответы [ 3 ]

0 голосов
/ 10 апреля 2019
  • struct - это объект данных, который где-то занимает память.
  • struct * - указатель на этот блок памяти
  • struct ** - указатель на указатель на этот блок памяти!(да, теперь это сбивает с толку)

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

Однако иногда структуры еще нет (потому что вы хотите создать ее в функции, например), такнет способа сообщить вызывающей стороне, где вы поместили эту новую структуру.Поэтому вы должны передать **, чтобы сказать: «Я создал эту структуру, и она здесь», а затем передать это местоположение вызывающей стороне.т. е. вы указываете на память, в которой создается структура, и передаете эту позицию обратно через трюк параметра «указатель на».

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

Указатели являются концептуально неуклюжими, ИМХО, лучший способ думать о них - это целочисленное значение, которое содержит область памяти (то, чем они на самом деле являются), а не пытаться понять ихкак некое абстрактное понятие.Это может помочь понять такие вещи, как производительность и копирование памяти.

0 голосов
/ 10 апреля 2019

Когда вы принимаете аргумент с *, вы фактически принимаете адрес к чему-либо (это называется указателем).Если вы принимаете аргумент с **, вы принимаете указатель на указатель.

Итак, это:

void insert_in_sorted_list(Node *lst, char x)

Принимает указатель на Node

и это:

void insert_in_sorted_list(Node **lst, char x)

принимает указатель на указатель на Node.

Ваша реализация будет работать, если у нас уже есть список, который мы не добавляем впередняя или задняя часть списка.Но подумайте, что может произойти, если вам нужно изменить первый элемент в списке.Если пользователь имеет указатель на первый узел в списке и передает его функции, а новый узел должен быть вставлен перед первым узлом, функция может правильно вставить его перед первым узлом, но когда пользователь смотритв списке после использования этой функции они по-прежнему будут иметь указатель на тот же Node (больше не должен быть первым) и не будут знать, что перед ним существует узел.Таким образом, пользователю необходимо будет передать указатель на указатель на первый узел, чтобы можно было изменить указатель на первый Node.

Обновление кода для принятия указателя на указатель на Node, теперь вам нужно получить доступ к указателю на узел с помощью *lst вместо просто lst

void insert_in_sorted_list(Node ** lst, char x)

Еще одна вещь, чтобы рассмотреть, что если у пользователя есть пустой список, ничего не будет вставлено.

Рассмотрим, что произойдет, если мы доберемся до последнего узла, т.е. lst->next равен NULL, когда мы попытаемся получить доступ к lst->next->value, у нас будет какое-то исключение NULL-указателя.Даже если мы не вставим этот код в конец другого узла?

0 голосов
/ 10 апреля 2019

Простой способ думать о том, что * <something> означает указатель на что-то, а '** `означает указатель на что-то.

Поскольку c передается по значению, единственный способ «изменить» параметр - передать на него указатель.

Так что функция с ** чем-то изменит то, на что указывает указатель в функции.

...