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

标签 c file

我是新来的所以在我的大学里,我只是学习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/

相关文章:

c# - FileOptions.DeleteOnClose Windows 是特定的吗?

file - Rebol 2 在 Windows 8 中创建文件时存在错误

python - 使用 python 替换文件中的行的方法是什么

.net - 启动线程

c - "make"错误,当我想制作 libsvm(系统 : MAC OS X 10. 12.6)

c++ - 我如何检查 C++ 代码中的文件写入权限?

c - 为什么我的程序在写入文件时崩溃?

c - 进入if条件时不出现变量(char) - C

c - 将负数打印为 C 中明确定义的字符吗?

java - 尝试在 Java 中构建