链表:输出时成员元素出现奇怪的混乱

linked list: strange muddle of member element during output

问题陈述:给定一份国家名单以及参与某项特定调查的女性和男性人数。程序是根据汇总的男性和女性数量对列表进行降序排序,从 SecondaryEd2005.txt 文件中读取列表。问题必须只使用链表来解决,而不是双链表。不允许使用数组进行预排序。成员必须是:指向国家名称的 char 指针,2 longs 表示女性和男性参与者的数量。 Space 必须动态分配国家名称。输出必须采用国家名称、女性参与者人数、男性参与者人数、总和、行尾等格式。

问题:在任何情况下,代码都会输出最后读取的国家/地区名称,同时正确输出有关男性和女性的数量及其总和,它们按降序排列。我试图在将新节点放入列表的正确位置之前输出新节点的成员,它给出了正确的输出,表明所有内容都已正确读取。 我认为有些东西的国家名称是动态分配的,但不确定,如果它是正确的,不知道到底是什么。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct _person_count {
    char* country;
    long females;
    long males;
    struct _person_count *link;
} person_count;

int main () {
    FILE *file;
    file = fopen("SecondaryEd2005.txt","r");

    person_count *first = NULL;

    char c[32];
    int male;
    int female;

    do {
        person_count *newNode = malloc(sizeof(person_count));
        fscanf(file, "%s %i %i %i", c, &female, &male);
        newNode->females = female;
        newNode->males = male;
        int n;

        n = strlen(c);
        newNode->country = malloc(n*sizeof(char));
        newNode->country = c;
    newNode->link = NULL;
        printf("still reading: %s %i %i \n", newNode->country, newNode->females, newNode->males);

        if(first == NULL) {
            first = newNode;
        } else {
            int sumnewNode = newNode->females + newNode->males;
            int sumFirst = first->females + first->males;

            if(sumnewNode > sumFirst) {
                newNode->link = first;
                first = newNode;
            }else {
                person_count* current = first;
                while (1)
                {
                    if (current->link == NULL)
                    {
                        current->link = newNode;            
                        break;
                    }
                    else if (current->link->females + current->link->males < sumnewNode)
                    {
                        newNode->link = current->link;
                        current->link = newNode;
                        break;
                    }
                    current = current->link;
                }
            }
        }
    } while(!feof(file));


    person_count* cur = first;

    while(1)
    {
    printf("%s %d %d %d\n", cur->country, cur->females, cur->males, cur->females + cur->males);
        if (cur->link == NULL)
            break;
        cur = cur->link;
    }

    return 0;

}

如果需要任何其他信息,我可以提供。提前谢谢你。

strlen() returns 字符串长度 没有 空终止符。这很重要(基本上你想要 newNode->country = malloc(n+1);sizeof(char) 总是 1)。

更糟糕的是,在那之后你重写了 newNode->country,丢失了指向已分配块的指针并设置 newNode->country 指向你的 32 字符缓冲区(所以最后 country 中的指针所有节点都指向同一个字符串)。应使用 strncpy() or strncpy_s() 调用进行字符串复制。

你这里有几个错误:

    n = strlen(c);
    newNode->country = malloc(n*sizeof(char));
    newNode->country = c;

C 字符串应该以 NUL 结尾,strlen() 没有考虑到这一点。也许在这里使用 strdup() 会更好:

    newNode->county = strdup(c);

您稍后在拆除列表时仍然需要free()记忆。

此外,您的版本会泄漏内存,因为您从未真正使用分配的缓冲区。这一行:

    newNode->country = c;

将 country 设置为指向堆栈上的缓冲区,该缓冲区将消失,使您的指针指向无效内存——或者更糟糕的是,不属于您自己的有效内存。至少,扫描的每一行都会被破坏,这会使您的所有节点都指向上次读取的国家/地区。如果您要坚持分配自己的内存,它应该更像是:

    newNode->country = calloc((n+1) * sizeof(char));
    strncpy(newNode->country, c, n);