c - 读取二进制文件并显示条目

标签 c struct fwrite fread

我可能需要你的帮助来解决这个问题... 我正在学习 C 并发现一个问题,如何正确读取二进制文件。

我填充了一个结构数组,然后写入二进制文件并尝试读取它,但这并没有显示任何内容。

代码在pastebin中

My code

#include <stdio.h>
#include <ctype.h>
#include <math.h>

typedef struct {
    int id;
    char name[100];
    char document[14];
    float testGrade;
} Candidate;

typedef struct {
    int id;
    float testGrade;
} Grade;

FILE * openFile(char filename[100], char filemode[3]) {
    FILE *p = fopen(filename, filemode);

    if (!p) {
        printf("Error to open %s file. \nThe program will be closed.",filename);
        exit(1);
    }
}


void addCandidate(int newId, int numbersOfNewCandidate, char candidateFilename[100], char gradeFilename[100]) {
    int counter = 0;
    float testGrade = 0;

    Candidate*candidate;
    candidate= malloc(sizeof(Candidate) * numbersOfNewCandidate);

    Grade *grade;
    grade= malloc(sizeof(Grade) * numbersOfNewCandidate);

    for(;counter< numbersOfNewCandidate; counter++) {
        system("@cls||clear");
        printf("Adding  #%d:",newId);
        printf("\n---------------\n");

        printf("\nName of candidate: ");
        gets(&candidate[counter].name);

        printf("\nDocument: ");
        gets(&candidate[counter].document);

        do {
            printf("\nTest grade (between 0 and 10): ");
            scanf("%f",&testGrade);
            printf("\n---------------\n");

            if (testGrade < 0 || testGrade > 10) {
                printf("\nERROR!\nTest grade %.2f invalid, please try again with a grade between 0 and 10.\n",testGrade);
            }

        } while(testGrade < 0 || testGrade > 10);

        candidate[counter].id = newId;
        grade[counter].id = newId;
        candidate[counter].testGrade = testGrade;
        grade[counter].testGrate = testGrade;
        newId++;
        fflush(stdin);
    }

    FILE *candidateFile = openFile(candidateFilename, "a+b");
    fwrite(candidate, sizeof(candidate),numbersOfNewCandidate, candidateFile );

    FILE *gradeFile = openFile(gradeFilename, "a+b");
    fwrite(grade, sizeof(grade),numbersOfNewCandidate, gradeFile );

    fclose(candidateFile);
    fclose(gradeFile);

    free(candidate);
    free(grade);
}

void showCandidate(int typeOfSearch, char valueToSearch[100]) {}

void listAllCandidates(char candid[100]) {
    FILE *fp = openFile(candidateFilename, "rb");

    //fseek(fp,0,SEEK_SET);

    Candidate *candidate = NULL;

    candidate = malloc(sizeof(Candidate) + 1);

    while(fread(&candidate,sizeof(Candidate),1,fp) == 1) {
        printf("\n\nId: %d \nName: %s \nDocument: %s \nGrade: %.2f",candidate->id,candidate->name,candidate->document, candidate->testGrade);
    }
    getche();
    free(candidate);
}

void main(){
    int lastId = 0;
    char candidateFilename[100] = "candidates.bin";
    char gradeFilename[100] = "classificationList.bin";
    char option;

    do {
        system("@cls||clear");
        printf("Menu: \n");
        printf("1 - Add candidates \n");
        // printf("2 - Search by name \n");
        // printf("3 - Search by document  \n");
        // printf("---------------------------\n");
        // printf("4 - Show Max Grade, Minimum, Avg \n");
        printf("5 - List candidates \n");
        printf("6 - Erase files \n");
        printf("---------------------------\n");
        printf("S - Exit \n");
        printf("\n\n");

        option = toupper(getche());

        switch(option) {
            case '1':
                system("@cls||clear");

                int numbersOfNewCandidate = 0;
                int newId = 0;

                printf("Home > Add candidates\n\n");
                printf("Please give the number of new candidates: ");
                scanf("%d",&numbersOfNewCandidate);
                newId = lastId;
                lastId += numbersOfNewCandidate;

                fflush(stdin);
                addCandidate(newId + 1, numbersOfNewCandidate, candidateFilename, gradeFilename);

                printf("\n\nAdding new candidates: Finished \n");
            break;
            // case '2':
            //     printf("\noption %c@\n",option);
            // break;
            // case '3':
            //     printf("\noption %c#\n",option);
            // break;
            // case '4':
            //     printf("\noption %c?\n",option);
            // break;
            case '5':
                listAllCandidates(candidateFilename);
            break;
            case '6':
                remove(candidateFilename);
                remove(gradeFilename);
                printf("\nRemoved!!\n");
            break;
            case 'S':
                printf("\noption %c, the program will be ended...\n",option);
            break;
            default:
                printf("\nWrong option!!\n");
            break;
        }
    } while (option != 'S');
}

如果您发现我的代码存在其他问题,请尝试向我解释一下。 我也已经尝试过,但还没有。

while(!feof(fp)) {
    fread(&candidate,sizeof(Candidate),1,fp);
    printf("\n\nId: %d \nName: %s \nDocument: %s \nGrade: %.2f",candidate->id,candidate->name,candidate->document, candidate->testGrade);
} 

最佳答案

Candidate *candidate = NULL;
candidate = malloc(sizeof(Candidate) + 1);
while(fread(&candidate,sizeof(Candidate),1,fp) == 1) {...}
free(candidate);

fread 中的第一个参数应该是一个指针 fread(void*,...),并且 candidate 已经声明为指针,它不应该有引用运算符。正确的用法是:

while(fread(candidate,sizeof(Candidate),1,fp) == 1) {...}

请注意,candidate 前面没有引用& 运算符

<小时/> 有时您会看到引用运算符,但情况不同,如下所示:

Candidate cand;
while(fread(&cand,sizeof(cand),1,fp) == 1) {...}

这是一种更简单的方法,因为 cand 不需要使用 malloc 进行分配,也不需要 free

<小时/> 不必要的函数会引入更多错误:

FILE * openFile(char filename[100], char filemode[3]) {
    FILE *p = fopen(filename, filemode);
    if (!p) {
        printf("Error to open %s file. \nThe program will be closed.",filename);
        exit(1);
    }
}

该函数应该返回一个文件指针。函数参数也可以简单地写成const char* filenameconst char *filemode。示例:

FILE * openFile(const char* filename, const char* filemode) {
    FILE *p = fopen(filename, filemode);
    if (!p) printf("Error to open %s file. \nThe program will be closed.",filename);
    return p;
}

我会完全放弃这个功能,因为它基本上没有用。只需使用fopen。完成后,请确保使用 fclose 关闭句柄。

<小时/>
grade[counter].testGrate = testGrade;
                      ^

这是一个拼写错误,应该是grade[counter].testGrade。建议编译程序时将警告级别设置为最高,或至少设置为 4 级。编译器将告知拼写错误、错误和警告。您必须能够以零错误和零警告的方式编译程序。这是一个简单的版本:

void listAllCandidates(char* candidateFilename)
{
    FILE *fin = fopen(candidateFilename, "rb");
    Candidate cand;
    while(fread(&cand, sizeof(cand), 1, fin))
        printf("%s, %s, %d, %f\n", cand.name, cand.document, cand.id, cand.testGrade);
    fclose(fin);
}

int main() 
{
    char candidateFilename[] = "file.bin";

    FILE *fout = fopen(candidateFilename, "ab");
    Candidate cand;

    strcpy(cand.name, "name1");
    strcpy(cand.document, "document1");
    cand.id = 1;
    cand.testGrade = 1.1f;
    fwrite(&cand, sizeof(cand), 1, fout);

    strcpy(cand.name, "name2");
    strcpy(cand.document, "document2");
    cand.id = 2;
    cand.testGrade = 2.2f;
    fwrite(&cand, sizeof(cand), 1, fout);

    fclose(fout);

    listAllCandidates(candidateFilename);

    printf("\n");
    return 0;
}

关于c - 读取二进制文件并显示条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47086358/

相关文章:

c - Valgrind 脏 helper 调用次数超出预期

go - 无法设置结构的属性

c++ - 使用 fwrite 转储的文件是否可以跨不同系统移植?

c - C-接受已知大小但未知类型的参数

c++ - 如何使用 luajit 在带有变量参数的 c 函数中获取 cdata?

c - 诊断进程卡在D状态(不可中断 sleep /阻塞IO)

c++ - 添加 'union' 关键字对预定义结构的影响

c - 使用指针元素检索链表中的数据

c - fwrite 和 fread 的问题

PHP | fopen() 和 fwrite() 在我的脚本中不起作用?