将节点插入链表

时间:2019-07-13 19:53:05

标签: c pointers linked-list

我是C语言的新手,但我一直将插入函数卡在链表中。当我尝试打印列表时。结果不是我期望的。我知道它与指针有关,但是我无法理解。我在这里做什么错了?

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

typedef struct CELL_NODE CellNode;
struct CELL_NODE {
    int row;
    int column;
    CellNode *next;
};

struct LinkedList {
    CellNode *head;
};
typedef struct LinkedList LinkedList;

void printList(LinkedList *myList) {
    CellNode *curr = (*myList).head;
    if (curr != NULL) {
        printf("(%d,%d)", (*curr).row, (*curr).column); 
        if ((*curr).next != NULL) {
            curr = (*curr).next;
            printf(" - (%d,%d)", (*curr).row, (*curr).column);
        }
    } else {
        printf("The list is empty");
    }
    printf("\n");
}

void insert(LinkedList *myList, CellNode *node) {
    CellNode *ref = (*myList).head;
    if (ref == NULL) {
        (*myList).head = node;
    } else {
        while ((*ref).next != NULL) {
            ref = (*ref).next;
        }
        (*ref).next = node;
    }
}

int main(int argc, char *argv[]) {
    LinkedList myList = { NULL };
    for (int k = 0; k < 2; k++) {
        CellNode myNode = { 1, k, NULL };
        insert(&myList, &myNode);
        printList(&myList);
        printf("\n");
    }
    return 1;
}

我得到的结果是:

(1,0)
(1,1) - (1,1)

我期望:

(1,0)
(1,0) - (1,1)

3 个答案:

答案 0 :(得分:1)

您应该首先将(*x).y的每个实例更改为x->y,以使代码更具可读性。

然后,看下面的代码:

int main(int argc, char *argv[])
{
    LinkedList myList = {NULL};
    for(int k = 0 ; k<2 ; k++) {
        CellNode myNode = {1,k,NULL};
        insert(&myList,&myNode);
        printList(&myList);
        printf("\n");
    }
    return 1;
}

您将myNode创建为for循环内的局部变量。这意味着循环的每次迭代都会获得myNode的新实例,从而破坏前一个实例。因此,您已经通过指针将myNode连接到链接列表,然后下次通过for循环将其销毁。

如果要让一段代码隐藏指向某个对象的指针,则必须确保该对象保持有效,直到不再有可能取消引用那些指针为止。

您需要做出决定-链表包含指向的对象将拥有?那一辈子什么时候结束?当它们结束时,什么将摧毁它们?

您尚未执行此操作。因此,您的对象的生命周期结束得太早。

答案 1 :(得分:1)

使用

 CellNode myNode = {1,k,NULL};
 insert(&myList,&myNode);

您正在传递一个指向局部变量的指针。该变量的生命期与循环的相应迭代一样长,即在第二次迭代中,第一次迭代的对象不在范围内。因此,您将访问一个生命周期已由您存储在列表中的指针结束的对象。这会产生不确定的行为。

使用动态生成的对象代替(并且不要忘记稍后释放它们):

CellNode *myNode = malloc(sizeof(CellNode));
myNode->row = ...

答案 2 :(得分:0)

您反复从立即超出范围的局部变量中将节点插入到链表中。该行为是不确定的,您的程序可能会以许多无法预测的方式失败。

您应该这样修改代码:

  • 更改insert函数以将元素数据作为参数并使用malloc()分配一个新节点。
  • 使printList()打印完整列表,而不仅仅是前几个单元格。
  • 将笨拙的(*pointer).member表示法更改为等效但更惯用的pointer->member表示法。
  • 0返回main,以成功进行操作。

这是修改后的版本:

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

typedef struct CellNode CellNode;
struct CellNode {
    int row;
    int column;
    CellNode *next;
};

typedef struct LinkedList LinkedList;
struct LinkedList {
    CellNode *head;
};

void printList(LinkedList *myList) {
    CellNode *curr = myList->head;
    if (curr != NULL) {
        printf("(%d,%d)", curr->row, curr->column); 
        while (curr->next != NULL) {
            curr = curr->next;
            printf(" - (%d,%d)", curr->row, curr->column);
        }
    } else {
        printf("The list is empty");
    }
    printf("\n");
}

CellNode *insert(LinkedList *myList, int row, int column) {
    CellNode *node = malloc(sizeof(*node));
    CellNode *ref = myList->head;

    if (node != NULL) {
        if (ref == NULL) {
            myList->head = node;
        } else {
            while (ref->next != NULL) {
                ref = ref->next;
            }
            ref->next = node;
        }
    }
    return node;  // return node pointer to allow the caller to detect out of memory error
}

int main(int argc, char *argv[]) {
    LinkedList myList = { NULL };
    CellNode *node;

    for (int k = 0; k < 2; k++) {
        insert(&myList, 1, k);
        printList(&myList);
        printf("\n");
    }
    // free the nodes
    while ((node = myList->head) != NULL) {
        myList->head = node->next;
        free(node);
    }
    return 0;
}