Уточнение при передаче указателя по ссылке - PullRequest
0 голосов
/ 23 мая 2018

Это глупо, но я не могу объяснить, почему это происходит.В качестве упражнения я хотел отменить односвязный список и сделал это, определив метод:

class solution {
    void reverseLinkedList(Node*& head) {
      Node* curr = head;
      Node* prev = NULL;
      while (curr != NULL) {
        Node* _next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = _next;
      }
      head = prev;
}

В моей основной функции я выполняю вызов

solution s;
s.reverseLinkedList(head);

Node* iterator = head;
while (iterator != NULL) {
    std::cout<<iterator->data<<std::endl;
    iterator = iterator->next;
}

Где яранее определил мою голову указателем на какой-то связанный список.Цикл while предназначен для печати моего связного списка, и функция делает это.Это сработало только после того, как я передал головной узел по ссылке;Сначала я пытался передать Node * head вместо Node * & head в начале, и он печатал только первый элемент моего связного списка (и не обращая его вспять).Например, если бы я не прошел по ссылке для списка 1-> 2-> 3, я бы распечатал только 1.

Я думал, что передачи указателя будет достаточно?Почему я получил такое странное поведение, не передавая по ссылке>

Ответы [ 4 ]

0 голосов
/ 23 мая 2018

Локальные переменные в C ++ (хранящиеся в стеке) имеют область видимости блока, т. Е. Они выходят за пределы области видимости после выполнения блока, в котором они определены.

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

Когда вы передаете по ссылке, вы не передаете копию переменной, а передаете фактическую переменную, поэтому любые изменения, внесенные в переменную, отражаются на фактической переменной, переданной в функцию (ссылка).

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

  1. Использовать указатель на указатель, который указывает на область памяти, в которой хранится переменная (адрес) указателя для следующего узла
  2. Передайте это функции (не по ссылке)
  3. Разыменуйте указатель и сохраните новый адрес, на который вы хотите указать.

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

void addNode(Node** head, int newData)
{
    Node* newNode = new Node;
    newNode->data = newData; // Can also be done using (*newNode).data
    newNode->next = *head;
    *head = newNode;
}
0 голосов
/ 23 мая 2018

Я думал, что передачи указателя будет достаточно?

void reverseLinkedList(Node* head) // pass pointer by value
                                   // head is a copy here

Передача pointer по значению создает копию для использования внутри функции.

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

Как только pointer (копия) выходит из области видимости, эти изменения "отбрасываются""из-за конца жизни.

Таким образом, вам нужна ссылка.

void reverseLinkedList(Node&* head) // changes made in head will be
                                    // reflected in original head pointer
0 голосов
/ 23 мая 2018

In

void reverseLinkedList(Node* head)

Указатель передается по значению.

Звучит глупо, это чертов указатель, верно?Вид - определение передачи по ссылке.Ну, Node, то есть , указывающий на , передается по ссылке.Сам указатель , head - это просто еще одна переменная, которая содержит адрес какой-то другой переменной, и она не передается по ссылке.

Так что head содержит копию указателя Node, используемого для вызова reverseLinkedList, и, как и со всеми параметрами, передаваемыми по значению, любые изменения в копии, указывающие head где-то еще, не являютсяпредставлены в вызывающей функции.

0 голосов
/ 23 мая 2018

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

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

Например:

//WRONG does not modify the original pointer, causes memory-leak.
void init(Object* ptr, int sz) {
    ptr = new T[sz]; 
}

против

 //Correct original pointer is a set to a new block of memory
void init(Object*& ptr, int sz) {
    ptr = new T[sz]; 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...