了解古代 C 中的动态分配

Understanding dynamic allocation in ancient C

如果您对动态内存分配不是很熟悉,可以将其视为脑筋急转弯。

首先将此代码作为 C 程序保存在您的 bin 目录中。

#include<stdio.h>
#include<conio.h>

struct node {
   int data;
   struct node *next;
} *head=NULL;

void ins_at_beg()
{
    struct node *node=malloc(4);
    node->next=head; head=node;
    printf("Please enter the value to be inserted at the start: ");
    scanf("%d",node); // POINT A
}

void ins_at_end()
{
    struct node *node=head;
    while(node->next) node=node->next;
    node->next=malloc(4);
    printf("Please enter the value to be inserted at the end: ");
    scanf("%d",node->next->data); // POINT B
}

void main()
{
    clrscr();
    ins_at_end();
    printf("%d",head->data);
    getch();
}

执行这段代码,一切都会好起来的。

现在程序执行完ins_at_end() main 函数到ins_at_beg() 并执行程序后,一切看起来还是不错的。

现在手动撤消上面的更改(将ins_at_beg更改为ins_at_end)并执行程序。现在你会得到 head->data 的值为 0.

现在只需将 'Point A' 的 node 更改为 node->data,您将看到输入的值反映在屏幕上(注意:我们没有调用它主函数中的函数)

现在再次反转上面的变化,得到0作为head->data的默认值。

这里要注意的主要事情是输出被一个刚定义的函数改变了,这个函数没有在主函数中调用。

玩一会你就会明白我想说什么了。

问题: 为什么当我将 node 更改为 node->data 时,程序可以正常运行,即使我实际上并没有调用我创建的函数主要功能有变化吗?

这个:

scanf("%d",node);

还有这个:

scanf("%d",node->next->data);

不正确。 %d 格式说明符需要一个 int * 作为参数。但是,您在一种情况下传递 struct node * 而在另一种情况下传递 int 。使用错误的 scanf 格式说明符会调用 undefined behavior,这就是您看到奇怪结果的原因。

你应该这样做:

scanf("%d",&node->data);

还有这个:

scanf("%d",&node->next->data);

此外,这对指针的大小进行了假设:

struct node *node=malloc(4);

你应该这样做:

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

你这里也有问题:

void ins_at_end()
{
    struct node *node=head;
    while(node->next) node=node->next;  //   <--- here
    node->next=malloc(4);
    printf("Please enter the value to be inserted at the end: ");
    scanf("%d",node->next->data); // POINT B
}

在程序启动时,head 为 NULL,因此您试图取消引用 NULL 指针,这再次导致未定义的行为。在您执行任何其他操作之前检查是否存在这种情况。此外,您应该将列表末尾的 next 指针显式设置为 NULL。

void ins_at_end()
{
    struct node *node=malloc(sizeof(*node));
    struct node *tmp;

    printf("Please enter the value to be inserted at the end: ");
    scanf("%d",&node->data);
    node->next = NULL;

    if (!head) {
        head = node;
    } else {
        tmp = head;
        while (tmp->next) tmp = tmp->next;
        tmp->next = node;
    }
}