簡體   English   中英

程序未寫入文件,加載時崩潰

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

因此,我需要在二進制文件中進行讀寫操作,但似乎無法做到這一點,並且在使用readFromFile時,程序崩潰。 我需要幫助寫入二進制文件,然后從中讀取文件,然后在關閉程序后恢復工作。我不知道我做錯了什么,而且我已經搜索了很長時間了,但是沒有結果。 這是我程序的代碼:

#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的返回值。 如果為NULL,則繼續或訪問它將是錯誤的。

完成處理后,相應地free()它。


一些基本的事情:

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

現在讓我們看一下代碼。

Op詢問為什么OP應該初始化,而不是初始化; t subjects->num_subjs = 0; subjects->subjs = NULL; subjects->num_subjs = 0; subjects->subjs = NULL; 不夠?

指針是應該保存地址的變量。 這里Subject*將保存類型Subject的變量的地址。

現在,您首先在這里對其進行了初始化。

您已分配的內存,並指派它的地址為Subject*變量subjects

現在,讓我們看看您還做什么。

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

您已初始化。 然后嘗試訪問它( subjects->subjs[i] )。 你能告訴我它指向哪里嗎? subject->subjs )?

答案不對。 它指向無處。 現在它包含NULL值。 您是否不認為應該告訴您要持有多少subject並相應分配? 是的,您應該這樣做,而這正是我在所示示例中所做的。

每當有指針變量時,請問一問它包含的內容-以及該值是否是您所了解的,而不是一些隨機垃圾值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM