C链接列表 - 条件跳转或移动取决于未初始化的值链接列表

时间:2018-04-12 23:23:01

标签: c linked-list valgrind sigsegv

嘿伙计们,

所以我正在做这个双重链接列表代码,编译工作..但执行给了我SIGSEGV。当我尝试运行valgrind时,它说有一些未初始化的值。

我最好的猜测是,这种情况正在发生,因为malloc的内存范围达到或类似...... idk也许它会在函数结束时被抛弃?我不确定,但它仍然说有一些内存分配和可达...或者可能只有一些我不知道的语义错误:/

valgrind --track-originins = yes out:

Conditional jump or move depends on uninitialised value(s)
==14798==    at 0x400848: push (in /home/mename/linkedlist/llist)
==14798==    by 0x40088E: main (in /home/mename/linkedlist/llist)
==14798==  Uninitialised value was created by a heap allocation
==14798==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14798==    by 0x400879: main (in /home/mename/linkedlist/llist)

==14798== Use of uninitialised value of size 8
==14798==    at 0x4E8476B: _itoa_word (_itoa.c:179)
==14798==    by 0x4E8812C: vfprintf (vfprintf.c:1631)
==14798==    by 0x4E8F898: printf (printf.c:33)
==14798==    by 0x400793: printlist (in /home/mename/linkedlist/llist)
==14798==    by 0x4008CD: main (in /home/mename/linkedlist/llist)
==14798==  Uninitialised value was created by a heap allocation
==14798==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14798==    by 0x400879: main (in /home/mename/linkedlist/llist)

==14798== Invalid write of size 8
==14798==    at 0x40071B: pop (in /home/mename/linkedlist/llist)
==14798==    by 0x4008D9: main (in /home/mename/linkedlist/llist)
==14798==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

==14798== Process terminating with default action of signal 11 (SIGSEGV)
==14798==  Access not within mapped region at address 0x0
==14798==    at 0x40071B: pop (in /home/mename/linkedlist/llist)
==14798==    by 0x4008D9: main (in /home/mename/linkedlist/llist)
==14798==  The main thread stack size used in this run was 8388608.
0 -> 0 -> 0 -> 0 -> 0==14798== 
==14798== HEAP SUMMARY:
==14798==     in use at exit: 96 bytes in 4 blocks
==14798==   total heap usage: 6 allocs, 2 frees, 1,144 bytes allocated
==14798== 
==14798== LEAK SUMMARY:
==14798==    definitely lost: 0 bytes in 0 blocks
==14798==    indirectly lost: 0 bytes in 0 blocks
==14798==      possibly lost: 0 bytes in 0 blocks
==14798==    still reachable: 96 bytes in 4 blocks
==14798==         suppressed: 0 bytes in 0 blocks

编辑:

添加了其他功能及其库(pop; clearlist; * .h) 更改/更新文件作为建议的答案

clearlist.h

#ifndef CLEARLIST_H
#define CLEARLIST_H

#include "defs.h"
#include <stdlib.h>

int clearlist(node** head);

#endif

pop.h

#ifndef POP_H
#define POP_H
#include "defs.h"
#include <stdlib.h>

int pop(node** head);

#endif

printlist.h

#ifndef PRINTLIST_H
#define PRINTLIST_H

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

int printlist(node* head);

#endif

push.h

#ifndef PUSH_H
#define PUSH_H
#include <stdlib.h>
#include "defs.h"

int push(node** head, int datainput);

#endif

的defs.h

#ifndef DEFS_H
#define DEFS_H

#define SUCCESS 0
#define FAIL -1
#define TRUE 0
#define FALSE -1
#define ALLOCFAIL -2
#define EMPTY -3

typedef struct Node{
    struct Node* next;
    struct Node* prev;
    int data;
} node;
#endif

的main.c

#include "defs.h"
#include "clearlist.h"
#include "pop.h"
#include "printlist.h"
#include "push.h"

int main(){
    node *head;
    head = (node*) malloc(sizeof(node));

    push(&head, 10);    
    push(&head, 20);    
    push(&head, 30);    
    push(&head, 40);    

    printlist(head);

    pop(&head);

    printlist(head);

    clearlist(&head);

    return SUCCESS;
}

我将展示所涉及的功能,直到核心转储,我认为这些错误负责。

push.c

#include "push.h"

int push(node** head, int datainput){

    /* Initialization of new node */
    node* newptr = (node*) malloc(sizeof(node));    
    if(newptr == NULL){
        return ALLOCFAIL;
    }
    newptr->next = NULL;
    newptr->data = datainput;

    /* Check for empty list */
    if(head == NULL){
        newptr->prev = NULL;
        *head = newptr;
        return SUCCESS;
    }

    /* Get to the end of list*/
    node* headptr = *head;
    while(headptr->next != NULL){
        headptr = headptr->next;        
    }

    headptr->next = newptr;
    newptr->prev = headptr;
    return SUCCESS;
 }

printlist.c

#include "printlist.h"

int printlist(node* head){
    /* Check if valid node or empty list */
    if(head == NULL){
        return EMPTY;
    }

    /* Move to first node if not already */
    node* firstptr = head;
    while(firstptr->prev != NULL){
        firstptr = firstptr->prev;
    }

    /* Print entire list*/
    while(firstptr != NULL){
        if(firstptr->next != NULL){
            printf("%d -> ", firstptr->data);
        }
        else{
            printf("%d", firstptr-->data);
        }
        firstptr = firstptr->next;
    }

    return SUCCESS;
}

pop.c

#include "defs.h"
#include "pop.h"
#include <stdio.h>

int pop(node** head){

    /* If no node to pop */
    if(*head == NULL){
        return EMPTY;
    }
    /* Get to the end of list */
    node* headptr = *head;
    while(headptr->next != NULL){
        headptr = headptr->next;        
    }
    /*Pop last*/ 
    node* temp = headptr->prev;
    free(headptr);

    /* po temp - Check if deleted the only node left*/
    if(temp = NULL){
        *head = NULL;
        return EMPTY;
    }
    /* ...if not, make previous node the last node  */

    temp->next = NULL;
    headptr = NULL;

    return SUCCESS; 
}

clearlist.c

#include "clearlist.h"

int clearlist(node** head){
    if(*head == NULL){
        return SUCCESS;
    }

    /* Go to start */
    while((*head)->prev != NULL){
        *head = (*head)->prev;
    }
    /* Delete to the end */
    while(*head != NULL){
        node *prevnode = *head;
        *head = (*head)->next;
        free(prevnode);
    }

    return SUCCESS;
}

感谢您的帮助!

我真的不想要求一个完整的解决方案,我想学习新的东西,但我有点卡在这一个。 :)

2 个答案:

答案 0 :(得分:3)

问题是malloc ing不会初始化任何内容,例如:

node *head;
head = (node*) malloc(sizeof(node));

节点的值可以是任何值,您需要将指针设置为NULL

head->prev = head->next = NULL;

此外,您应该在一行上声明和初始化节点,并且不要转换malloc的结果,我还建议使用其他sizeof机制。如果你在C99或更高版本中使用复合文字

,有一种更健全的方法可以对node中的所有内容进行零初始化
node* head = malloc(sizeof *head);
*head = (node){0};

仔细查看其余代码,如果这是同样的问题,我不肯定,但为了您自己的安全,您应该遵循上述模式。

答案 1 :(得分:2)

问题在于:

int main(){
    node *head;
    head = (node*) malloc(sizeof(node));

    push(head, 10);

    ...

}

head仅被分配,未初始化!

将未初始化的指针传递给push时,

 if(head == NULL)

将为false,并且不会执行该块,但是下一个块

node* headptr = head;
while(headptr->next != NULL){
    headptr = headptr->next;        
}

已执行。 Remeber head未初始化,因此headptr->next指向 无处,你分配headptr = heatdptr->next等等。 Valgrind告诉你这个:未初始化的值是由堆分配创建的

push函数应该使用指向head的双指针并更改它的位置 指向何时创建新头:

int push(node **head, int datainput){
   /* Initialization of new node */
   node* newptr = (node*) malloc(sizeof(node));    
   if(newptr == NULL){
       return ALLOCFAIL;
   }
   newptr->next = NULL;
   newptr->data = datainput;

   /* Check for empty list */
   if(*head == NULL){
       newptr->prev = NULL;
       *head = newptr; // change where head is pointing to
       return SUCCESS;
   }

   /* Get to the end of list*/
   node* headptr = *head;
   while(headptr->next != NULL){
       headptr = headptr->next;        
   }

   headptr->next = newptr;
   newptr->prev = headptr;
   return SUCCESS;
}

然后你可以这样称呼它:

int main(){
    node *head = NULL; // <-- important initialization

    push(&head, 10);
    push(&head, 20);
    ...
}

另请注意:don't cast malloc

修改

printlist还有一个小错误,你只打印头部, 正确的版本应该是

int printlist(node* head){
    /* Check if valid node or empty list */
    if(head == NULL){
        return EMPTY;
    }

    /* Move to first node if not already */
    node* firstptr = head;
    while(firstptr->prev != NULL){
        firstptr = firstptr->prev;
    }

    /* Print entire list*/
    while(firstptr != NULL){
        if(firstptr->next != NULL){
            printf("%d -> ", firstptr->data);
        }
        else{
            printf("%d", firstptr->data);
        }
        firstptr = firstptr->next;
    }

    puts("");

    return SUCCESS;
}

请注意,C没有按引用传递,因此如果要修改值 在其他函数中,您传递一个指向该变量的指针:

void foo(int *p)
{
    *p = 8;
}

void bar(void)
{
    int c = 4;

    foo(&c);

    // c is now 8
}

如果你想改变指针指向的位置,这同样适用于指针 在另一个函数中,你必须将指针传递给指针(也就是双精度) 指针):

void foo(char **str)
{
    *str = "World";
}

void bar(void)
{
    char *x = "Hello";
    puts(x); // prints Hello

    foo(&x);

    // x points now to a different string literal

    puts(x); // print World
}

这就是我在push中所做的事情。

要证明这是正确的,请参阅:https://ideone.com/As5XDy

我使用了我的push功能(以及printlist的修正),输出是

10 -> 20 -> 30 -> 40

也不要忘记编写一个释放内存的函数。