所以我需要对二进制文件进行读写操作,但似乎做不到,当使用read from file时,程序崩溃。我需要帮助写二进制文件,然后从中读取并在关闭程序后重新开始工作。我不知道自己做错了什么,我已经搜索了很长时间,但没有结果。以下是我的程序代码:

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

typedef struct{
    char *subjName;
    char *lectName;
    char *lectSurname;
    int credits;
    int num_students;
}Subject;

typedef struct{
        Subject **subjs;
        int num_subjs;
}Subjects;

int numOfSubjs=0;

void listInput();
void listEdit();
void listDelete();
void listPrint();
int userChoice(int select);
int enterNumber(char *name);
void saveToFile(Subjects *subjects);
void readFromFile(Subjects *subjects);

int main() {

    Subjects *subjects = malloc(sizeof(Subjects));
    subjects->num_subjs = 0;
    subjects->subjs = NULL;
    readFromFile(subjects);
    int r=1;
    while(r!=0){
        int select=userChoice(select);
        switch(select){
            case 1:
            listPrint(subjects);
            break;

            case 2:
            listInput(&subjects);
            break;

            case 3:
            listDelete(subjects);
            break;

            case 4:
            listEdit(subjects);
            break;

            case 0:
            r=0;
            break;
        }
    }
    saveToFile(subjects);
    return 0;
}

int userChoice(int select){                                                 // menu options
    int choice,input=0;
    printf("(1). View all the data\n");
    printf("(2). Enter new data\n");
    printf("(3). Delete data\n");
    printf("(4). Edit data\n");
    printf("(0). Exit\n");
    printf("-----------------------------\n");

    while(input!=1){
        choice = enterNumber("menu");
        if(choice>4 || choice<0){
            printf("Invalid input \n");
        }
        else
            input = 1;
    }
    return choice;
}

void listPrint(Subjects *subjects){                         // print data
    int i;
    for(i=0; i< numOfSubjs; i++){
        printf("%d, %s, %s, %s, %d, %d\n",i+1, subjects->subjs[i]->subjName, subjects->subjs[i]->lectName, subjects->subjs[i]->lectSurname, subjects->subjs[i]->credits, subjects->subjs[i]->num_students);
    }
    printf("Number of entries: %d \n", numOfSubjs);
}

char *getln()                                               //dynamically allocate input string
{
    char *line = NULL, *tmp = NULL;
    size_t size = 0, index = 0;
    int ch = 1;

    while (ch) {
        ch = getc(stdin);
        if (ch == '\n')
            ch = 0;

        if (size <= index) {
            size += 1;
            tmp = realloc(line, size);
            if (!tmp) {
                free(line);
                line = NULL;
                break;
            }
            line = tmp;
        }

        line[index++] = ch;
    }

    return line;
}



void saveToFile(Subjects *subjects){
    FILE *data;
    data = fopen("data.bin","wb");
    printf("%s", subjects->subjs[0]);
    for(int i=0; i<numOfSubjs; i++){
        fwrite(&subjects->subjs[i],sizeof(Subject*),1,data);
    }
    fclose(data);
}

void readFromFile(Subjects *subjects){
    FILE *data;
    int i=0;
    data = fopen("data.bin","rb");
    while(!feof(data))
    {
         fread(&subjects->subjs[i],sizeof(Subject*),1,data);
         i++;
    }
    fclose(data);
}

int isText(char *str,char *name){                                   // check if is text
    for(int i = 0; i < strlen(str);i++){
        if((str[i]<'A' || str[i]>'z') && str[i]!=' '){
            printf("Error, %s must be a text \n",name);
            return 0;
        }
    }
    return 1;
}

int enterNumber(char *name){                                // enter number and check if is number
    int input=0, crash=0, num=0;
        while(input!=1)
        {
             crash=0;
             printf("Enter the number of %s\n", name);
             scanf("%d", &num);
             while(getchar()!='\n')
             {
                crash++;
             }
             if(crash>0 || num<0)
                printf("Error, enter a not negative number of %s\n", name);
             else if(crash==0)
                input=1;
        }
    return num;
}

void listInput(Subjects **p_subjects){                              // input new data

    Subject *new_subj = malloc(sizeof(Subject));
    new_subj->subjName = NULL;
    new_subj->lectName = NULL;
    new_subj->lectSurname = NULL;
    new_subj->credits = 0;
    new_subj->num_students = 0;

    do{
        printf("Enter the name of the subject \n");
        new_subj->subjName = getln();
    }while(!isText(new_subj->subjName,"Subject name"));

    do{
        printf("Enter the name of the lecturer \n");
        new_subj->lectName = getln();
        new_subj->lectName[0] &= '_';
    }while(!isText(new_subj->lectName,"Lecturer's name"));

    do{

        printf("Enter the surname of the lecturer\n");
        new_subj->lectSurname = getln();
        new_subj->lectSurname[0] &= '_';                                            //Convert to uppercase if lowercase
    }while(!isText(new_subj->lectSurname,"Lecturer's name"));

    new_subj->credits = enterNumber("credits");

    new_subj->num_students = enterNumber("students");

    (*p_subjects)->subjs = realloc((*p_subjects)->subjs,sizeof(Subject*)*(++(*p_subjects)->num_subjs));
    (*p_subjects)->subjs[(*p_subjects)->num_subjs-1] = new_subj;
    numOfSubjs++;
    printf("Added a new entry.\n\n");
}

void listDelete(Subjects *subjects){                                                // delete entries
    int del;
    if(numOfSubjs==0)
        printf("Number of entries is 0, can't delete anything\n");
    else{
        printf("Enter 0 to exit. Number of subjects : %d \n", numOfSubjs);
        while(1){
            del = enterNumber("entry which you would like to delete");
            if(del<=numOfSubjs && del>0){
                    for(int i = del-1; i<numOfSubjs-1; i++){
                        subjects->subjs[i]=subjects->subjs[i+1];
                        subjects->subjs = realloc(subjects->subjs,sizeof(Subject*)*(--subjects->num_subjs));
                    }
                numOfSubjs--;
                break;
            }
            if(del>numOfSubjs)
                printf("Error, input a number between 1 and %d (or enter 0 to exit)\n", numOfSubjs);
            else
                break;
        }
    }
}
void listEdit(Subjects *subjects){                                                                  // edit entries
    int choice=0, editEntry=0, editSubj=0;
    if(numOfSubjs == 0)
        printf("Number of entries is 0, can't edit anthing\n");
    else{
        while(1){
            printf("Number of entry must be between 1 and %d \n", numOfSubjs);
            choice = enterNumber("entry you would like to edit.");
            if(choice>0 && choice<=numOfSubjs){
                while(1){
                    editEntry = enterNumber("what would you like to edit\n 1 - Subject name\n 2 - Lecturer's name\n 3 - Lecturer's surname\n 4 - Number of credits\n 5 - Number of students");
                        if(editEntry>0 && editEntry <=5){
                            switch(editEntry){
                                case 1:
                                    do{
                                        printf("Enter the name of the subject \n");
                                        subjects->subjs[choice-1]->subjName = getln();
                                    }while(!isText(subjects->subjs[choice-1]->subjName,"Subject name"));
                                    break;
                                case 2:
                                    do{
                                        printf("Enter Lecturer's name \n");
                                        subjects->subjs[choice-1]->lectName = getln();
                                    }while(!isText(subjects->subjs[choice-1]->lectName,"Lecturer's name"));
                                    break;
                                case 3:
                                    do{
                                        printf("Enter Lecturer's surname \n");
                                        subjects->subjs[choice-1]->lectSurname = getln();
                                    }while(!isText(subjects->subjs[choice-1]->lectSurname,"Lecturer's surname"));
                                    break;
                                case 4:
                                    subjects->subjs[choice-1]->credits = enterNumber("credits");
                                    break;
                                case 5:
                                    subjects->subjs[choice-1]->num_students = enterNumber("students");
                                    break;

                            }
                        }
                    break;
                }
            }
            break;
        }
    }
}

最佳答案

&subjects->subjs[i],这是未定义的行为。访问垃圾值。你需要正确地初始化它正确的内存地址。你哪儿也做不到。
(*subjects).subjssubjects->subjs->这不是指向任何地方。它是NULL
这里也不需要双指针。一个指针就能做你想做的事。

typedef struct{
        Subject *subjs;
        int num_subjs;
}Subjects;

对于单指针
Subjects *subjects = malloc(sizeof(Subjects));
subjects->num_subjs = 10;
subjects->subjs = malloc(subjects->num_subjs * sizeof Subject);
subjects->subjs[0].subjName = malloc(40);

每个malloc都应该检查它的返回值。如果它为空,则继续或访问它将是错误的。
当你完成它的工作时,free()就会相应地。
一些基本的东西:-
  typedef struct{
          Subject *subjs;
          int num_subjs;
  }Subjects;

现在让我们看一下代码。
Op问为什么要初始化Op,但这还不够?
指针是用来保存地址的变量。这里subjects->num_subjs = 0; subjects->subjs = NULL;将保存Subject*类型变量的地址。
现在在这里,首先初始化它。
您已经分配了一个内存并将其地址分配给Subject变量Subject*
现在让我们看看你还能做什么。
subjects->num_subjs = 0;
subjects->subjs = NULL;

你初始化了它。然后尝试访问它(subjects)。你能告诉我它指向哪里吗?(subjects->subjs[i])?
答案是否定的。它指的是什么地方。它现在包含subject->subjs值。你不认为你应该告诉它你想持有和分配多少股份吗?是的,你应该这样做,这正是我在所示例子中所做的。
每当你有一个指针变量的时候,问问自己它包含什么——如果这个值是你知道的,那就不要问随机的垃圾值。

关于c - 程序不写入文件,加载时崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47559200/

10-11 15:55