简体   繁体   English

我的fscanf为什么不读?

[英]Why doesn't my fscanf read?

I'm trying to read information from the file.txt into BST. 我正在尝试将file.txt信息读入BST。 First, I was thinking of saving info into temporary mini-arrays, and than assigning those values to the tree nodes. 首先,我正在考虑将信息保存到临时迷你数组中,而不是将这些值分配给树节点。 Apparently something goes wrong, I'm sure that one thing is the incorrect regular expression and might be something else. 显然出了点问题,我确定一件事是不正确的正则表达式,并且可能还有其他问题。 Please help me to figure out how to save data to the BST, I'm really late with this project. 请帮我弄清楚如何将数据保存到BST,这个项目真的很晚。

Samples of data contained in the input file.txt : 输入file.txt包含的数据样本:

3800 Lee, Victor; 2.8
3000 Brown, Joanne; 4.0
1300 South, Frankie; 2.6
4000 Trapp, Dave; 3.9

They have to be read and parsed into: 1) int= id , 2) char= name , 3) float= gpa 必须将它们读取并解析为:1) int= id ,2) char= name ,3) float= gpa

They have to be saved properly, without any symbols, so when I will do search in my next functions it wont give me any errors. 它们必须正确保存,没有任何符号,因此当我在下一个函数中进行搜索时,不会出现任何错误。

Here is my code below(UPDATED): 这是我的下面的代码(更新):

int readFile(BST_TREE *list) {
int id  = 0;
int val = 0;
int ln  = 0;
float gpa = 0.0;
char name[MAX_NAME_LEN];
STUDENT *stuptr = 0;
char line[MAX_LEN];

stuptr = (STUDENT*)malloc(sizeof(STUDENT));


FILE *fp = fopen("gpa.txt", "r");
if(fp == NULL) {
    printf("Error in opening file\n");
    return 1;
}

while (fgets(line, sizeof(line), fp)) {

ln++;
if (sscanf(line, "%d %[^;]; %f ", &id, name, &gpa) < 3) {
    printf("Syntax error in line %d.\n", ln);
} else {
    printf("1 %4d  %-29s%f\n", id, name, gpa);
  }
 }

    stuptr->id = id;
    strcpy(stuptr->name, name);
    (stuptr->gpa) = gpa;
    return 0;
}

// Typedef
 typedef struct
{
    int   id;
    char  name[MAX_NAME_LEN];
    float gpa;
} STUDENT;

That is because the format string of fscanf is wrong. 这是因为fscanf的格式字符串错误。 What you need is "%d %[^;];%f " . 您需要的是"%d %[^;];%f " This means 这意味着

  1. First read a decimal integer and store it. 首先读取一个十进制整数并将其存储。
  2. Then read and discard any number of whitespace characters. 然后读取并丢弃任意数量的空格字符。
  3. Then match any number of all characters except a semicolon ; 然后匹配除分号以外的所有所有字符; and store it. 并存储它。 The buffer where the characters are written must be large enough for the characters read plus a terminating null byte added by fscanf . 写入字符的缓冲区必须足够大,足以读取字符,再加上fscanf添加的终止空字节。
  4. Then match a semicolon ; 然后匹配一个分号; and discard it 丢掉
  5. Then read a floating-point value discarding any number of leading whitespace characters. 然后读取一个浮点值,该值将舍弃任何数量的前导空白字符。
  6. Then read and discard any number of whitespace characters. 然后读取并丢弃任意数量的空格字符。

As you see, if any line in the file is ill-formatted, then fscanf will fail due to matching failure and might leave the file pointer in an unknown location. 如您所见,如果文件中的任何行格式错误,则fscanf将由于匹配失败而失败,并且可能会将文件指针保留在未知位置。

You should use fgets instead to read a line and then use sscanf to process the line and read elements from it. 您应该改用fgets读取一行,然后使用sscanf处理该行并从中读取元素。 Here's how you should do it. 这是您应该如何做。 However, you must know beforehand, the maximum length a line in the file can have. 但是,您必须事先知道文件中一行的最大长度。

There are other mistakes in your code snippet. 您的代码段中还有其他错误。

  1. You are allocating memory to store a pointer, not the structure itself by this- 您正在为此分配内存来存储指针,而不是结构本身—
    stuPtr = (STUDENT*)malloc (sizeof (stuPtr));
    You should do the following. 您应该执行以下操作。 Also don't cast the result of malloc and check its result for NULL - 也不要malloc的结果并检查其结果是否为NULL
    stuPtr = malloc(sizeof *stuPtr);

  2. You cannot assign arrays. 您不能分配数组。 You should copy each character of the array instead. 您应该改为复制数组的每个字符。 Also, the structure member name is a character, not an array. 此外,结构成员name是字符,而不是数组。
    stuPtr->name = tempName;
    In the above statement, tempName is an array which decays into a pointer to its first element. 在上面的语句中, tempName是一个数组,该数组会衰减为指向其第一个元素的指针。 This pointer is assigned to structure member name which is a character - this is clearly an error. 该指针分配给结构成员name ,该name是一个字符-显然这是一个错误。 You should change the type of structure member name into a char array. 您应该将结构成员name的类型更改为char数组。

Here's a modified version with the changes I suggested. 这是我建议的修改后的版本。

#define MAX_LEN 100
#define MAX_NAME_LEN 40

typedef struct {
    int id;
    char name[MAX_NAME_LEN]; 
    float gpa;
} student;   

void add_student(BST_TREE *list) {
    int id, val;
    float gpa;
    char name[MAX_NAME_LEN]
    student *stuptr;
    char line[MAX_LEN];

    FILE *fp = fopen("gpa.txt", "r")       
    if(fp == NULL) {
        printf("error in opening file\n");
        return 1;
    }       

    while(fgets(line, sizeof line, fp) != NULL)
        stuptr = malloc(sizeof *stuptr);
        if(stuptr == NULL) {
            printf("not enough memory to allocate\n");
            return 1;
        }
        val = sscanf(line, "%d %[^;];%f", id, name, gpa)
        if(val != 3) {
            printf("input format error\n");
            // handle it
        }
        stuptr->id = id;
        strcpy(stuptr->name, name);
        stuptr->gpa = gpa;
    }
}

About reading your file: The return value is not necessarily EOF on failure to convert all placeholders and your format string does not correspond to the format in your file. 关于读取文件:如果未能转换所有占位符,则返回值不一定是EOF ,并且格式字符串与文件中的格式不对应。

fscanf returns the number of successful conversions. fscanf返回成功的转换次数。 When the input has run out, it returns EOF . 输入用完后,将返回EOF In your case, the format string will convert only the first item, so the return value is 1. You are looking for 3. (When fscanf does not convert all items, it is stuck. When you try to read the next line, you really try to read from where fscanf gave up converting, which is usually not where you think it is.) 在您的情况下,格式字符串将仅转换第一项,因此返回值为1。您正在寻找3。(当fscanf不能转换所有项时,它会卡住。当尝试读取下一行时,您会发现确实尝试从fscanf放弃转换的地方开始阅读,通常这并不是您认为的那样。)

The format of the entries in file is: 文件中条目的格式为:

3800 Lee, Victor; 2.8

Your format string is: 您的格式字符串是:

"%4d, %[^\t\n,;]c %f"

Several things here. 这里有几件事。

  • There is no comma after the id, but your format string has one. id后面没有逗号,但是您的格式字符串有一个。
  • The spurious c after the brackets cannot be understood 方括号后的虚假c无法理解
  • You treat the comma as one of the characters that end the name, but all names contain commas. 您将逗号视为以名称结尾的字符之一,但是所有名称都包含逗号。
  • The name entry ends with a semicolon, so there should be a semicolon in your format string where the c is. 名称条目以分号结尾,因此格式字符串中的c应该是一个分号。
  • Names that are longer than 30 characters will lead to buffer overflows. 长度超过30个字符的名称将导致缓冲区溢出。 Better specify a maximum string length. 最好指定最大字符串长度。

So your format should look like: 因此,您的格式应如下所示:

"%d %29[^;]; %f "

Putting it all togehter: 全部放在一起:

while (fscanf (f, "%d %[^;]; %f ", &id, name, &gpa) == 3) {
    printf("1 %4d  %-20s%f\n", id, name, gpa);
}

This will stop on the first line that can't be converted, so if you have a typo, a missing semicolon perhaps, in the first line, nothing will be read. 这将在无法转换的第一行上停止,因此,如果您有错字,可能缺少第一行中的分号,则不会读取任何内容。 That is not desirable. 那是不可取的。 Because the format of your file is line-based, I recommend to read lines with fgets first, then parse the line with sscanf : 因为文件的格式是基于行的,所以我建议先读取带有fgets的行,然后使用sscanf解析该行:

char buffer[80];
int ln = 0;

while (fgets(buffer, sizeof(buffer), f)) {
    int id;
    float gpa;
    char name[30];

    ln++;
    if (sscanf(buffer, "%d %[^;]; %f ", &id, name, &gpa) < 3) {
        printf("Syntax error in line %d.\n", ln);
    } else {
        printf("1 %4d  %-20s%f\n", id, name, gpa);
    }
}

Now bad lines are just skipped, with a (terse) error message. 现在,仅会跳过错误行,并显示(简短)错误消息。

Oh, and concentrate on the real problem and don't get too fancy. 哦,专注于真正的问题,不要太花哨。 While cramming everything together like this: 像这样将所有东西挤在一起:

if(!(fpStudents = fopen("gpa.txt", "r")))
    printf("-*- Could not open file for reading! -*-\n"), exit(100);

might give you h4xx0r credits, your code is rendered better as: 可能会给您h4xx0r积分,您的代码会更好地呈现为:

fpStudents = fopen("gpa.txt", "r");
if (fpStudents == NULL) {
    printf("-*- Could not open file for reading! -*-\n");
    exit(100);
}

You can see everything you need at a glace: Open a file. 您可以一目了然地看到所需的一切:打开文件。 If that goes wrong, print a message and exit. 如果那不对,请打印一条消息并退出。 I have a hard time to read that from your code without squinting. 我很难不斜视地从您的代码中读取它。 Assignments in conditionals and comma operators are so seventies . 有条件的运算符和逗号运算符的赋值是如此七十

My notes on your code: 我的代码注释:

sizeof (stuPtr) should be sizeof (STUDENT).

You have to pass the type definination to size of, the allocate the number of bytes of that type. 您必须将类型定义传递给size,分配该类型的字节数。

Here you can find more about that 在这里您可以找到更多关于

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM