Classes, Arrays and file reading

First time poster here =/

So let me begin by saying I'm a little embarrassed to be posting my code considering I have no idea what I am doing and I have search near and far for help. Online classes ftw. I have taken two previous c++ classes and I was doing just fine. Now that I'm in intermediate I am lost.

Here is what I need to accomplish.

Using class hierarchy and arrays I need to write a program that will read off test bank questions from a txt file. Each line on the txt file means something different. The first line describes how many questions there will be. The second line, the type of question that it will be, true/false(TF) or multiple choice(MC) followed by value of the question, 5 or 10. The third line has the question that is asked. The fourth line has the answer. This happens for 3 total questions one of which that is multiple choice of six possible answers.
The goal is to output the question, the value and the answer. I'm assuming on different lines.

Any and all help would be greatly appreciated.
P.S.
Try not to be too hard on me.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  // Question.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <fstream>
#include <sstream>

using namespace std;

class QData
{
public:
	void setQType(string z)
	{
		QType = z;
	}
	string getQType()
	{
		return QType;
	}
	void setQValue(int y)
	{
		QValue = y;
	}
	int getQValue()
	{
		return QValue;
	}
	void setQuestion(string x)
	{
		Question = x;
	}
	string getQuestion()
	{
		return Question;
	}
private:
	string QType;
	string Question;
	int QValue;
};



int _tmain(int argc, _TCHAR* argv[])
{
	QData ObjQuestion;
	QData ObjQType;
	QData ObjQValue;
	string numberQ;
	string line;

	int numQuestion;


	ifstream input("Test.txt");
	getline(input, numberQ);
	stringstream ss(numberQ);
	ss >> numQuestion;
	
	while(numQuestion>0)
	{
			getline(input, line);
			ObjQuestion.setQuestion(line);
			cout << ObjQuestion.getQuestion() << endl;
			numQuestion --;
	}
	


	system("Pause");
	return 0;
}

Could you please describe what you are having trouble with?

So let me begin by saying I'm a little embarrassed to be posting my code considering I have no idea what I am doing

You shouldn't feel embarrassed, everyone has to learn and we have all been there once. Can you post the contents of the Test.txt so I can be clear what it contains.
Here is the Test.txt. Thanks for the confidence haha.

3 - How many questions
TF 5 - What type of question / value of question
The sun is yellow? - Question
true - answer
MC 10 - Type of question / value of question
What is 5+5? - question
6 - how many choices
Two - choice 1 (a)
Three - choice 2 (b)
Six - choice 3 (c)
Seven - choice 4 (d)
Nine - choice 5 (e)
Ten - choice 6 (f)
F - answer
TF 5 - type of question / value of question
A mouse is bigger than an elephant? - question
false - answer

end of text

Last edited on

First off, you shouldn't be creating an object for Question, Type, Value etc.

You are expected to create a Quiz class that is basically going to be your quiz engine, i.e. the class should open the data file, check its opened successfully, parse the data from the file and ask the questions to the user.

You only need one object for that with the necessary private variables to hold the question information (assuming you want to store them and not simply show them). Obviously you would need to store some such as the number of questions to read in for the purpose of looping.

I've provided an example of what I am talking about, and because its an assignment I have purposely not completed the whole thing (and probably provided too much lol)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

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

class CQuiz
{

private:
	// game stuff
	int score;

	// question storage
	int numQuestions;
	int numAnswers;
	std::string questionType;
	int questionValue;
	std::string question;
	std::string mcAnswers[10];
	std::string answer;

	// file stream
	std::fstream quizData;

	bool openQuiz(std::string);
	void closeQuiz();
	void doQuestions();

public:
	CQuiz();
	bool Run(std::string);

};

CQuiz::CQuiz()
{
	score = 0;
}


bool CQuiz::openQuiz(std::string filename)
{
	quizData.open(filename, std::ios::in);
	if (quizData.fail())
		return false;	// problem
	return true;
}

void CQuiz::closeQuiz()
{
	quizData.close();
}

void CQuiz::doQuestions()
{

	// ok, so here we would want to first read in
	// the number of questions we have in the data
	// file.. as you know this is the first line, 
	// we can then use that value to form our
	// data loop...

	std::string data;	// temp storage.

	// read the number of questions. We are reading
	// as strings so in some cases we need to use 
	// stoi to change string to int.

	// http://www.cplusplus.com/reference/string/stoi/

	getline(quizData, data);
	numQuestions = stoi(data);

	// numQuestions will now have 3 based on your
	// example data file. We can use that for our
	// for loop.

	for (int i = 1; i <= numQuestions; i++) {
		
		// we can safely read in question type,
		// question value and question, these
		// are always in the same position in
		// the file.

		// you then need to test what the 
		// question type was because the layout
		// of the file now changes depending 
		// on that, i.e.  TF would just have
		// the expected answer come next, but
		// in MC we have the number of possible
		// answers, then the answers.

		// because this is a assignment, the rest
		// is up to you  :)

		// feel free to ask questions  :)

	}



}

bool CQuiz::Run(std::string filename)
{
	if (openQuiz(filename)) {
		doQuestions();
		closeQuiz();
	}
	else
		return false;	// cant open file.
	return true;
}


int main()
{
	CQuiz Game;

	// i chose to pass the filename
	// in the run function so that
	// we could have multiple files
	// in our game if we wanted.

	if (!Game.Run("Test.txt"))
		std::cout << "Game failed due to missing quiz data.";

	return 0;
}


First off, I want to say you're awesome. You have no obligation whatsoever to respond to my post let alone post useful information and you outdid yourself. I wasn't expecting this much code as help, more of explanation on how these things worked. I will most certainly take it.

One of the main issues I was having was figuring out how to pull the type of question then the value and store it. I'm a little lost on how to read only bits of information from a line and store it and continue to read the rest and store that. Which is what I would assume I would have to do in order to get the question type and value.

Also why do people not use "using namespace std;" and use "std::" for everything?

Thanks again. You're a lifesaver.

One of the main issues I was having was figuring out how to pull the type of question then the value and store it. I'm a little lost on how to read only bits of information from a line and store it and continue to read the rest and store that. Which is what I would assume I would have to do in order to get the question type and value.


If you pay attention to line 71 in my last post which reads getline(quizData, data);, that command reads the whole line into my string variable called data which is fine for lines that don't have multiple data (question etc.).

The problem you have is some lines do have multiple data such as the line that holds the question type and question value, i.e. MC 10. What you need to do here is read those two separately, to do this you can include a third parameter to instruct getline to read until it reaches that character, as an example the below code will read MC only..

getline(quizData, questionType, ' ');

Basically what I am doing there is telling getline to read up to, and ignore space.. so with "MC 10" it would read only MC

so if I were to now go that one step further.. my next lines would be

1
2
3
4

getline(quizData, data);   // read up until end of line
questionValue = stoi(data);  // convert the 10 to integer.


I would now have stored in questionValue an integer value of 10.


EDIT:

Regarding your std:: namespace question, check out this link: http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice


Last edited on
Oh man that's genius. I have used that before but for some reason I had it stuck in my head that it would start on the next line and not start reading from where it left off (at the space).

:)

Oh man, you just lifted the world off of my shoulders. haha. Here is the finished product

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>



class CQuiz
{

private:

	int score;


	int numQuestions;
	int numAnswers;
	std::string questionType;
	int questionValue;
	std::string question;
	std::string mcAnswers[10];
	std::string answer;

	std::fstream quizData;

	bool openQuiz(std::string);
	void closeQuiz();
	void doQuestions();

public:
	CQuiz();
	bool Run(std::string);

};

CQuiz::CQuiz()
{
	score = 0;
}


bool CQuiz::openQuiz(std::string Test)
{
	quizData.open(Test, std::ios::in);
	if (quizData.fail())
		return false;
	return true;
}

void CQuiz::closeQuiz()
{
	quizData.close();
}

void CQuiz::doQuestions()
{
	std::string data;
	std::string qData;
	std::string aData;
	std::string mcData;



	getline(quizData, data);
	numQuestions = stoi(data);

	for (int i = 1; i <= numQuestions; i++) {
		getline(quizData, questionType, ' ');
		if (questionType == "TF"){
			getline(quizData, qData);
			questionValue = stoi(qData);
			getline(quizData, question);
			std::cout << question << " Value: " << questionValue << std::endl;
			getline(quizData, answer);
			std::cout << answer << std::endl;
		}
		if (questionType == "MC"){
			getline(quizData, qData);
			questionValue = stoi(qData);
			getline(quizData, question);
			std::cout << question << " Value: " << questionValue << std::endl;
			getline(quizData, aData);
			numAnswers = stoi(aData);
			for(int j = 1; j<= numAnswers; j++){
				getline(quizData, mcAnswers[j]);
				std::cout << mcAnswers[j] << std::endl;
				}
			getline(quizData, answer);
			std::cout << answer << std::endl;
		}
	}



}

bool CQuiz::Run(std::string Test)
{
	if (openQuiz(Test)) {
		doQuestions();
		closeQuiz();
	}
	else
		return false;
	return true;
}


int _tmain(int argc, _TCHAR* argv[])
{
	CQuiz Game;

	if (!Game.Run("Test.txt"))
		std::cout << "Game failed due to missing quiz data.";

	system("pause");
	return 0;
}


See any room for improvement?
Last edited on

I see you are parsing the data which is good.

You could reuse the data variable, there's no need to create std::string qData; etc. data is just a temporary string used so I could use stoi, once I've done that the data inside it can be overwritten.

So lets take a look at your example text file:

3 - How many questions
TF 5 - What type of question / value of question
The sun is yellow? - Question
true - answer
MC 10 - Type of question / value of question
What is 5+5? - question
6 - how many choices
Two - choice 1 (a)
Three - choice 2 (b)
Six - choice 3 (c)
Seven - choice 4 (d)
Nine - choice 5 (e)
Ten - choice 6 (f)
F - answer
TF 5 - type of question / value of question
A mouse is bigger than an elephant? - question
false - answer


First line is the number of questions, then what we see is 3 common lines regardless of the question type which are Question Type, Question Value and the actual Question. You are repeating code in your IF statements - see what I mean? - Would it not be better to read those 3 lines then check the question type?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39


	for (int i = 1; i <= numQuestions; i++) {
		
		// these are common regardless of 
		// the question type, so its safe
		// to read them in now.. no need to
		// read it in your if statements.
		getline(quizData, questionType, ' ');
		getline(quizData, data);
		questionValue = stoi(data);
		getline(quizData, question);

		if (questionType == "TF") {
			// we are true/false so we
			// only expect the actual
			// answer.
			getline(quizData, answer);
		}
		else
			if (questionType == "MC") 
			{
				// multiple choice
				// the next is the number of available
				// answers to our questions.
				getline(quizData, data);
				numAnswers = stoi(data);
				// start reading them in.
				for (int i = 0; i < numAnswers; i++)
					getline(quizData, mcAnswers[i]);
				// now the expected answer
				getline(quizData, answer);
			}

		// so at this point we have the current question,
		// we can display it, and ask for the answer.

	}


Since this is a quiz, you need to be asking the player what the answer is and not simply listing the answer :)

Lastly, logically the user could have caps lock on or off, and the game should support either, i.e. if I enter TRUE and the txt file has true it would say my answer was wrong.


EDIT:

Earlier today I filled in the rest from my code and here is an example output from it - this should give you an idea of the sort of output expected.


Question 1:
The sun is yellow?

Enter Answer: true

Well done, you are correct!

Question 2:
What is 5+5?
A: Two
B: Three
C: Six
D: Seven
E: Nine
F: Ten

Enter Answer: F

Well done, you are correct!

Question 3:
A mouse is bigger than an elephant?

Enter Answer: false

Well done, you are correct!

Last edited on
Oh man, you just lifted the world off of my shoulders. haha. Here is the finished product

The important thing here is that you are learning from it.
First off, you shouldn't be creating an object for Question, Type, Value etc.

Not sure I agree with this statement. To me a quiz is a set of questions which implies that (from an OO point of view) a Quiz class should have an array (or vector, etc) of Question objects member. (Type and Value are propterties of a question, not the quiz.)

If this question was being asked after studying polymorphism I'd also be expecting specialization for the different type of question, too. The problem does stateent does say "using class hierarchy and array..." but I see no hierarchy in the code posted above.

@JakoMako - As I don't know what you've studied so far I don't know how relevant my comments are. But you do say you doing an intermediate class, which implies you should know all the basics already. And of OOA/D as well as C++ I would hope.

Also, I think running the quiz off of the file is a bit lazy. Should really load the quiz into the question array and then run the quiz off in-memory data. That would you allow the quiz to dump details after the quiz ends (to give the user the correct answers to the ones they got wrong, for example.)

Andy

PS What I can see is that the only member variable which is acting as one is std::fstream quizData;. Everything else is only being used in the scope of CQuiz::doQuestions() and so should be local variables.
Last edited on

@ Andy, I will agree to disagree on your last post.. that's all i will say on this :)

I edited my last one, wording looked bad and it wasnt intended that way, sorry Andy :)
Last edited on
id love you to explain based on his code how that would work then?

I didn't base my comment on his code but on the problem statement. I didn't put a lot of weight on the code after reading JakoMako statement "that I have no idea what I am doing."

The suggestion that a class hierarchy was used, together with this being an exercise for an intermediate course, made me think a more involved solution was being sought. But until JakoMako clarifies what he covered to date I know this is pure supposition.

or does this state "all question data must be stored in arrays".. ?

As the only class hierachy which springs to mind (based on the structure of the data file) involves Question, TFQuestion, and MTQuestion, I guess I would expect to see an array of polymorphic Question objects.

Andy

Last edited on
You could reuse the data variable, there's no need to create std::string qData; etc. data is just a temporary string used so I could use stoi, once I've done that the data inside it can be overwritten.


I thought this would change the numQuestions value and mess up the loop.

First line is the number of questions, then what we see is 3 common lines regardless of the question type which are Question Type, Question Value and the actual Question. You are repeating code in your IF statements - see what I mean? - Would it not be better to read those 3 lines then check the question type?


Good call. They are all stored different. I miss things like this all the time and make more work for myself and the program.


Since this is a quiz, you need to be asking the player what the answer is and not simply listing the answer :)


As strange as this sounds, the instructor did not want any user input from this code. I had to get clarity on this myself.

As I don't know what you've studied so far I don't know how relevant my comments are. But you do say you doing an intermediate class, which implies you should know all the basics already. And of OOA/D as well as C++ I would hope.


Honestly I have taken 2 semesters of VB in high school 10 years ago. More recently I have taken Problem Solving Concepts with C++, Programming with C++ and currently in Intermediate C++ Programming. These classes are online courses so lets be real about how they are not the most in depth classes, especially since I'm in an accelerated degree schedule. 5 week classes. I've done fine up until this class. I feel like I missed something between Programming with C++ and Intermediate C++ Programming. I'm not going for a computer science degree. I'm going for a BS of Information Technology with a study in Cyber Security.
Last edited on

I thought this would change the numQuestions value and mess up the loop.

No, it's just used during string to int conversions and the value we need was transferred into the class member variables.

As strange as this sounds, the instructor did not want any user input from this code. I had to get clarity on this myself.

Indeed it does sound strange, oh well :)
Topic archived. No new replies allowed.