fscanf!= eof Clang编译器,异常行为

时间:2017-12-15 19:22:02

标签: c file clang

我有一个我无法理解的加重问题,

void file_count(FILE* stream,int* const num)
{
    int temp;
    while((fscanf(stream,"%d",&temp))!=EOF)
    {
        (*num)++;
    }
}

通过这个程序,我从一个文件中读取其中包含所有数字的信息,并且我花了一个数字计数器增加,所以我可以计算文件中有多少元素。

在这个文件中有6个数字,但是如果我运行这个代码,计数器就会飙升到32777 ...... 如果我用gcc编译它,没有问题,计数器是6按预期。这是一个铿锵的错误吗?这是我不知道的功能吗?

该文件包含:

22 30 30 21 25 29

整个代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef char* string;
typedef struct student
{
    int flag;
    char name[25];
    char surname[25];
    char dorm[25];
    int* grades;
}
Student;

void check_input(const int argc,const string* const argv);
void check_file(FILE* stream);
void file_count(FILE* stream,int* const num);
void update_student(const string* const infos,Student* const student,const int grades,FILE* stream);
void print_student(FILE* stream,Student const student,const int grades);

int main(int argc, string argv[])
{
    check_input(argc,argv);
    FILE* one,* two;
    string info[]={"David","Malan","Mather"};
    Student student;
    int grades;
    one=fopen(argv[1],"r");
    check_file(one);
    file_count(one,&grades);
    update_student(info,&student,grades,one);
    fclose(one);
    two=fopen(argv[2],"w");
    check_file(two);
    print_student(two,student,grades);
    fclose(two);
    free(student.grades);
    system("cat out");
    return 0;
}

void check_input(const int argc,const string* const argv)
{
    if(argc!=3)
    {
        printf("\x1B[31mError: %s takes two arguments!\x1B[0m\n",argv[0]);
        exit(EXIT_FAILURE);
    }
}

void check_file(FILE* stream)
{
    if(stream==NULL)
    {
        printf("\x1B[31mError:invalid file.\x1B[0m\n");
        exit(EXIT_FAILURE);
    }
}

void file_count(FILE* stream,int* const num)
{
    int temp;
    printf("reading file...\n");
    while((fscanf(stream,"%i",&temp))!=EOF)
    {
        (*num)++;
    }
    printf("\x1B[33mthe value read were %i\x1B[0m\n",*num);
}

void update_student(const string* const infos,Student* const student,const int grades,FILE* stream)
{
    rewind(stream);
    student->grades=malloc(grades*sizeof(int));
    strcpy(student->name,infos[0]);
    strcpy(student->surname,infos[1]);
    strcpy(student->dorm,infos[2]);
    student->flag=0;
    for(int i=0;i<grades;i++)
    {
        fscanf(stream,"%i",&student->grades[i]);
    }
}

void print_student(FILE* stream,Student const student,const int grades)
{
    printf("Writing to file..\n");
    fprintf(stream,"%i %s %s %s ",student.flag,student.name,student.surname,student.dorm);
    for(int i=0;i<grades;i++)
    {
        fprintf(stream,"%i ",student.grades[i]);
    }
    printf("\x1B[32mFile successfully written..\x1B[0m\n");
}

2 个答案:

答案 0 :(得分:4)

您的代码很危险,因为不正确的文件会将其发送到无限循环中。

fscanf %d找到无法解释为int的输入后,该函数返回零,而不会消耗输入。因此,循环永远不会达到EOF

只要输入被消耗,您就可以通过循环解决此问题:

while(fscanf(stream,"%d",&temp) == 1) {
    ...
}

现在,如果计数正确与否,您需要一种与呼叫者通信的方法。你可以通过在达到EOF时返回一个来做到这一点,否则为零:

int file_count(FILE* stream,int* const num) {
    int temp, last;
    while((last = fscanf(stream,"%d",&temp)) == 1) {
        (*num)++;
    }
    return last == EOF;
}
  

我尝试使用fscaf==1它仍然达到32777

这是因为您没有在调用者中初始化grades。您应该将其定义为int grades = 0,或在*num = 0中输入循环之前添加file_count

答案 1 :(得分:0)

当前的ISO C标准将fscanf()的返回值定义为

  

如果在第一次转换(如果有)完成之前发生输入故障,fscanf函数将返回宏EOF的值。否则,该函数返回分配的输入项的数量,如果早期匹配失败,则可以少于提供的数量,甚至为零。

ISO-C标准的逐字引用(没有可用的公共链接,标准不是公开的AFAIK)

如果有要读取的数据,但该数据无法成功匹配,则此函数将返回0.如果没有要读取的数据,它将仅返回EOF(通常为-1)因为流是您的正在读取处于EOF状态或有另一个读取错误。

所以如果你有这样的文件:

23 a 57

循环永远不会终止。在第一次扫描时,它将读取23并返回1(一个值匹配)。在下一次调用时,它将返回0,因为a无法与整数匹配。然而,它也不会将文件指针移到a之外。因此,在下一次调用时,它会再次尝试匹配a,它将再次失败。这种情况持续不断。