提问人:Andy Nguyen 提问时间:2/17/2023 最后编辑:chqrlieAndy Nguyen 更新时间:2/19/2023 访问量:54
在 C 中迭代链接列表时,Null-check 行为不正确
Null-check behaves incorrectly when iterating linked-list in C
问:
我正在尝试通过编写一个程序来学习 C 基础知识,该程序提示用户输入整数,然后将值存储在链表中。如果输入等于或低于,则节点设置为 并且提示结束。然后,程序遍历列表并计算输入值的平均值。但是,列表的计数器最终总是比预期多一个元素,因此会导致不正确的平均值,尽管我在添加每个值和增量计数器之前显式指定了检查。-128
current
NULL
NULL
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main()
{
struct record {
int temperature;
struct record *next;
};
// Keep hold of the first record for iterating --v
struct record *first = NULL;
first = (struct record *)malloc(sizeof(struct record));
// Keep hold of the current record used in the while loop --v
struct record *current = first;
while (true) {
// Get user input --v
int temp;
printf("Enter measurement: ");
scanf("%d", &temp);
// If input is less than -128, end the loop --v
if (temp <= -128) {
current = NULL;
break;
}
// Record the temperature --v
current->temperature = temp;
// Allocate memory for the next record --v
current->next = (struct record *)malloc(sizeof(struct record));
// The next now becomes the current because we are done with the current --v
current = current->next;
printf("Next record created!\n");
}
// Calculate average --v
current = first;
double sum = 0.;
int count = 0;
// As long as the record is not NULL --v
while (current != NULL) {
sum += current->temperature;
count++;
printf("%d %d\n", count, current->temperature);
// Move to the next record --v
current = current->next;
}
printf("\nAverage of the list values: %.1f", sum / count);
}
这是正确的行为吗?C 语言中有一些我不知道的机制吗?
我放置了一些调试行,以便我可以跟踪计数器以及相应的记录,并发现该属性似乎不是 NULL,尽管我将其显式设置为 NULL。这是代码的输出:current
Enter measurement: 22
Next record created!
Enter measurement: 22
Next record created!
Enter measurement: 22
Next record created!
Enter measurement: -128
1 22
2 22
3 22
4 0
Average of the list values: 16.5
我确实尝试通过使用来释放指针的内存,但结果并不好,因为当时只保留一个随机数。current
free(current)
temperature
答:
问题在于指针 和 是两个不同的指针,它们占用不同的内存范围。 是局部变量,而是动态分配节点的数据成员。current
current->next
current
current->next
在此声明中
current = current->next;
设置指向指针的指针的值。因此,这两个指针具有相同的值。current->next
current
但是在这个if语句中
if (temp <= -128) {
current = NULL;
break;
}
只有指针发生了变化。指针保持不变。也就是说,局部变量已更改,但动态分配节点的数据成员未更改,并指向具有未初始化数据成员的动态分配节点。current
"previous"current->next
current
next
分配内存时的方法如下
// Allocate memory for the next record --v
current->next = (struct record*) malloc(sizeof(struct record));
// The next now becomes the current because we are done with the current --v
current = current->next;
并将其地址分配给指针,然后尝试将指针设置为循环内,在任何情况下都会导致内存泄漏。您应该重新设计代码的逻辑。current->next
NULL
最简单的方法是使用指针到指针,例如
struct record *first = NULL;
struct record **current = &first;
while (true) {
// Get user input --v
int temp;
printf("Enter measurement: ");
scanf("%d", &temp);
// If input is less than -128, end the loop --v
if (temp <= -128) {
break;
}
*current = malloc( sizeof( struct record ) );
( *current )->temperature = temp;
( *current )->next = NULL;
current = &( *current )->next;
puts("Next record created!");
}
在 while 循环之外,您需要为辅助指针使用另一个名称。例如
// Calculate average --v
struct record *tmp = first;
// and so on...
请注意这一点 -- 当不再需要列表时,您将需要释放所有分配的内存。
评论
current->next = NULL