了解古代 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;
}
}
如果您对动态内存分配不是很熟悉,可以将其视为脑筋急转弯。
首先将此代码作为 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;
}
}