我正在用元素周期表项目练习C语言.我有这个.txt文件,其中包含以下顺序的所有元素: atomic_number name symbol mass_number.

我的程序应该用数据填充一个 struct 数组(为了便于搜索). 问题是我的程序不会一直打印到最后一个元素(ATOM_NUMBER=118),它只在54结束,不会继续打印.它也不会填充超过54的array.

以下是我试图解决这个问题的方法

file: populate.c

#include "periodic_table.h"

int populate(void)
{
    struct element
    {
        int atomic_num;
        char name[15];
        char symbol[5];
        float mass_num;
    };

    // Array to hold the elements
    struct element e[118];

    // checks that the file exists
    FILE *ptr = fopen("periodic_table.txt", "r");
    if (ptr == NULL)
    {
        printf("No file to read from.\nExiting...\n");
        return 1;
    }

    int line;   // first line of the txt file
    for (line = 1; line <= 118; line++)
    {
        if (fscanf(ptr, "%d %s %s %f", &e[line].atomic_num, &e[line].name, &e[line].symbol, &e[line].mass_num))
        {
            //print is just for debugging purpose
            printf("%d record: %d %s %s %.2f\n", line, e[line].atomic_num, e[line].name, e[line].symbol, e[line].mass_num);
        }
        fflush(stdin);
    }

    fclose(ptr);
    return (0);
}

我的文本文件如下所示

1 Hydrogen H 1.01
2 Helium He 4.00
3 Lithium Li 6.94
.
.
.
116 Livermorium Lv 293.00
117 Tennesine Ts 294.00
118 Oganesson Og 294.00

推荐答案

您的程序中存在多个问题:

  • struct element和数组e的定义是populate函数的本地定义,因此一旦该函数返回,数据将不可用.

  • 索引变量line应该在0117之间运行,因为它用于索引e[118]array.访问e[118]具有未定义的行为.

  • 您应该一次读取一行,并使用sscanf()来解析该行,并报告转换错误以及行内容,以便于调试.

  • 测试if (fscanf(...))不正确:如果所有4次转换都成功,则返回值应为4.任何其他结果都应被视为错误.

  • %s是一个危险的转换说明符,因为如果文件内容包含的单词比预期的更长,则fscanf()可能会导致缓冲区溢出.

  • 对于数组形式的目标变量,不应使用&.

  • fflush(stdin);是无用的,实际上具有未定义的行为.

以下是修改后的版本:

#include "periodic_table.h"

// these definitions should be moved to "periodic_table.h"
struct element {
    int atomic_num;
    char name[15];
    char symbol[5];
    float mass_num;
};

// Array to hold the elements
struct element e[118];

int populate(void) {
    // checks that the file exists
    FILE *ptr = fopen("periodic_table.txt", "r");
    if (ptr == NULL) {
        fprintf(stderr, "No file to read from.\nExiting...\n");
        return 1;
    }

    int line;   // first line of the txt file
    for (line = 0; line < 118; line++) {
        char buffer[128];
        int pos;
        if (!fgets(buffer, sizeof buffer, ptr)) {
            fprintf(stderr, "cannot read element %d\n", line + 1);
            break;
        }
        if (sscanf(buffer, "%d%14s%4s%f%n", &e[line].atomic_num, e[line].name,
                   e[line].symbol, &e[line].mass_num, &pos) == 4) {
            //print is just for debugging purpose
            printf("%d record: %d %s %s %.2f\n",
                   line + 1, e[line].atomic_num, e[line].name,
                   e[line].symbol, e[line].mass_num);
            if (buffer[pos] != '\n') {
                fprintf(stderr, "line %d: extra data: %s\n", line + 1, buffer + pos);
            }
        } else {
            fprintf(stderr, "line %d: invalid data: %s\n", line + 1, buffer);
        }
    }

    fclose(ptr);
    return 0;
}

C++相关问答推荐

Zig将std.os.argv转换为C类型argv

从STdin读写超过4096个字节

字符串令牌化xpath表达式

空指针的运行时强制转换

如何在IF语句中正确使用0.0

如何在c++中包装返回空*的函数

N的值设置为0或1(未定义的行为),而我正在try 学习realloc和Malloc的用法

在Apple Silicon上编译x86的Fortran/C程序

getline()从c中的外部函数传递指针时输出null

如何编写一个for循环来计算C中各项的总和?

关于scanf()和空格的问题

接受任何参数的函数指针是否与接受不同参数的函数兼容

获取前2个连续1比特的索引的有效方法

C语言中MPI发送接收字符串时出现的分段错误

如何确保我将使用C标准库函数的函数版本,如&getc";,而不是类似函数的宏版本?

安全倒计时循环

从BIOS(8086)中读取刻度需要多少?

如何修复我的qsort()算法?它每次都给出不同的结果

关于不同C编译器中的__attribute__支持

inline 关键字导致 Clion 中的链接器错误