2015-05-08 2 views
0

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

Эта проблема заключается в том, чтобы написать реализацию функции PushBack() в соответствии с ее вызовом в основном корпусе. Поэтому мой вопрос касается функции PushBack().

#include <iostream> 

class Node{ 
public: 
    static Node* MakeNode() { return new Node(100); } 
    Node* prev; 
    Node* next; 
    int value; 
private: 
    Node(int num) : value(num), prev(NULL), next(NULL) {} 
}; 

void PushBack(Node* simple, Node* newNode){ 
    if (simple == NULL){ 
     //still a empty list 
     simple = newNode; 
     } 
    else{ 
    //need to loop to the end of list because there is no "tail" in the class 
    Node* itr = simple; 
    while (itr->next != NULL){ 
     itr = itr->next; 
    } 
    newNode->prev = itr; 
    itr->next = newNode; 
} 
return; 
} 

int main() 
{ 
    Node* simple = NULL; 
    PushBack(simple, Node::MakeNode()); 
    std::cout << (simple == NULL); 
    PushBack(simple, Node::MakeNode()); 
    PushBack(simple, Node::MakeNode()); 
    PushBack(simple, Node::MakeNode()); 
    while (simple != NULL){ 
     std::cout << simple->value << std::endl; 
     simple = simple->next; 
    } 
    return 0; 
} 

У меня есть два вопроса о типе аргумента функции PushBack():

  1. возвращаемый тип MakeNode() является static Node*, но почему мы должны установить второй тип аргумента в PushBack() в Node*? почему не static Node *?

  2. В начале я пытался void PushBack(Node* simple, Node* newNode), но когда до завершения программы и выхода из PushBack(), simple становится NULL снова. Таким образом, новые элементы не могут быть добавлены в список. Я должен использовать void PushBack(Node*& simple, Node* newNode).

Зачем нужен символ &? Я думаю, что если я передам значение указателя в функцию, простой указатель можно изменить напрямую. Но, похоже, это не так.

В чем разница между моей проблемой и этим сегментом :?

void changeVal(int* data){ 
    for (int i = 0; i < 9; i++) 
     *(data + i) = 99; 
    } 
void main() 
{ 
    int *data; 
    data = new int[10]; 
    changeVal(data); 
    for (int i = 0; i < 9; i++) 
     std::cout << data[i] << std::endl; 
} 

Я передал указатель data в changeVal(), а содержание может быть изменено внутри функции. Я не совсем понимаю разницу между ними.

Мне не удалось найти полезное объяснение в Интернете, поэтому я прошу здесь.

ответ

2
  1. Нет, возвращаемый тип MakeNode() является Node*. Вы можете объявить метод класса как static, чтобы вы могли вызвать метод без необходимости использования экземпляра класса заранее, вы вызываете метод в самом типе класса. static в этом случае не является частью возвращаемого значения, он является частью самого метода класса. Что касается PushBack(), нет такой функции, как параметр функции static. Функция действует на конкретный экземпляр класса Node, поэтому он является просто регулярным указателем.

  2. При объявлении параметра simple в Node*, вы передаете ваш Node* переменная значением. Параметр получает локальную копию текущего значения переменной Node*. Все, что функция делает для чтения или изменения значения параметра, выполняется с использованием этого копия, а не оригинал переменная. Вот почему ваша переменная simple в main() не изменилась, когда PushBack() вышел.

    С другой стороны, при объявлении параметра simple в Node*&, вы передаете ваш Node* переменная по ссылке. Параметр получает адрес памяти оригинальной переменной Node*. Все, что функция делает для чтения или изменения значения параметра, выполняется с использованием переменной , а не копия. Вот почему ваша переменная simple в main() менялась при выходе PushBack().

ссылка является по существу указателем компилятор управляемого. Никогда не может быть установлено значение NULL, и оно автоматически разыгрывается всякий раз, когда вы читаете/записываете значение из/в него. Итак, если вы думаете о ссылке как неявный указатель, PushBack(Node*&) это функциональность эквивалентна PushBack(Node**) (с дополнительной проверкой компилятором), похожее на следующее:

void PushBack(Node** simple, Node* newNode){ 
    if (*simple == NULL){ 
     //still a empty list 
     *simple = newNode; 
    } 
    else{ 
     //need to loop to the end of list because there is no "tail" in the class 
     Node* itr = *simple; 
     while (itr->next != NULL){ 
      itr = itr->next; 
     } 
     newNode->prev = itr; 
     itr->next = newNode; 
    } 
    return; 
} 

PushBack(&simple, ...); 
+0

1. Вы можете полностью иметь параметры статической функции (в VC++) и 2. Это довольно запутанно. Функция может получить _copy_, но эта копия по-прежнему является точным адресом памяти объекта Node, который был передан, поэтому вы все равно можете изменять данные по адресу памяти, но не там, где указывает Node *. –

+1

Где VC++ определяет параметры статической функции? 'static' не является допустимым модификатором параметра. –

+1

Когда вы передаете переменную-указатель * по значению *, вы передаете ее значение, то есть адрес памяти объекта, на который указывает. Он НЕ передает адрес памяти самой указательной переменной. Вы получите это, когда вместо этого передаете указатель * по ссылке *. –

1

Вам нужно передать указатель а не только указатель, так что адрес, указанный простым, может быть изменен внутри функции PushBack.

Это определение от MSDN.

Ссылки на указатели могут быть объявлены так же, как ссылки на объекты. Объявление ссылки на указатель дает модифицируемое значение , которое используется как обычный указатель.

Позвольте мне создать простой пример:

Адрес | Значение

[0001]-> 
[0002]-> 
[0003]-> 
[0004]-> 
...... 
[nnnn]-> 

При запуске программы вы имеете переменную простой указывающей на NULL:

[0001]->NULL 
[0002] 
[0003] 
[0004] 
...... 
[nnnn] 

При вызове PushBack firstime вы просто проездом значение указал простой переменной, которая просто NULL.

[0001]->NULL 

Когда вы измените его значение внутри функции PushBack, вы просто изменения локальной копии этой функции, а не фактический указатель простой переменной. После того, как ваш вызов PushBack завершен, ваша простая переменная по-прежнему указывает на NULL.

Теперь, когда вы передаете ссылочный указатель, вы передаете изменяемое значение простой переменной, используемой в качестве указателя. Когда вы меняете значение указателя, вы также меняете значение, указанное фактической простой переменной. После того, как PushBack вызывается с использованием ссылки на указатель, простая переменная будет теперь указывать на адрес нового экземпляра, возвращаемого MakeNode.

[0001]->newNode 
[0002] 
[0003] 
[0004] 
...... 
[nnnn] 
+0

Привет, христианин, Большое спасибо за ваш ответ. Я попытался это понять, но у меня все еще есть путаница. Я думаю, что адрес памяти был передан в функцию, поэтому я думаю, что операция может напрямую влиять на исходное значение ... Почему это локальная копия? Я добавил новый сегмент кода в исходную проблему. В чем разница между этими двумя? Большое спасибо! – Andrinux

+0

Это хорошая ссылка с иллюстрациями: https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp4_PointerReference.html –

+0

Спасибо большое! Я очень благодарен. :) – Andrinux