2011-03-07 98 views
1

我正在学习链接列表操作并且有一个与参数传递有关的问题。链接列表引用指针

问题1: 我正在用三个值1-> 2-> 3创建一个简单的链表。我试图打印它。 以下是我的代码。我在我的main中创建一个节点“first”,并将它传递给“createlinkedlist”方法。我正在使用一个指针“头”并在方法中更新它。但是我发现在“createlinkedlist”方法之外正确保留了“head”的值。我不明白这是怎么发生的。我想我应该使用的借鉴参数传递喜欢

void createLinkedList(struct node * & head)void createLinkedList(struct node ** head)

,而不是

void createLinkedList(struct node * head) 

以获得正确的价值观体现在函数外。我在这里错过了什么?为什么我能够在printList方法内看到正确的值?

struct node 
{ 
    int data; 
    struct node * next; 

}; 

void createLinkedList(struct node * head) 
{ 

    struct node * second = (node *)malloc(sizeof(node)); 
    struct node * third = (node *)malloc(sizeof(node)); 

    head->data = 1; 
    head->next = second; 

    second->data = 2; 
    second->next = third; 

    third->data = 3; 
    third->next = NULL; 

} 

void printList(struct node * first) 
{ 
struct node * current = first; 
while(current) 
{ 
printf("%d",current->data); 
current = current->next; 
} 
} 
void main() 
{ 
    struct node * first = (node *)(malloc(sizeof(node))); 
    createLinkedList(first); 
    printList(first); 
} 

问题2:我使用的是同一个程序同上,但加入了推送功能

void push(struct node *& first, int data) 
{ 
    struct node * newnode = (node*)malloc(sizeof(node)); 
    newnode->data = data; 
    newnode->next = first; 
    first = newnode; 
} 

现在我明白了,除非我用的是“&”在推的第一个参数( ),我无法在printList方法中看到更新。这对我来说很有意义,因为我们通常需要使用参考参数来使得在函数外部看到的局部功能改变。所以如果列表需要一个参考参数,为什么它在问题1中的行为不同。 请致电让我知道。

+1

语言? C还是C++? – duffymo 2011-03-07 20:46:30

+0

*和&取消。它本质上意味着[struct node head] – rkg 2011-03-07 20:48:00

+1

@Ravi:我不认为这是一个声明的情况。 – Lars 2011-03-07 20:54:34

回答

0

既然你是在谈论引用我假设你正在使用C++。

你想在struct node *& head传递,如果你要去指针修改head,但在你的例子中,你希望只修改头节点本身,而不是指向它,这是为什么你只是传递一个指针来让你查找地址。当你通过取消引用的head->...指针,你正在寻找起来head在内存中的位置,然后移动到其datanext场。或者,你可以在头通作为参考struct node & head,并修改之类的东西head.data直接。

push需要有一张参考first指针struct node *& first),或指针first指针struct node **first),这样你实际上可以修改pointer itself。这是发生了什么事就行了:

first = newnode; 

另外,如果你使用的struct node **first,你会怎么做:

*first = newnode; 

这里push了这两种情况修改指针struct node,而不是修改一个struct node本身。

+0

很多人。它有很大的帮助!我thk我现在得到它。 – user457660 2011-03-08 00:18:17

2

关于问题1)

你不改变指针头在你的createLinkedList方法;您正在更改头指向的节点的内容。所以你当然会在调用createLinkedList之后看到这种改变。

对于问题2)

在第二种情况下,你实际上是添加新节点,你需要改变头指针指向链表的新负责人,而在第一种情况下,你保持列表头部稳定,并将新节点添加到列表的尾部。所以你不需要把列表头的新地址返回给调用者,因为头的地址没有改变。

我还要创建一个节点构造函数:

 
struct node * make_node(int data) 
{ 
    struct node * tmp = (node *)malloc(sizeof(node)); 
    if (!tmp) { 
    /* error handling for malloc failure */ 
    } 
    tmp->next = NULL; 
    tmp->data = data; 
    return tmp; 
} 

另一点:

如果我是你,如果我写的添加节点列表的头推功能,我会明确地返回列表的新掌门人:

 
struct node * push(const struct node * head, int data) { 
    struct node * fresh = make_node(data) 
    fresh->next = head; 
    return fresh; 
} 

调用此像这样:

 
struct node * head = make_node(1); 
head = push(head, 2); 

这比理解推动(头部,1)改变头部更容易理解。但这是一个风格问题。

+0

是的,我同意你的观点,JeSuisse更容易理解,而不必处理文献。参数,但是我在链表上看到的大部分书籍和链接都是在ref中实现的。参数。所以这让我想到,从内存和空间利用率以及性能角度来看,这是否是非常有效的方式。 – user457660 2011-03-08 00:17:08

+0

关于问题1.在做一些研究之后,我的理解是,“第一”和“头”都只是复制其指向同一个内存位置。所以当我修改其中一个时,变化应该反映到另一个上。 – user457660 2011-03-08 07:12:15

+0

Reg。引用与返回值:实际上引用*的效率更高一些,因为编译器不需要将返回值复制到头变量中,但这是按照几条机器指令的顺序排列的,这些指令可以忽略不计。 – JeSuisse 2011-03-08 11:09:25

1

变化

struct node * first = (node *)(malloc(sizeof(node))); 
struct node * second = (node *)(malloc(sizeof(node))); 
struct node * third = (node *)(malloc(sizeof(node))); 

部分

struct node * first = (struct node *)(malloc(sizeof(struct node))); 
struct node * second = (struct node *)(malloc(sizeof(struct node))); 
struct node * third = (struct node *)(malloc(sizeof(struct node))); 

。由于您在没有“typedef”的情况下初始化“节点”,因此每次使用“节点”之前都需要写入“struct”。