在C中迭代链表时,空检查行为不正确

vshtjzan  于 2023-02-21  发布在  其他
关注(0)|答案(1)|浏览(124)

我试图通过编写一个程序来学习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中是否有一些我不知道的机制?
我添加了一些调试行,以便跟踪计数器以及相应的记录,并发现current属性看起来并不为NULL,尽管我显式地将其设置为NULL。

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

我确实尝试过使用free(current)来释放current指针的内存,但结果并不好,因为temperature只保存了一个随机数。

6jjcrrmo

6jjcrrmo1#

问题在于指针currentcurrent->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...

请注意这一点--当不再需要该列表时,您需要释放所有分配的内存。

相关问题