英文:
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 "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.atomic_num, &e.name, &e.symbol, &e.mass_num))
{
//print is just for debugging purpose
printf("%d record: %d %s %s %.2f\n", 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
应该从0
到117
,因为它用于索引数组e[118]
。访问e[118]
具有未定义的行为。 -
你应该逐行读取数据并使用
sscanf()
解析每一行,以便更容易进行调试时报告转换错误以及行内容。 -
测试
if (fscanf(...))
是不正确的:如果所有 4 次转换都成功,返回值应为4
。任何其他结果都应视为错误。 -
%s
是一种风险较大的格式说明符,因为如果文件内容中的单词超过了预期的长度,fscanf()
可能会导致缓冲区溢出。 -
不应该对数组作为目标变量使用
&
。 -
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 arraye
is local to thepopulate
function, so the data will be unavailable once the function returns. -
the index variable
line
should run from0
to117
as it is used to index thee[118]
array. accessinge[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 be4
if all 4 conversions succeeded. any other result should be considered an error. -
%s
is a risky conversion specifier asfscanf()
can cause a buffer overflow if the file contents has words longer than expected. -
you should not use
&
for destination variables that are arrays. -
fflush(stdin);
is useless and actually has undefined behavior.
Here is a modified version:
#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.atomic_num, e.name,
e.symbol, &e.mass_num, &pos) == 4) {
//print is just for debugging purpose
printf("%d record: %d %s %s %.2f\n",
line + 1, e.atomic_num, e.name,
e.symbol, e.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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论