简体   繁体   English

程序未写入文件,加载时崩溃

[英]Program doesnt write to file and crashes when loading

So i need to write and read to and from a binary file, but cant seem to do it, and when using readFromFile, the program crashes. 因此,我需要在二进制文件中进行读写操作,但似乎无法做到这一点,并且在使用readFromFile时,程序崩溃。 I need help write to binary file, and then reading from it and resuming my work later after turning off the program.I have no idea what i am doing wrong, and i have googled for a long time now, but with no results. 我需要帮助写入二进制文件,然后从中读取文件,然后在关闭程序后恢复工作。我不知道我做错了什么,而且我已经搜索了很长时间了,但是没有结果。 Here is the code of my program: 这是我程序的代码:

#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], This is Undefined behavior. &subjects->subjs[i],这是未定义的行为。 Accessing garbage value. 访问垃圾值。 You need to properly initialize it proper memory address. 您需要正确初始化它正确的内存地址。 You ddin't do it anywhere. 你什么都没做。

(*subjects).subjs or subjects->subjs -> This is not pointing anywhere. (*subjects).subjssubjects->subjs >这没有指向任何地方。 It is NULL . 它为NULL

Also here you don't need the double pointer. 同样在这里,您不需要双指针。 A single pointer would do the thing you want to do. 单个指针可以完成您想做的事情。

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

For single pointer this would be like 对于单个指针,这就像

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

Each of the malloc should be checked with it's return Value. 应该检查每个malloc的返回值。 If it's NULL then it would be error to proceed further or access it. 如果为NULL,则继续或访问它将是错误的。

And free() it accordingly when you are done working with it. 完成处理后,相应地free()它。


Some basic things:- 一些基本的事情:

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

Now let's look a bit in the code. 现在让我们看一下代码。

Op asked why OP should initialize and isn;t subjects->num_subjs = 0; subjects->subjs = NULL; Op询问为什么OP应该初始化,而不是初始化; t subjects->num_subjs = 0; subjects->subjs = NULL; subjects->num_subjs = 0; subjects->subjs = NULL; not enough? 不够?

A pointer is a variable that is supposed to hold address. 指针是应该保存地址的变量。 here Subject* will hold the address of the variables of type Subject . 这里Subject*将保存类型Subject的变量的地址。

Now here initially you initialized it. 现在,您首先在这里对其进行了初始化。

You have allocated a memory and assigned it's address to the Subject* variable subjects . 您已分配的内存,并指派它的地址为Subject*变量subjects

Now let's see what else you do. 现在,让我们看看您还做什么。

subjects->num_subjs = 0;
subjects->subjs = NULL;

You initialized it. 您已初始化。 And then you try to access it( subjects->subjs[i] ). 然后尝试访问它( subjects->subjs[i] )。 Can you tell me where it points to? 你能告诉我它指向哪里吗? ( subject->subjs )? subject->subjs )?

Answer is nope. 答案不对。 It is pointing to nowhere. 它指向无处。 It contains NULL value now. 现在它包含NULL值。 Don't you think you should tell it how many subject you want to hold and allocate accordingly? 您是否不认为应该告诉您要持有多少subject并相应分配? Yes you should and that's what I did precisely in the example shown. 是的,您应该这样做,而这正是我在所示示例中所做的。

Whenever you have a pointer variable ask yourself what it contains - and if the value is something you know about, not some random garbage value. 每当有指针变量时,请问一问它包含的内容-以及该值是否是您所了解的,而不是一些随机垃圾值。

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

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