如果不需要此程序的关键错误流程,我不会询问效率,进一步列出可访问性或缺少free()函数:
#include <stdlib.h>
typedef struct a
{
a * nast;
double v;
};
void add(struct a* list,double d)
{
list = (a*)malloc(sizeof(a));
if(!list->nast) goto exception;
list=list->nast;
list->v=d;
return;
exception:
printf("Cannot add to the list \n");
}
int main()
{
struct a l;
add(&l,-602.1);
return 0;
}
问题是:为什么抛出
list.exe中0x000000013f84107a处的未处理异常: 0xC0000005:访问冲突读取位置0xffffffffffffffff。
运行时错误以及如何修复它?
答案 0 :(得分:2)
这段代码有很多问题,我认为你更多地了解指针和参数传递会更好。但是这里有一些事情:
当您在main
函数中声明“list”时,它已经在堆栈中分配。然后,您尝试在add
函数中重新分配它。
如果要在add
函数中分配节点,则需要通过引用传递指针,即指向指针的指针。这是因为否则指针按值传递,并且当函数返回时,对它的所有更改(即实际指针,而不是它指向的指针)都将丢失。
malloc
函数不会清除已分配的内存。如果您希望自动执行此操作,则应使用calloc
功能。
您没有将节点链接到列表中,只需使用(未初始化的)nast
指针覆盖列表头。
您在结构中使用typedef
,但实际上并未为此typedef
定义名称。
请哦,请不要使用goto
!它可以使您的代码非常难以阅读和遵循,如果习惯了很多(并且很多人会争辩说即使使用过一次也是如此)。
如果我这样做,我会让我的add
函数将一个指针引用作为参数,以及要添加到列表中的值。然后,我将为该值分配一个新节点,并通过使next
指针指向旧列表将其链接到列表中,然后重新分配列表指针以指向新节点。如果传递的列表是NULL
,那么只需使列表指向新节点。
这样的事情:
struct node
{
struct node *next;
double value;
};
void add(struct node **l, const double value)
{
/* Allocate a new node, use `calloc` to clear the memory automatically */
struct node *n = calloc(1, sizeof(struct node));
/* Set the value of the new node */
n->value = value;
/* Is the list non-null? */
if (*l != NULL)
{
/* Yes, make the `next` pointer point to the old list */
n->next = *l;
}
/* Make the list point to the new node */
*l = n;
}
可以像这样调用此函数:
/* Initialize to `NULL` to mark the list as empty */
struct node *list = NULL;
/* Add two nodes, passing the list pointer by reference */
add(&list, 12.34);
add(&list, 56.78);
该列表现在有两个节点:
56.78
12.34
答案 1 :(得分:0)
这段代码需要做很多工作。但是,由于这一行,你得到一个例外:
if(!list->nast) goto exception;
malloc
不会将其分配的内存清零。您分配了一个新的列表结构,但由于它没有归零,它的nast
指针会保留垃圾。上面的检查失败了,在下一行你不引用这个垃圾并获得异常。
但实际上,即使你修复它,这段代码也需要工作。
答案 2 :(得分:0)
因为您的list=list->nast;
让列表为空。