gpt4 book ai didi

c - 读取空文件,输出为符号

转载 作者:行者123 更新时间:2023-11-30 20:34:49 25 4
gpt4 key购买 nike

我是新来的所以在我的大学里,我只是学习c语言中的文件。我有一个任务。如果我将一个空文件放在我的项目目录中,并读取它。输出是符号(我不知道它是什么符号)。所以这是代码,请帮助

player dota[100];
FILE *fp;
fp = fopen("soal09.txt", "r");
if(fp == NULL)
{
printf("Error Opening The File!!\n");
return 0;
}
else
{
while(!feof(fp))
{
fscanf(fp, "%[^ ] %d %d\n", &dota[idx].name, &dota[idx].score, &dota[idx].num);
idx++;
}
}
fclose(fp);

do
{
enter();
menu();
printf("Input your choice [1..5]: ");
scanf("%d", &choose); fflush(stdin);

if(choose == 1)
{
system("cls");
enter();
printf("%-20s %-15s %s\n", "Player Name", ": Average Score", ": Number of Playing");
printf("====================================================================\n");
for(int i = 0; i < idx; i++)
{
printf("%-20s %-15d %d\n", dota[i].name, dota[i].score, dota[i].num);
}
printf("\nPress Enter to Continue...");
getchar();
}

getchar();
return 0;


}

输出是╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠-858993460
谢谢^^

最佳答案

仅在先前的文件I / O操作失败后才设置由feof()检查的文件结束指示符。您必须尝试进行I / O操作,以查明是否已到达文件末尾。因此,对于一个空文件,您的代码尝试读取该文件,设置了文件结束指示符,第一个struct中没有读取任何值,但是idx递增了,所以看起来您已经添加了玩家的数据。但是第一个struct的字段尚未初始化,因此您会看到垃圾。还要注意,dota[idx].name大概是char的数组,因此当传递给char时,它会衰减为指向fscanf()的指针。尽管似乎可以使用&dota[idx].name,但是使用gcc -Wall -Wextra -pedantic是错误的。确实会导致编译器发出警告,因此您应该启用这些警告(我总是至少使用feof())。

You should not use fscanf() to control file I/O loops。一种简单的解决方案是使用player的返回值来控制循环:

while(fscanf(fp, "%[^ ] %d %d\n",
dota[idx].name, &dota[idx].score, &dota[idx].num) == 3) {
idx++;
}


如果通过调用 struct进行了三项分配,则只会更新 fscanf() struct。但是,这种简单解决方案的问题在于它不能很好地处理格式错误的输入。如果数据文件的一行缺少字段,则 fgets()将被错误地填充,即使文件中还有更多行需要读取,循环也会终止。另外,由于没有为字符串转换指定字段宽度,因此长名称可能会导致程序崩溃。

更好的解决方案是使用 sscanf()将文件的行读取到缓冲区中,然后使用 buffer从缓冲区中提取信息:

#include <string.h>        // for strcpy()

...

char buffer[1000];
int line = 0;
char temp_name[100];
int temp_score, temp_num;

while(fgets(buffer, sizeof(buffer), fp)) {
++line;

if (sscanf(buffer, "%99[^ ] %d %d\n",
temp_name, &temp_score, &temp_num) == 3) {
strcpy(dota[idx].name, temp_name);
dota[idx].score = temp_score;
dota[idx].num = temp_num;
++idx;
} else if (buffer[0] != '\n') {
fprintf(stderr, "Bad input in line %d\n", line);
}
}


在这里,一个慷慨的 struct被声明为接受文件中的一行文本,并且声明了临时变量以保存要存储在 temp_name字段中的值。我为 struct选择的大小为100,但这应与您实际的 sscanf()中字符串数组的大小匹配。请注意, %99s中的字符串转换的字段宽度为99,因此最多匹配99个非空格(不是非空格,为什么不在这里仅使用 '\0'?)字符匹配,从而留出空格要添加的 fgets()

NULL到达文件末尾时将返回 line,因此循环将继续直到发生这种情况。对于读取的每一行, sscanf()计数器都会递增。然后,使用 sscanf()将数据读入临时变量。检查从 struct返回的值以确保已进行3个分配,如果是,则将数据复制到 idx,并递增 strcpy()。请注意,需要使用 temp_name将字符串从 dota[idx].name复制到 sscanf()

如果从 buffer返回的值表示进行了3项分配以外的操作,则检查 stderr是否保留空行。如果不是,则会在 do上显示一条错误消息,提供文件中错误输入的行号。

还有更多意见。您的 while()循环似乎缺少关联的 fflush(stdin)。然后在 scanf()循环内的 do之后使用 fflush()fflush()用于刷新输出流。在C标准(ISO / IEC 9899:2011 7.21.5.2/2)中明确未定义 fflush(stdin)在输入流上的行为,尽管我认为Microsoft在这里与标准有所不同。但是,您不应在可移植的C代码中使用 '\n'。相反,请使用以下内容:

int c;

...

scanf("%d", &choose);
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters


此代码从输入流中读取字符,直到到达 EOFscanf(),从输入流中清除上一次对 的调用留下的所有字符。

关于c - 读取空文件,输出为符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41205858/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com