Can';t向单向简单列表中添加元素

Can';t向单向简单列表中添加元素,c,list,C,List,我不是在问效率、进一步列出可访问性或缺少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=

我不是在问效率、进一步列出可访问性或缺少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;
}
#包括
类型定义结构a
{
a*nast;
双v;
};
空添加(结构a*列表,双d)
{
列表=(a*)malloc(sizeof(a));
如果(!list->nast)转到异常;
列表=列表->nast;
列表->v=d;
返回;
例外情况:
printf(“无法添加到列表\n”);
}
int main()
{
结构a l;
添加(&l,-602.1);
返回0;
}
问题是:为什么它会抛出

list.exe中0x000000013f84107a处的未处理异常: 0xC0000005:访问冲突读取位置0xFFFFFFFFFFFFFF


运行时错误以及如何修复它?

此代码需要大量工作。但是,由于这一行,您会得到一个异常:

如果(!list->nast)转到异常

malloc
不会将分配的内存归零。您分配了一个新的列表结构,但由于它没有归零,所以它的
nast
指针包含垃圾。上述检查失败,在下一行中,您取消引用此垃圾并获得异常


但实际上,即使你修复了它,这段代码也需要工作。

因为你的
list=list->nast让列表为空

这段代码有太多的问题,所以我认为您最好多读一些关于指针和参数传递的内容。然而,这里有几件事:

  • 当您在
    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);
此函数的调用方式如下:

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

  • 就在这里:
    list=(a*)malloc(sizeof(a))你损失惨重。您已将现有列表(如果有的话)放到地板上,无法将其取回。坐下来好好想一想,直到你明白为什么它不好。然后您就可以再试一次了。通常最好更清楚地说明类型和变量,在您的示例中,您使用“a”作为结构名和变量名,如果您在更大的模块中发现这样的代码,这会让人感到困惑。这是真的,但忽略了前面出现的错误的破坏因素。什么错误,重新分配列表?这是一个错误,但不是导致异常的错误。它不会导致异常,但它确实会使代码彻底崩溃。当你仍然有那么大的逻辑错误时,试图修复这个异常是没有意义的。公平地说,这是goto的少数几个用途之一,可以找到一些捍卫者。尽管如此,在OP能够在他或她的睡眠中无错误地编写这种代码之前,您可能是对的。