

学校の課題でわからない点があるので質問させていただきます。  
課題の内容は、構造体と外部ファイルを使いユーザーに問題を提供するというものです。  
構造体の内容は、char key []と char level[] と char question[] です。  
keyというのは、問題のトピックで、conditional, loop, function, structureのうちどれかです。  
levelというのは、問題の難易度で、easy, medium, hardのうちのどれかです。  
questionというのは、問題の内容です。  
５つの構造体を作り、そのうち４つにはすでに情報の入ってるconditionals.txt, loops.txt, functions.txt,
structures.txtを読み込みます。  
そしてもう一つの構造体には、ユーザーが新しく情報を入れれるようにからの状態にしておきます。

まず外部ファイルがちゃんとそれぞれの構造体に読み込まれてませんでした。  
そしてadd.txtにユーザーが打ち込んだ新しい情報が入ってませんでした。

エラーコードは出ませんでした。

とても複雑になっているため、読みにくいと思います。すみません。  
意見をいただけたら嬉しいです。  
以下が外部ファイルです。  
外部ファイル

conditionals.txt

[code]

    Conditionals:Easy:In an if statement what is the operator that is used to check if at least one is correct? 
    Conditionals:Medium:Convert a percentage grade to a letter grade using if-else statements
    Conditionals:Medium:What type of operator will return true even if one of them is false?
    Conditionals:Medium:Create a conditional loop that will not let the user proceed unless they enter “Y” or “N”.
    Conditionals:Easy:Write an if statement which checks if a number inputted by the user is less than 10
    Conditionals:Medium:Convert an integer to a float number and vice versa.
    Conditionals:Hard:Make an if statement for a program that solves an addition (x + y) only if the x and y values are multiples of 5, without being able to use absolute zero for either.
    Conditionals:Easy: A statement “if ( a = b ) “ is correct or not. Yes or not
    
[/code]

loops.txt

[code]

    Loops:Medium:Write a loop that capitalizes all lower case letters in a character array without using the cctype library
    Loops:Easy:Write a loop outputting all even numbers in array
    Loops:Easy:Which type of loop will always execute at least once? 
    Loops:Hard:Create a For Loop that increments more than one counter at the same time and ends when one of the counters, or the sum of both is greater than or equal to 10. 
    Loops:Hard:A do-while loop will always be executed at least once
    Loops:Medium:Create a for loop to read data from an array. 
    Loops:Hard:Write a loop that counts the number of letter “e” in a phrase input by user (max length 100 char), and output a message every 5 times it counts an “e.”
    Loops:Easy:while loop is executed once at least. Yes or not.
    
[/code]

functions.txt

[code]

    Functions:Easy:Write a function that returns an integer that is double the value of the function’s argument
    Functions:Easy:can you pass an int and char type in your functions argument? (y/n)
    Functions:Hard:What is the difference between passing by value and passing by reference?
    Functions:Easy:Create a function that takes in an integer from a user as one of it’s arguments and outputs to the user the squared value of the input value.
    Functions:Easy:What is the symbol we use for indicating that we are passing an argument by reference?
    Functions:Medium:Create a function to store int and char data and pass it by reference.
    Functions:Hard:Create a function that reads in two numbers and can add, subtract, etc.. similar to our first calculator program.
    Functions:Easy:When you want to change value in main function, you should use pass by value. Yes or not.
    
[/code]

structures.txt

[code]

    Structures:Easy:Create a structure that can contain a person’s name, age, and phone number
    Structures:Easy: how do we access a structure notation? - “DOT” 
    Structures:Medium:Can you store a struct into another struct?(y/n)
    Structures:Easy:Create a structure with 4 different members, each a different data type.
    Structures:Easy: what is the keyword we use to declare a structure in a program?
    Structures:Easy:When and how do you pass a struct by value?
    Structures:Easy: Create a structure that holds three arrays of three different sizes
    Structures:Easy: All data type in structure must be the same. Yes or not.
    
[/code]

以下がコードです。

[code]

    #include <iostream>
    #include <cctype>
    #include <cstring>
    #include <fstream>
    using namespace std;
    
    const int KEY = 20;
    const int LEVEL = 10;
    const int QUESTION = 100;
    const int NUM = 10;
    
    struct info
    {
      char key[KEY];
      char level[LEVEL];
      char question[QUESTION];
    };
    
    int menu1_choice(int option);
    void menu1(int option, info conditionals [], info loops[], info functions[], info structures[],info add[], int num_to_save);
    int menu2(int option);
    int menu3(int option);
    void display_type_of_topic(int option, info conditionals [], info loops[], info functions[], info structures[]);
    void display(info topic[]);
    void display_type_of_level(int option, info conditionals [], info loops[], info functions[], info structures[]);
    void display2(info topic[], char level []);
    void load_choice(info conditionals [], info loops[], info functions[], info structures[], info add[]);
    void load(info topic[], char topic1[]);
    void read_info(info add[],int &num_to_save);
    void read_a_info(info &add);
    void save(info add[], int num_to_save);
    void exit();
    
    int main()
    {
      info conditionals[NUM];
      info functions[NUM];
      info loops[NUM];
      info structures[NUM];
      info add[NUM];
      int option1 = 0; 
      int num_to_save =0;
    
      load_choice(conditionals, loops, functions, structures, add);
    
      option1 = menu1_choice(option1);
      menu1(option1, conditionals , loops, functions, structures, add, num_to_save);
    
      save(add, num_to_save);
    }
    
    int menu1_choice(int option)
    {
      cout <<"Hello! This program help you learn CS162. Please select option below within 1 ~ 4." << endl;
      cout <<"[MENU]" << endl;
      cout <<"1. Display the information about a particular type of question" << endl;
      cout <<"2. Display just a particular level of question" << endl;
      cout <<"3. Add new question to data file" << endl;
      cout <<"4. Exit from this program" << endl;
      cin >> option;
      return option;
    }
    
    void menu1(int option, info conditionals [], info loops[], info functions[], info structures[], info add [], int num_to_save)
    {
      if (option == 1)
      { 
        int option2 =0;
        option2 = menu2(option2);
        display_type_of_topic(option2, conditionals , loops, functions, structures);
      }
      else if (option ==2)
      {
        int option3 =0;
        option3 = menu3(option3);
        display_type_of_level(option3, conditionals, loops, functions, structures);
      }
      else if (option == 3)
      
      read_info(add, num_to_save);
      
      else if (option == 4)
      exit();
    }
    
    void load_choice(info conditionals [], info loops[], info functions[], info structures[], info add[])
    {
      char conditionals1 [KEY] = "conditionals.txt";
      char loops1 [KEY] = "loops.txt";
      char functions1 [KEY] = "functions.txt";
      char structures1 [KEY] = "structures.txt";
      char add1 [KEY] = "add.txt";
      load(conditionals, conditionals1);
      load(loops, loops1);
      load(functions, functions1);
      load(structures, structures1);
      load(add, add1);
    }
    
    void load(info topic[],char topic1[])
    { 
      ifstream file_in;
      int i =0;
    
      file_in.open(topic1);
      if (file_in)
      {
        file_in.get(topic[0].key, KEY, ':'); file_in.ignore(100, ':');
    
        while (!file_in.eof())
        {
          file_in.get(topic[i].level, LEVEL, ':'); file_in.ignore(100, ':');
          file_in.get(topic[i].question, QUESTION, ':'); file_in.ignore(100, ':');
          ++i;
          file_in.get(topic[i].key, KEY, ':'); file_in.ignore(100, ':');
        }
        file_in.close();
      }
    }
    
    int menu2(int option)
    { 
      do
      {
        cout <<"Please select topic" << endl;
        cout <<"1. Conditionals" << endl;
        cout <<"2. Loops" << endl;
        cout <<"3. Functions" << endl;
        cout <<"4. Structures" << endl;
    
        cin >> option;
    
        if(option < 1 || option >4)
        cout << "please enter again." << endl;
      }while(option < 1 || option > 4);
      return option;
    }
    
    void display_type_of_topic(int option, info conditionals [], info loops[], info functions[], info structures[])
    {
      if (option == 1)
      display(conditionals);
      else if (option == 2)
      display(loops);
      else if (option == 3)
      display(functions);
      else if (option == 4)
      display(structures);
    }
    
    void display(info topic[])
    {
      for(int i = 0; i <NUM; ++i)
      {
        cout << topic[i].key << endl;
        cout << topic[i].level<< endl;
        cout << topic[i].question << endl;
      }
    }
    
    int menu3(int option)
    { 
      do
      {
        cout <<"Please select level" << endl;
        cout <<"1. Easy" << endl;
        cout <<"2. Medium" << endl;
        cout <<"3. Hard" << endl;
    
        cin >> option;
    
        if(option < 1 || option >3)
        cout << "please enter again." << endl;
      }while(option < 1 || option > 3);
      return option;
    }
    
    void display_type_of_level(int option, info conditionals [], info loops[], info functions[], info structures[])
    {
      if(option == 1)
      { 
        char level [LEVEL] = "Easy";
        display2(conditionals, level);
        display2(loops, level);
        display2(functions, level);
        display2(structures, level);
      }
      else if (option == 2)
      {
        char level[LEVEL] = "Medium";
        display2(conditionals, level);
        display2(loops, level);
        display2(functions, level);
        display2(structures, level);
      }
      else if (option == 3)
      {
        char level [LEVEL] = "Hard";
        display2(conditionals, level);
        display2(loops, level);
        display2(functions, level);
        display2(structures, level);
      }
    }
    
    void display2(info topic[], char level [])
    {
      for(int i = 0; i < NUM; ++i)
      {
        if(strcmp(topic[i].level, level)== 1)
        {
          cout << topic[i].key << endl;
          cout << topic[i].level << endl;
          cout << topic[i].question << endl;
        }
      }
    }
    
    void read_info(info add[],int &num_to_save)
    {
      int i = num_to_save;     
      char response = 'n'; //allow the user to decide when to be done     
      cout << "Do you want to read in a new info? ";     
      cin >> response;     
      cin.ignore(100, '\n');     
      
      //Read in the movies if the user wants to     
      while ('Y' == toupper(response) && i < NUM)     
      {         
        read_a_info(add[i]);         
        cout << "Another? ";
        cin >> response;         
        cin.ignore(100, '\n');        
        ++i;     
      }     
      //Update the number of movies     
      num_to_save = i;                   
    }
    
    void read_a_info(info & add)
    {    
      //Prompt and read in the title, information, and # of stars    
      cout << "Please enter the topic: ";    
      cin.get(add.key, KEY, '\n');  cin.ignore(100, '\n');    
      cout << "Enter the difficulty: ";    
      cin.get(add.level, LEVEL, '\n');  cin.ignore(100, '\n');    
      cout << "Enter the question: ";    
      cin.get(add.question, QUESTION, '\n');  cin.ignore(100, '\n');
    }
    
    void save(info add[], int num_to_save)
    {
        ofstream file_out;
        //file_out.open("movie.txt", ios::app);    
        file_out.open("add.txt");    
        if (file_out)    
        {        
          for (int i = 0; i < num_to_save; ++i)        
          {            
            file_out << add[i].key << ':'                      
            << add[i].level <<':'                     
            << add[i].question <<endl;    
          }        
          file_out.close();    
        }
    }
    
    void exit()
    {
      cout <<"Thank you so much using the program!" << endl;
    }
    
[/code]


CC BY-SA 4.0
2021-02-18T00:38:03.587
74083
2021-02-18T11:56:43.213
2021-02-18T01:06:00.600
3060
44009
question
c++
構造体に外部ファイルを読み込む


> まず外部ファイルがちゃんとそれぞれの構造体に読み込まれてませんでした。

`load()`と`read_a_info()`の処理を見較べてみると分るでしょう。  
`QUESTION`の区切り文字の指定が違います。

> そしてadd.txtにユーザーが打ち込んだ新しい情報が入ってませんでした。

`menu1()`がsaveすべきデータの数を呼び出し元まで通知出来ないようなパラメータ型になっています。  
そのため`save()`に渡す`add.txt`にセーブすべきデータ数は常に`0`と判断されます。

* * *

それ以外にも以下のような不具合があります。

  * `main()`の各`info`構造体配列の領域が初期化されていません。
  * `main()`は或る機能を１つだけ実行すると、メニューで`4`を選択せずとも、そのまま終了してしまいます。  
そしてあるべき姿の処理になった時に、ちゃんと終了させる処理が未だありません。

  * `display()`は各`topic`の構造体で、データが存在しない(サンプルの????.txtは各8行しか無いが、`main()`の各`info`構造体配列は10個分ある)インデックスも表示処理してしまいます。  
各topicの構造体領域を初期化していないのと併せて、例えばデバッグ時などにはおかしな表示になるか、そうでなくても空白行の連続が表示されるでしょう。

  * `display2()`は指定された`level`のデータを表示出来ていません。

* * *

以下は個々人の考え方依存レベルの指摘です。

  * `load()`の各テキスト行読み取りとデータの区切りの判定・ループ処理が、何というか綺麗で無く判り難い処理になっている気がします。
  * `exit()`という標準のライブラリ[std::exit](https://cpprefjp.github.io/reference/cstdlib/exit.html)と紛らわしい名前で用途の違う関数を独自に定義するのはやめた方が良いでしょう。
  * 多くの関数で全ての`info`構造体配列をパラメータに指定してデータを受け渡している方式はやめて、インタフェースの取り方/指定方法は考え直した方が良いでしょう。


CC BY-SA 4.0
2021-02-18T11:56:43.213
74107
2021-02-18T11:56:43.213
26370
74083
answer