c# fgets()在几次迭代后不再工作

sxpgvts3  于 2023-06-20  发布在  C#
关注(0)|答案(1)|浏览(178)

我有一个headers.h文件,其中有一个这样定义的结构:

#ifndef HEADERS
#define HEADERS
#define FILE_ERR -10
#define OK 0
#define TRUE 0
#define FALSE -1
#define SONGS 4

struct song {
    char title[31];
    char author[31];
    int duration_in_sec;
    int reps;
};  

int load_music_from_file(char*, struct song*);
int write_music_on_file(char*, struct song*);

#endif

我有一个这样写的输入文件:

we will rock you
queen
2:01
it's my life
bon jovi
3:46
we will rock you
queen
2:01
the show must go on
queen
4:36

我必须读取文件并将其写入输出文件,以秒为单位修改持续时间并在输入文件中添加每首歌曲的重复。这些是我的功能:

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

int check_reps(struct song* list, char* title, int n) {
    for (int i=0; i<n; i++) {
        if (strcmp(list[i].title, title) == 0) {
            list[i].reps++;
            return TRUE;
        }
    }
    return FALSE;
} 

int min_to_sec(int min, int sec) {
    return (min * 60) + sec; 
}

int load_music_from_file(char* filename, struct song* list) {
    FILE* fp = fopen(filename, "r");
    if (fp == NULL) return FILE_ERR;
    int i = 0;
    int min, sec;
    char buf_title[31], buf_author[31], buf[6];
    
    while (fgets(buf_title, 31, fp) != NULL && fgets(buf_author, 31, fp) != NULL) {
        if (check_reps(list, buf_title, i) == FALSE) {
            strncpy(list[i].title, buf_title, 31);
            strncpy(list[i].author, buf_author, 31);
            if (fgets(buf, 6, fp) != NULL && sscanf(buf, "%d:%d", &min, &sec) == 2) list[i].duration_in_sec = min_to_sec(min, sec);
            else return FILE_ERR;
            list[i].reps = 1;
            printf("%s%s%d\n%d\n\n", list[i].title, list[i].author, list[i].duration_in_sec, list[i].reps);
        } 
        i++;
    }

    fclose(fp);
    return OK;
}

int write_music_on_file(char* filename, struct song* list) {
    FILE* fp = fopen(filename, "w");
    if (fp == NULL) return FILE_ERR;
    
    for (int i=0; i<SONGS; i++) {
        fprintf(fp, "%s%s%d\n%d\n\n", list[i].title, list[i].author, list[i].duration_in_sec, list[i].reps);
    }
    
    return OK;
}

这是我的主要功能:

#include "headers.h"
#include <stdio.h>
#include <stdlib.h>

int main() {
    struct song* list = (struct song*) malloc(sizeof(struct song) * 4);

    char* input = "songs.txt";
    printf("loading songs from %s\n", input);
    load_music_from_file(input, list);
    
    char* output = "output.txt";
    printf("songs written to %s\n\n", output);
    write_music_on_file(output, list);
    
    free(list);
    return 0;
}

如果我cat output.txt我看到:

we will rock you
queen
121
2

it's my life
bon jovi
226
1

0
0

2:01
the show must go on
0
0

我认为,load_music_from_file()函数有一个问题,让我不爽的是,它只适用于循环的一定次数的迭代。
旁注:

  • 我正在准备考试,但我不必交这个程序。
  • 我知道我还没有检查函数的返回值。
hc2pp10m

hc2pp10m1#

在这个while循环中似乎有两个逻辑错误

while (fgets(buf_title, 31, fp) != NULL && fgets(buf_author, 31, fp) != NULL) {
    if (check_reps(list, buf_title, i) == FALSE) {
        strncpy(list[i].title, buf_title, 31);
        strncpy(list[i].author, buf_author, 31);
        if (fgets(buf, 6, fp) != NULL && sscanf(buf, "%d:%d", &min, &sec) == 2) list[i].duration_in_sec = min_to_sec(min, sec);
        else return FILE_ERR;
        list[i].reps = 1;
        printf("%s%s%d\n%d\n\n", list[i].title, list[i].author, list[i].duration_in_sec, list[i].reps);
    } 
    i++;
}

第一个是,如果函数check_reps返回TRUE,则记录如下

2:01

在循环的下一次迭代中被读取为例如标题,因为在if语句中的这些fgets调用

if (fgets(buf, 6, fp) != NULL && sscanf(buf, "%d:%d", &min, &sec) == 2) list[i].duration_in_sec = min_to_sec(min, sec);
        else return FILE_ERR;

不要得到控制。
第二个逻辑错误是变量i被递增,即使函数check_reps再次返回TRUE,尽管在这种情况下结构数组的新元素没有被填充。
另外,函数load_music_from_file应该以某种方式报告结构数组中实际填充了多少个元素。你应该在函数中动态分配一个结构数组,而不是使用幻数4。虽然在这种情况下,使用列表而不是数组会更好。
注意这些宏定义

#define TRUE 0
#define FALSE -1

是不好的,只会让代码的读者感到困惑,因为通常逻辑值true被定义为非零值,而false被定义为零值。
你可以包含头文件<stdbool.h>,并使用定义的宏truefalsebool

相关问题