所以我正在做这个双重链接列表代码,编译工作..但执行给了我SIGSEGV。当我尝试运行valgrind时,它说有一些未初始化的值。
我最好的猜测是,这种情况正在发生,因为malloc的内存范围达到或类似...... idk也许它会在函数结束时被抛弃?我不确定,但它仍然说有一些内存分配和可达...或者可能只有一些我不知道的语义错误:/
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) 更改/更新文件作为建议的答案
#ifndef CLEARLIST_H
#define CLEARLIST_H
#include "defs.h"
#include <stdlib.h>
int clearlist(node** head);
#endif
#ifndef POP_H
#define POP_H
#include "defs.h"
#include <stdlib.h>
int pop(node** head);
#endif
#ifndef PRINTLIST_H
#define PRINTLIST_H
#include "defs.h"
#include <stdlib.h>
#include <stdio.h>
int printlist(node* head);
#endif
#ifndef PUSH_H
#define PUSH_H
#include <stdlib.h>
#include "defs.h"
int push(node** head, int datainput);
#endif
#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
#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;
}
我将展示所涉及的功能,直到核心转储,我认为这些错误负责。
#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;
}
#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;
}
#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;
}
#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;
}
我真的不想要求一个完整的解决方案,我想学习新的东西,但我有点卡在这一个。 :)
答案 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
也不要忘记编写一个释放内存的函数。