理解c中两个链表实现之间的区别

时间:2014-03-08 10:06:38

标签: c pointers

自从我开始学习数据结构一两个月后,使用C,我一直在遵循编写链表的特定方法。看起来像这样。

#include<stdio.h>
#include<stdlib.h>

struct Node{
    int exponent;
    int coeff;
    struct Node *next;
};

typedef struct Node N;
N *st = NULL;

void insert(N *node, int c, int e){
    N *temp;
    node->exponent = e;
    node->coeff = c;

    if(st == NULL){
        node->next = st;
        st = node;
    } else {
        temp = st;
        while(temp->next != NULL){
            temp = temp->next;
        }
        node->next = temp->next;
        temp->next = node;
    }
    printf(" %p", st); //this is written on purpose, not that i write it everytime
}

我从主方法中调用它,

N *node = malloc(sizeof *node);
insert(node, 1, 2);

四次此类调用的printf输出为 00340D18 00340D18 00340D18 00340D18

,即开始指针的值保持不变,但如果我在代码中进行了一些小改动

typedef struct Node N;

void insert(N *node, N *st, int c, int e){
    N *temp;
    node->exponent = e;
    node->coeff = c;

    if(st == NULL){
        node->next = st;
        st = node;
    } else {
        temp = st;
        while(temp->next != NULL){
            temp = temp->next;
        }
        node->next = temp->next;
        temp->next = node;
    }
    printf(" %p", st);
}

并在main方法中声明开始指针

N *strt = NULL;
node = malloc(sizeof *node);
insert(node, strt, 1, 1);

然后像前一种情况一样运行四次,启动指针的值会发生变化 每次通话后 00560D18 00560D30 00560D48 00560D60

为什么会这样? 如果我想将开始指针作为参数传递应该进行哪些更改?

2 个答案:

答案 0 :(得分:4)

  

为什么会这样?

这是因为对st的更改对调用方是不可见的。即st = node 对调用者没有任何影响。该函数更改自己的副本,在函数返回后,如果调用者打印strt,它仍然是NULL

这是一个有点微妙的结果,因为C参数是通过值传递的,甚至是指针。所以你按价值传递strt。您可以更改st->whatever,因为它是一个指针,更改将传播给调用方,但更改strt本身将无效。

  

如果我想将开始指针作为参数传递更改   应该制作

这是此网站上的常规问题,还有C FAQ来描述问题。你可以做的一个简单但有点麻烦的改变就是让函数占用一个 N **st并传递&strt

答案 1 :(得分:1)

这是因为strt方法中的main和修改后的函数st中的insert是两个不同的变量。函数调用

insert(node, strt, 1, 1);

strt中定义的main的值复制到函数参数st,这是一个不同的变量,并在函数insert为时在堆栈上分配调用。对st所做的任何更改在函数内部都是可见的,因为它是一个局部变量。一旦函数返回,它就会超出范围。因此,strt中定义的main仍然指向null并且永远不会更改。这意味着条件st == NULL始终为true,并且if中的insert块始终执行,并且每次函数时局部变量st都设置为新创建的节点调用insert。事实上,这会导致内存泄漏,因为一旦函数insert返回,您将丢失节点上的句柄。

您应该做的是将变量strt的地址传递给insert,以便在main中显示对其所做的更改。由于您始终将新节点附加到链接列表的末尾,因此我建议您进行一些更改。

void insert(N *node, N **st, int c, int e) {
    N *temp = *st;
    node->exponent = e;
    node->coeff = c;
    node->next = NULL;  // set it explicitly to NULL

    if(*st == NULL) {  // if head of the linked list is NULL
        *st = node;
    } 
    else {
        while(temp->next != NULL)  // reach the end of the linked list
            temp = temp->next;
        temp->next = node;   // add the new node at the end
    }
    printf("%p", *st);
}

main中,将函数调用为

// in main method

N *strt = NULL;
node = malloc(sizeof *node);
insert(node, &strt, 1, 1);