Doubt about files in C ++, Basic

2

I just started studying files in C ++. I was trying to do an exercise but I have not been able to get it out.

The statement is as follows:

  

Perform a program that reads the name of a file by keyboard. This file will contain a series of test questions. The number of questions that the file will contain will never be greater than 50.

     

For each question, the file will contain three possible answers and a number indicating which of the three possible answers is correct (see attached example file). In this way, the format of the file will be as follows:

pregunta1 --salto de linea
respuesta_correcta_a_la_pregunta1 salto de linea
respuesta1 salto de linea
respuesta2 salto de linea
respuesta3 salto de linea
pregunta2 salto de linea
respuesta_correcta_a_la_pregunta2 salto de linea
respuesta1 salto de linea
respuesta2 salto de linea
respuesta3 salto de linea
...
     

The program, after loading the data from the file into memory in an appropriate data structure, should perform the test by displaying each of the questions and possible answers on the screen and reading the answer to each question on the keyboard.

     

At the end, the program will display on the screen the answer number correctly answered, the number of answers incorrectly answered and the score calculated according to the following formula:

puntuación = 10 * (respuestas_correctas – (respuestas_incorrectas / 2)) / total_de_preguntas_en_el_fichero
     

Keep in mind that the score should be calculated as a real number.

I leave you my code:

#include <iostream>
#include <fstream>
#include <array>
#include <string>

using namespace std;

const int MAX_PREG = 10;

    struct preguntas{

        string pregunta;
        int respuesta;
        string respuesta1;
        string respuesta2;
        string respuesta3;
    };

    typedef array <preguntas,MAX_PREG> array_dat;

    struct Ttest{
        int np = 0;
        array_dat pr;
    };

int main(){

    int respuesta_introducida;
    int contador = 0;



    Ttest x;
    array_dat y;

    string fichero;

    cout << "Introduce el nombre del fichero " << endl;
    cin >> fichero;

    ifstream fichero1;

    fichero1.open(fichero);

    string linea;
    int correcta;
    //getline(fichero1,linea);
    //contador++;
    while(!fichero1.eof()){

        if (contador == 0 || contador % 4 == 0){
            x.pr[x.np].pregunta = linea;
        }
        if (contador == 1 || contador % 1 == 1){
            x.pr[x.np].respuesta = correcta;
        }
        if (contador == 2 || contador % 2 == 0){
            x.pr[x.np].respuesta1 = linea;
        }
        if(contador == 2 || contador % 2 == 0){
            x.pr[x.np].respuesta2 = linea;
        }
        if(contador == 3 || contador % 3 == 0){
            x.pr[x.np].respuesta3 = linea;
        }

        getline(fichero1,linea);
    }
}

The example txt I was using was this:

De los siguientes animales cual no es un mamifero?
2
La ballena
El pulpo
La vaca
Cuando vale 0 dividido por 5?
1
0
1
No se puede calcular
Un bucle for
2
Puede utilizar una variable de control de tipo double
Tiene que ser determinista
Ninguna de las otras dos respuestas es correcta

The doubts I have is that I do not know how to assign each line to each element of the structure, that is to say, to choose the line that I assign to each element of the structure. From that arises the mess that I have below with the counters, etc

    
asked by Skydez 23.02.2017 в 16:50
source

2 answers

2

Being told that the maximum number of possible questions is 50 does not mean that ALWAYS there will be 50 questions. std::array implements a vector of fixed size and it does not seem very practical because you can not ask how many elements it actually contains (because in your case it will always contain 50 although the file has only 5 questions).

Instead I would recommend using std::vector . This container can store a variable number of elements and a great advantage of it is that you will not have to deal with ghost elements .

// Lo siento, no me gusta usar "using namespace std"
typedef std::vector<preguntas,MAX_PREG> array_dat;

Now we go with the reading.

The readings are supposed to be sequential:

  • The question is read
  • The solution is read
  • Option 1 is read
  • Read option 2
  • Read option 3
  • Then for each question you will have to read 5 lines. This means that, necessarily, you have to call std::getline 5 times within each iteration of while :

    while(true){
    
      // Planteate que lo mismo el nombre de la estructura
      // no es el más adecuado
      preguntas pregunta;
    
      std::getline(fichero1,pregunta.pregunta);
    
      if( pregunta.pregunta.empty() )
        break;
    
      fichero1 >> pregunta.respuesta;
      fichero1.ignore();
    
      std::getline(fichero1,pregunta.respuesta1);
      std::getline(fichero1,pregunta.respuesta2);
      std::getline(fichero1,pregunta.respuesta3);
    
      y.push_back(pregunta);
    }
    

    Two details that may draw attention:

  • The loop does not have an end, by default. Since we will arrive at the end of the file when finding a blank question (according to the file specification that you have been given, the ALWAYS responses have a line break), we will use this empty question to exit the loop.
  • The integer is read differently because there is a special method to read this type of value and not deal with the conversion. The problem with this reading is that it does not eliminate the line break, hence the line fichero.ignore() , which will eliminate the line break.
  • The test vector is filled in on the fly. At the end of the reading just call y.size() to know the number of questions stored (assuming you are using std::vector instead of std::array ).
  • answered by 23.02.2017 в 17:41
    0

    Let's see. A problem to consider in the original code is the following:

    struct Ttest{
            int np = 0;
            array_dat pr;
        };
    

    I understand that you use this structure to store the question number, and its block of questions and answers. However, you can directly use the position of each type structure preguntas within the array for this purpose, so this structure is no longer necessary.

    Regarding the reading of the file, I would recommend that you use two counters: one to take the count of the next block of questions and answers, and another one to handle each line of that block.

    The following code (is yours with some modifications, and is tested) performs the reading of the file and stores it in the structure you defined. Check the code, and from here you can continue with your exercise:

        #include "stdafx.h"
            #include <iostream>
            #include <stdio.h>
            #include <string>
            #include <conio.h>
            #include <fstream>
            #include <array>
    
    
            using namespace std;
    
            const int MAX_PREG = 10;
    
            struct preguntas{
    
                string pregunta;
                int respuesta;
                string respuesta1;
                string respuesta2;
                string respuesta3;
            };
    
            typedef array <preguntas, MAX_PREG> array_dat;
    
            array_dat lista_preguntas;//solo es necesario este array
    
             /*Siempre inicializar las estructuras y variables*/
            void inicializar_arreglo(array_dat arreglo)
            {
                for (int contador = 0; contador < MAX_PREG; contador++)
                {
                    arreglo[contador].pregunta = "";
                    arreglo[contador].respuesta = 0;
                    arreglo[contador].respuesta1 = "";
                    arreglo[contador].respuesta2 = "";
                    arreglo[contador].respuesta3 = "";
    
                }
            }
    
            int main(int argc, _TCHAR* argv[])
            {
                int respuesta_introducida;
                int contador_preguntas = 0;
                int contador_lineas = -1;
                string linea;
                int correcta = 0;
    
                string fichero;
                inicializar_arreglo(lista_preguntas);
                cout << "Introduce el nombre del fichero " << endl;
                cin >> fichero;
    
                ifstream fichero1;
    
                fichero1.open(fichero);
    
                while (!fichero1.eof()){
                    getline(fichero1, linea);
                    contador_lineas++;
                    if (contador_lineas == 0)
                    {
                        lista_preguntas[contador_preguntas].pregunta = linea;           
                    }
    
                    if (contador_lineas == 1)
                    {
                        lista_preguntas[contador_preguntas].respuesta = std::stoi(linea);   
    
    //Se utiliza el stoi para castear el tipo de dato string (de la linea) a int (la variable de la estructura que almacena el número de respuesta correcta)        
                    }
                    if (contador_lineas == 2)
                    {
                        lista_preguntas[contador_preguntas].respuesta1 = linea;         
                    }
                    if (contador_lineas == 3)
                    {
                        lista_preguntas[contador_preguntas].respuesta2 = linea;         
                    }
                    if (contador_lineas == 4)
                    {
                        lista_preguntas[contador_preguntas].respuesta3 = linea;         
    
        /* Cuando llegamos a la ultima respuesta del bloque, se debe inicializar el contador de lineas para leer un nuevo bloque, y se incrementa en uno el contador de preguntas para que se almacene la siguiente*/
                        contador_lineas = -1;
                        contador_preguntas++;
                    }
    
                }
    
    
                contador_preguntas = 0;
                while (contador_preguntas < 10)
                {
                    if (!(lista_preguntas[contador_preguntas].pregunta == ""))
                    {
                        cout << "Pregunta: " << contador_preguntas << endl;
                        cout << "Pregunta" << lista_preguntas[contador_preguntas].pregunta << endl;
                        cout << "Respuesta Correcta" << lista_preguntas[contador_preguntas].respuesta << endl;
                        cout << "Respuesta 1" << lista_preguntas[contador_preguntas].respuesta1 << endl;
                        cout << "Respuesta 2" << lista_preguntas[contador_preguntas].respuesta2 << endl;
                        cout << "Respuesta 3" << lista_preguntas[contador_preguntas].respuesta3 << endl;            
                    }
                    contador_preguntas++;
                }
    
                cin >> correcta;
    
    
                return 0;
            }
    

    One more annotation that will help you in the development of your programs: use descriptive names (do not be afraid they are long) for your variables and procedures, you can see that it is easier to read and understand:

    lista_preguntas[contador_preguntas].pregunta = linea;
    

    That for example:

    x.pr[x.np].pregunta = linea;
    

    This will not give you much trouble to follow the logic of your code.

        
    answered by 23.02.2017 в 17:54