如何从文件中读取一个长列表的数据?

huangapple go评论89阅读模式
英文:

how do I read a long list of data from a file?

问题

我正在用一个周期表项目练习C语言。我有一个**.txt**文件,其中按照以下顺序包含所有元素的信息:
原子序号 名称 符号 质量数

我的程序应该用数据填充一个结构体数组(以便于搜索)。
问题是我的程序不能一直运行到最后一个元素(原子序号=118),它在54处停止,并且不再打印。它还不会填充数组超过54。

以下是我尝试解决问题的方式

文件:populate.c

#include "periodic_table.h"

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

    // 用于保存元素的数组
    struct element e[118];

    // 检查文件是否存在
    FILE *ptr = fopen("periodic_table.txt", "r");
    if (ptr == NULL)
    {
        printf("找不到要读取的文件。\n正在退出...\n");
        return 1;
    }

    int line;   // txt文件的第一行
    for (line = 1; line <= 118; line++)
    {
        if (fscanf(ptr, "%d %s %s %f", &e
.atomic_num, e
.name, e
.symbol, &e
.mass_num))
{ // 仅用于调试目的的打印 printf("%d 记录:%d %s %s %.2f\n", line, e
.atomic_num, e
.name, e
.symbol, e
.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
英文:

I am practicing C with a periodic table project. I have this .txt file that contains all the elements in this order:
atomic_number name symbol mass_number.

My program was supposed to populate an array of structures with the data (for easy searching).
The problem is my program doesn't go all the way to the last element (atomic_number = 118) it just stops at 54 and doesn't print further. It also does not populate the array beyond 54.

Here is how I have tried to tackle the problem

file: populate.c

#include &quot;periodic_table.h&quot;

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(&quot;periodic_table.txt&quot;, &quot;r&quot;);
    if (ptr == NULL)
    {
        printf(&quot;No file to read from.\nExiting...\n&quot;);
        return 1;
    }

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

My text file looks like this

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

答案1

得分: 0

你的程序存在多个问题:

  • struct element 和数组 e 的定义仅在 populate 函数内部可见,因此一旦函数返回,数据将不再可用。

  • 索引变量 line 应该从 0117,因为它用于索引数组 e[118]。访问 e[118] 具有未定义的行为。

  • 你应该逐行读取数据并使用 sscanf() 解析每一行,以便更容易进行调试时报告转换错误以及行内容。

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

  • %s 是一种风险较大的格式说明符,因为如果文件内容中的单词超过了预期的长度,fscanf() 可能会导致缓冲区溢出。

  • 不应该对数组作为目标变量使用 &amp;

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

以下是修改后的版本:

#include "periodic_table.h"

// 这些定义应该移到 "periodic_table.h"
struct element {
    int atomic_num;
    char name[15];
    char symbol[5];
    float mass_num;
};

// 用于保存元素的数组
struct element e[118];

int populate(void) {
    // 检查文件是否存在
    FILE *ptr = fopen("periodic_table.txt", "r");
    if (ptr == NULL) {
        fprintf(stderr, "无法读取文件。\n正在退出...\n");
        return 1;
    }

    int line;   // 文本文件的第一行
    for (line = 0; line < 118; line++) {
        char buffer[128];
        int pos;
        if (!fgets(buffer, sizeof buffer, ptr)) {
            fprintf(stderr, "无法读取元素 %d\n", line + 1);
            break;
        }
        if (sscanf(buffer, "%d%14s%4s%f%n", &e
.atomic_num, e
.name,
e
.symbol, &e
.mass_num, &pos) == 4) {
// 仅用于调试目的的打印 printf("%d 记录: %d %s %s %.2f\n", line + 1, e
.atomic_num, e
.name,
e
.symbol, e
.mass_num);
if (buffer[pos] != '\n') { fprintf(stderr, "第 %d 行: 额外数据: %s\n", line + 1, buffer + pos); } } else { fprintf(stderr, "第 %d 行: 无效数据: %s\n", line + 1, buffer); } } fclose(ptr); return 0; }

注意:这只是一个修复了问题的修改版本,你可能需要根据你的具体需求进行进一步的改进和测试。

英文:

There are multiple problems in your program:

  • the definition for struct element and the array e is local to the populate function, so the data will be unavailable once the function returns.

  • the index variable line should run from 0 to 117 as it is used to index the e[118] array. accessing e[118] has undefined behavior.

  • you should read one line at a time and use sscanf() to parse the line, and report conversion errors along with the line contents for easier debugging.

  • the test if (fscanf(...)) is incorrect: the return value should be 4 if all 4 conversions succeeded. any other result should be considered an error.

  • %s is a risky conversion specifier as fscanf() can cause a buffer overflow if the file contents has words longer than expected.

  • you should not use &amp; for destination variables that are arrays.

  • fflush(stdin); is useless and actually has undefined behavior.

Here is a modified version:

#include &quot;periodic_table.h&quot;

// these definitions should be moved to &quot;periodic_table.h&quot;
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(&quot;periodic_table.txt&quot;, &quot;r&quot;);
    if (ptr == NULL) {
        fprintf(stderr, &quot;No file to read from.\nExiting...\n&quot;);
        return 1;
    }

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

huangapple
  • 本文由 发表于 2023年7月23日 15:55:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76747182.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定