2017-11-29 16 views
0

私はバイナリファイルとの間で書き込みや読み込みが必要ですが、読み込みできないようですが、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; 
     } 
    } 
} 

答えて

2

&subjects->subjs[i],これは未定義の動作です。ガベージ値へのアクセス。適切なメモリアドレスを適切に初期化する必要があります。あなたはどこにでもいけません。

(*subjects).subjsまたはsubjects->subjs - >これはどこにも指していません。それはNULLです。

また、ここではダブルポインタは必要ありません。 1つのポインタがあなたがしたいことをするでしょう。単一のポインタについては

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

これはmallocのそれぞれは、それの戻り値をチェックする必要があります

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

ようなものです。 NULLの場合は、さらに進んだりアクセスしたりするとエラーになります。

そしてfree()それに応じて作業を終えたときにそれに応じて


いくつかの基本的な事柄: -

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

今度は、コード内のビットを見てみましょう。

オペアンプを初期化してisnする必要がある理由について質問しました; subjects->num_subjs = 0; subjects->subjs = NULL;で十分ではありませんか?

ポインタは、アドレスを保持するはずの変数です。ここではSubject*はタイプSubjectの変数のアドレスを保持します。

ここで最初に初期化しました。

Subject*変数subjectsにメモリを割り当て、そのアドレスを割り当てました。

他に何をしているかを見てみましょう。

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

これを初期化しました。そしてそれにアクセスしようとします(subjects->subjs[i])。それがどこに指しているか教えていただけますか? (subject->subjs)?

答えはnopeです。それはどこにも向いていない。それは現在NULL値を含んでいます。それに応じてどれくらい多くの番号を保持したいのですか?subjectはい、あなたはそうしなければなりません、そして、それは私が示した例で正確にしたことです。

あなたがポインタ変数を持っているときはいつでも、それが何を含んでいるのかを尋ねてください。値があなたが知っているものであれば、ランダムなごみ値ではありません。

+0

どうすればいいですか?私は全体の構造体を印刷する必要があります – Tom

+0

私はまだそれを得ることはありません、申し訳ありません、私はちょうど初心者 – Tom

+0

@トム:それは、主なアイデアをprinitngについてではない不確定なポインタ値にアクセスすることです。ここにポインターへのポインターは必要ありません。あなたがそれを使用したとしても、それを初期化するのにアクセスしています。 – coderredoc

関連する問題