错误无法访问链接列表中地址的内存

时间:2017-06-06 13:57:05

标签: c

我正在使用一些插入函数创建链接列表。

这种方法很好用:

void insert_before(){
    struct node *new_node, *ptr, *preptr;
    int pivot;

    new_node = (struct node*)malloc(sizeof(struct node));
    ptr = link;
    preptr = link;

    printf("\n Enter the data : ");
    scanf("%d", &new_node->data);

    printf("\n Enter the value before which the data has to be inserted : ");
    scanf("%d", &pivot);

    while(ptr->data != pivot){
        preptr = ptr;
        ptr = ptr->next;
    }

    preptr->next = new_node;
    new_node->next = ptr;
}

但是,我在这个方法中得到了Cannot access memory at address 0x8

void insert_after(){
    struct node *new_node, *ptr, *preptr;
    int pivot;

    new_node = (struct node*)malloc(sizeof(struct node));
    ptr = link;
    preptr = link;

    printf("\n Enter the data : ");
    scanf("%d", &new_node->data);

    printf("\n Enter the value after which the data has to be inserted : ");
    scanf("%d", &pivot);

    while(preptr->data != pivot){
        preptr = ptr;
        ptr = ptr->next;
    }

    preptr->next = new_node;
    new_node->next = ptr;
}

请注意,这两种方法都使用相同的struct * link,唯一的区别在于循环while(preptr->data != pivot)

为什么第一个代码工作正常,但第二个代码坏了?

感谢您的帮助

PS:这是我的整个项目(非常简短),万一你需要它:https://pastebin.com/wsMEicGv

2 个答案:

答案 0 :(得分:3)

我不认为即使是第一种方法也能正常工作(简单证明:代码永远不会改变 $("#Order").data("kendoNumericTextBox").value(data); 的值,因此在第一个节点之前的插入不能工作)。

无论如何,当您为link输入的值与任何数据不匹配或与列表中的最后一个节点匹配时,您的代码将在这两个函数中产生上述错误消息:

pivot

原因是当条件while(preptr->data != pivot){ preptr = ptr; ptr = ptr->next; } 仍然访问此空指针时,上面的循环将到达列表的末尾(具有preptr = NULL)。我想成员preptr->data是你结构中的第二个(第一个是data),对吗?然后,您实际访问的next (NULL + sizeof(node*)) (NULL + 8)

答案 1 :(得分:1)

你有很多不好的做法:

  • 你毫无理由地使用全球!
  • 你没有理由使用全球!!
  • 你没有理由使用全球!!!
  • 你毫无理由地施放malloc()
  • 您不会检查scanf()malloc()等函数的返回值。
  • 您可以多次编写相同的功能。
  • fflush(stdin);是未定义的行为。
  • 您可以尽可能初始化变量。
  • 您在函数的开头声明所有变量。

例如,display()可能如下所示:

void display(struct node *head) { // no global it's better, isn't it ?
    printf("List:");
    while (head != NULL) {
        printf(" %d", head->data);
        head = head->next;
    }
    printf("\n");
}

此外,在您的create_ll()函数中,为什么不在之后使用插入开始和反转列表?

int create_ll(struct node **head) {
    *head = NULL;
    while (insert_beginning(head) != ERROR) {
    }
    return reverse_ll(head);
}

使用示例:

int main(void) {
    struct node *head;
    if (create_ll(&head) == ERROR) {
        return 1;
    }
    display(head);
    free_ll(head);
}

对于两个功能的问题,请阅读stephan-lechner的answer。但我举个例子:

int insert_after(struct node **head) {
    printf("\n Enter the data : ");
    int data;
    if (scanf("%d", &data) != 1) { // If the input has no been parse.
        // data is invalid here
        return ERROR;
    }
    // data is valid here

    printf("\n Enter the value after which the data has to be inserted : ");
    int pivot;
    if (scanf("%d", &pivot) != 1) {
        return ERROR;
    }

    for (struct node *node = *head; node != NULL; node = node->next) {
        if (node->data == pivot) {
            struct node *new_node = malloc(sizeof *new_node);
            if (new_node == NULL) {
                return ERROR;
            }
            new_node->data = data;
            new_node->next = node->next;
            node->next = new_node;

            return OK;
        }
    }
    return ERROR;
}

请注意:如果使用全局,则列表功能将为:

  1. 不是线程安全的。
  2. 仅适用于一个列表。
  3. 更多信息here