C++ Member Vector Inaccurate Values - c++

I've created a class called "Person" which holds a name, three sets of high scores and a picture link. I am reading from a text file that contains all of these variables and create several "Person" objects accordingly,then put them into a vector of "Person" objects.
This is the function that takes in an empty vector and outputs a vector with Persons added.
void input_data(vector<Person>& input){
ifstream ifs("personData.txt");
while (true) {
if (ifs.eof()) {
return;
}
Person n;
string name;
string picture;
string check;
int t1;int t2;int t3;
int r1;int r2;int r3;
int f1;int f2;int f3;
getline(ifs,name); // use getline to deal with spaces
getline(ifs,picture); // use getline to deal with spaces
ifs >> t1 >> t2 >> t3;
ifs >> r1 >> r2 >> r3;
ifs >> f1 >> f2 >> f3;
ifs.ignore(100, '\n');
getline(ifs,check); // use getline to deal with spaces
n.setName(name);
n.setPic(picture);
n.addScore(3, t1);n.addScore(3, t2);n.addScore(3, t3);
n.addScore(4, r1);n.addScore(4, r2);n.addScore(4, r3);
n.addScore(5, f1);n.addScore(5, f2);n.addScore(5, f3);
input.push_back(n);
if(check == ""){
cout << endl << "breaking" << endl;
break;
}
}
}
As you can see, using the "addScore" function, I intend to change the vector of scores in each Person according to the inputted type (3, 4 , or 5). Here is the Person class that is use. The logic for adding the values to the vector is used to maintain a size of 3 in each vector, and so I add the new value to the vector, sort it, and then delete the smallest entry. This gives me tht top three high scores.
class Person{
private:
//basic member functions
string name;
string pic;
vector<int> highThree;
vector<int> highFour;
vector<int> highFive;
public:
//constructor jsut makes eveything zero
Person(string m_name = "", string m_pic = ""):
name(m_name),
pic(m_name),
//initializing every vector to three instnace of 0
highThree(3,0),
highFour(3,0),
highFive(3,0){}
//manipulating member functionsjj
void setName(string i_name){name = i_name;}
string getName(){return name;}
void setPic(string i_pic){pic = i_pic;}
string getPic(){return pic;}
//logic for adding to the highschores
void addScore(int gameType, int val){
//(which is sorted), then add it and sort it again
if (gameType == 3){
//name = "yo";
highThree.push_back(val);
//sort the vector
sort(highThree.begin(), highThree.end());
//erase the first thing
highThree.erase(highThree.begin());
}
if (gameType == 4){
highFour.push_back(val);
sort(highFour.begin(), highFour.end());
highFour.erase(highThree.begin());
//cout << val << endl;
}
if (gameType == 5){
highFive.push_back(val);
sort(highFive.begin(), highFive.end());
highFive.erase(highThree.begin());
//cout << val << endl;
}
}
//gets the three score vecotors
vector<int>& getScores(int gameType){
if (gameType == 3){
for(int i = 0; i<highThree.size(); i++){
cout << highThree[i] << endl;
}
return highThree;
}else if(gameType == 4){
return highFour;
}else if(gameType == 5){
return highFive;
}else{
cout << "error in getScores input\n";
vector<int> bad;
return bad;
}
}
};
In main, when I try to access the scores in one of these member vectors, I get results that are not accurate to what I took in from the file. In fact, I printed out my input values in the "addScore" function as well as in the "input_data" function, and they are correct. This means that I'm getting data from the file accurately, but there is something wrong afterword.
int main(){
vector<Person> peeps;
input_data(peeps);
//the value that i get below is wrong
cout << peeps[0].getScores(3)[0];
}
The value that I get in the print above is 0, when it should be 8
. The text file that I'm reading from is attached below. I apologize for a such a long post, but I've spoken to all of my team mates about the issue and cant seem to figure out what is going wrong. There seems to be an issue with retrieving the contents of the member vector, but I cant find the issue.
bob
mypic
8 9 10
3 4 5
2 7 6

Related

ifstream getline - Reading txt File to an array of objects, but it's only reading the first line?

I'm writing a beginner program that takes a text file of 10 trivia questions and answers, reads the file, puts the questions and answers into an array, and then uses the questions for a trivia game.
Currently, I'm having an issue reading the file into the array. Only the first line of the file is being read.
I'm new to debugging, but I tried to rewrite the program with Vectors and had the same issue.
Here is the trivia file (the number at the end of the answers is the correct answer):
The Gettysburg Address
The US Declaration of Independence
The Magna Carta
The US Bill of Rights
2
(2) Who said "A billion dollars isn't worth what it used to be"?
J. Paul Getty
Bill Gates
Warren Buffet
Henry Ford
1
(3) What number does "giga" stand for?
One thousand
One million
One billion
One trillion
3
(4) What number is 1 followed by 100 zeros?
A quintillion
A googol
A moogle
A septaquintillion
2
(5) Which of the planets is closest in size to our moon?
Mercury
Venus
Mars
Jupiter
1
(6) What do you call a group of geese on the ground?
skein
pack
huddle
gaggle
4
(7) What do you call a group of geese in the air?
skein
pack
huddle
gaggle
1
(8) Talk show host Jerry Springer was the mayor of this city.
Chicago
Indianapolis
Cincinnati
Houston
3
(9) On a standard telephone keypad, the letters T, U, and V are matched to what number?
5
6
7
8
4
(10) Crickets hear through this part of their bodies.
Head
Knees
Ears
Tail
2
Here is my program currently:
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;
//Question class
class Question{
private:
string triviaQuestion;
string answer1;
string answer2;
string answer3;
string answer4;
int correctAnswer; //1,2,3 or 4
public:
Question();
//mutator functions
void setTriviaQuestion(string);
void setAnswer1(string);
void setAnswer2(string);
void setAnswer3(string);
void setAnswer4(string);
void setCorrectAnswer(int);
//accessor functions
string getTriviaQuestion();
string getAnswer1();
string getAnswer2();
string getAnswer3();
string getAnswer4();
int getCorrectAnswer();
};
//Question class member functions
Question::Question(){
//initialize member variables
correctAnswer = 0;
triviaQuestion = " ";
answer1 = " ";
answer2 = " ";
answer3 = " ";
answer4 = " ";
}
void Question::setTriviaQuestion(string question){
triviaQuestion = question;
}
void Question::setAnswer1(string option) {
answer1 = option;
}
void Question::setAnswer2(string option) {
answer2 = option;
}
void Question::setAnswer3(string option) {
answer3 = option;
}
void Question::setAnswer4(string option) {
answer4 = option;
}
void Question::setCorrectAnswer(int number) {
correctAnswer = number;
}
string Question::getTriviaQuestion(){
return triviaQuestion;
}
string Question::getAnswer1() {
return answer1;
}
string Question::getAnswer2() {
return answer2;
}
string Question::getAnswer3() {
return answer3;
}
string Question::getAnswer4() {
return answer4;
}
int Question::getCorrectAnswer() {
return correctAnswer;
}
//main function
int main() {
//variables
int playerOneScore = 0;
int playerTwoScore = 0;
string holder = " ";
const int ARRAY_SIZE = 10;
Question triviaInfo[ARRAY_SIZE];
//check for a file's existence before opening it
ifstream dataFile;
dataFile.open("trivia.txt");
if (dataFile.fail()){
//The file does not exist
cout << "ERROR: Cannot open trivia File.";
}
else{
//the file already exists
//get the data from the file and put into the Question array
//for each element of the array
int fiveLineCounter = 0;
int arrayCounter = 0;
while (getline(dataFile, holder)){
cout << holder << endl; // test to see what's being entered
if (fiveLineCounter == 0){
triviaInfo[arrayCounter].setTriviaQuestion(holder);
fiveLineCounter++;
}
if (fiveLineCounter == 1){
triviaInfo[arrayCounter].setAnswer1(holder);
fiveLineCounter++;
}
if (fiveLineCounter ==2){
triviaInfo[arrayCounter].setAnswer2(holder);
fiveLineCounter++;
}
if (fiveLineCounter == 3){
triviaInfo[arrayCounter].setAnswer3(holder);
fiveLineCounter++;
}
if (fiveLineCounter == 4){
triviaInfo[arrayCounter].setAnswer4(holder);
fiveLineCounter++;
}
if (fiveLineCounter == 5){
triviaInfo[arrayCounter].setCorrectAnswer(stoi(holder));
arrayCounter++;
fiveLineCounter = 0;
}
}
}
return 0;
}
When I run the program, this is the current output:
(1) What famous document begins: "When in the course of human events..."?
Process finished with exit code 0
Would really appreciate any help or pointers on how to fix this.
Thank you!
fiveLineCounter starts as zero. So if (fiveLineCounter == 0){ check is true, the code calls setTriviaQuestion(holder) and increments fiveLineCounter; it's now 1.
Then the next check if (fiveLineCounter == 1){ is true, so the code calls setAnswer1(holder) (with the same line in holder) and and increments fiveLineCounter; it's now 2.
Then the next check if (fiveLineCounter == 2){ is true, ...
This continues until setCorrectAnswer(stoi(holder)). Whereby stoi(holder) throws an exception, because the contents of holder (still the first line of the file) can't be parsed as an integer.

Why string comparison results an infinite loop

I have a Plane's entity class such as:
class Plane{
private:
string tailNumber;
public:
void setTail(string tail);
string getTail();
}
and a Planes' collection class such as:
class Planes{
public:
void addPlane();
void printDetails();
void printAllPlanes();
private:
vector<Plane> currentPlane;
}
addPlane definition:
void Planes::addPlane(){
Plane a;
string temp;
cout << "Enter tail:";
getline(cin, temp);
a.setTail(temp);
currentPlane.push_back(a);
}
My printDetails definition:
void Planes::printDetails()
{
cout << "Enter Plane's Tail Number: ";
getline(cin, tail);
cin.ignore();
for (unsigned int i = 0; i < currentPlane.size(); i++)
{
if (currentPlane[i].getTailNumber() == tail)
{
//print tail number by calling accessor function}
}
else
{
cout << "Error.";
}
}
and my main class:
int main(){
Plane a;
int userChoice;
do{
cout << "1.Add Plane";
cout << "2.Print All Planes";
cout << "3.Print a plane";
cout << "4.Quit";
cin >> userChoice;
if (userChoice == 1)
a.addPlane();
else if (userChoice == 2)
a.printAllPlanes();
else if (userChoice == 3)
a.printDetails();
}while (userChoice != 4);
return 0;
}
I am successfully adding a new object and print all objects in my vector to display. The problem is if my tail number is: "TGA", then running currentPlane[0].getTail() return "TGA". However, when compare the user-input variable tail = "TGA" with currentPlane[0].getTail() = "TGA" yields an infinite-loop of do-while menu for some reason that I do not understand (because it is a simple string comparison?).
If I only enter integer value such as "12345", then it will jump to the else branch instead of infinite-looping. If I enter any alphanumeric value, then the infinite-looping will appear again.
Can you help me, please?
Nothing to do with string comparisons, the problem with your code is at no point do you set the variable userChoice.
Presumably you meant to have some code somewhere like
cin >> userChoice;
but you don't have anything like that, so the behaviour of your program is undefined.
You really should have had a compiler warning telling you that you are using an uninitialised variable. Pay attention to compiler warnings and fix any that you get.

Sorting string array alphabetically in a 2D array (C++)

I have coded thus far and I am not sure how to sort using the 2-dimensional array. Basically, one function is for sorting an array of strings, another function is for swapping two strings. Any help would be appreciated. (Also I am not allowed to use c++ 11 :/)
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
void input_name(string&);
void sort_names(string&);
void repeat_pro(int&);
void sortArray(string, int);
int main() {
string b_list[100][2];
string name;
int choice;
int count=0;
cout << "Welcome to the Business Sorting Program!" << endl;
do{
input_name(name);
b_list[count][1] = name;
count++;
repeat_pro(choice);
cout<<"\n \n Your Businesses are:"<<endl;
for(int j=0; j<count; j++){
cout<<b_list[j][1]<<endl;
}
cout << "\n\n";
}while(choice == 0);
cout << "Thanks for using this program"<<endl;
return 0;
}
void input_name(string &name){
cout << "Enter in the name of the business: ";
getline(cin, name);
}
void sort_names(string &name){
}
void repeat_pro(int &choice){
cout << "Do you want to enter in more names: ";
string answ;
cin>>answ;
cin.ignore(1000,'\n');
if (answ == "YES" || answ == "Y" || answ == "yes" || answ == "y"){
choice = 0;
}
else {
choice = 1;
}
}
it is not clear to me from the description what problem the program really tried to solve. I'm assuming it's kind of like a two column spreadsheet, the second column is the name entered by the user(but what is in the first column?).
assume you need to keep the array in sorted order as the data goes in, just do a binary search (you can do a linear search for small dataset like 100 entries).
// we don't have lambda before C++11
struct comparator {
bool operator () (const string (&x)[2], const string (&y)[2]) const {
return x[1] < y[1];
}
};
//... omitted
string data[100][2];
int count = 0;
while (count < 100) {
// no rvalue, move, rvo, etc. before C++11
string name;
input_name(name);
// no type deduction and lambda
string (*position)[2] =
std::lower_bound(&data[0], &data[count], name, comparator());
int index = position - &data[0];
// simulate an vector::insert operation, but for our array
for (int i = count; i > index; --i) {
// before we had move in C++, we would do swap with an empty element.
// in this case, the entry at data[count] is default constructed
std::swap(data[i][1], data[i-1][1]);
}
data[index][1] = name;
}
//... omitted
of course we can use a typedef to make it cleaner, but that's left to you.

Sorting Linked Lists - move nodes or swap data members?

I have a simple question. I'm working on a C++ app that is a contact list app. It stores names, addresses, numbers, ages, etc for multiple people. I'm using stucts and linked lists (nodes). I'm building the sort list function, to alphabetize the list. I'm currently wondering if it's better to actually reorder the list by moving the structs as a whole or by swapping the data members inside each node. At first, I considered moving the nodes, but now swapping the data members seems more safe, as I don't have to reorder the list. At any rate, I don't know if either possesses any benefits over the other.
EDIT: Here's the source code I'm working on. Notice the sort function is incomplete. Also, I'm still a novice programmer, so the coding will probably have a ton of issues, from a professional standpoint. That, alongside the fact I'm not close to being done with it. I'm only writing it to practice coding over my summer break between programming classes.
#include <iostream>
#include <fstream>
#include <string.h>//for functions in date function
#include <time.h> //for functions in date function
#include <sys/stat.h>//for mkdir functions
#include <unistd.h>//for usleep function
#include <ctype.h>//for toupper function in swap function
using namespace std;
struct PersonInfo
{
char FirstName[20];
char LastName[20];
char Address[40];
char PhoneNumber[20];
int Age;
PersonInfo *Link;
};
bool EmptyFileChecker(ifstream &FI, const char *P);
void AddPeopleToList(PersonInfo *&HeadPointer);
void RebuildOldList(ifstream &FI, PersonInfo *&HeadPointer, const char *P);
void DisplayList(PersonInfo *HeadPointer);
void SaveSettings(ofstream &FO, const PersonInfo *HeadPointer, const char *P);
void DisplayMenu(PersonInfo *&HeadPointer, const char *P, ifstream &FileIn, ofstream &FileOut);
void SortContacts(PersonInfo *&HeadPointer);
bool NamesInOrder(const char LastName1[], const char LastName2[]);
string Date();
//Delete Contact
//ENCRYPT LIST?
//Check for memory leaks in code and destructor?
//Return something - noun-like
//void adjective - like
int main()
{
PersonInfo *HeadPointer;
const char *Path = "/Users/josephlyons/Library/Application Support/The Lyons' Den Labs/TheLyons'DenContactInformation.txt";//code variable for username
ifstream FileIn;
ofstream FileOut;
mkdir("/Users/josephlyons/Library/Application Support/The Lyons' Den Labs", ACCESSPERMS);//MODE??
if (!EmptyFileChecker(FileIn, Path))
AddPeopleToList(HeadPointer);
else
RebuildOldList(FileIn, HeadPointer, Path);
DisplayMenu(HeadPointer, Path, FileIn, FileOut);
//SortContacts(HeadPointer);
SaveSettings(FileOut, HeadPointer, Path);
}
void DisplayMenu(PersonInfo *&HeadPointer, const char *P, ifstream &FileIn, ofstream &FileOut)
{
short int MenuChoice;
do
{
cout << "(1) Display Contact List\n";
cout << "(2) Organize Contact List\n";//delete when done with program and automatically sort list before saving.
cout << "(3) Add Contact/s\n";
cout << "(4) Delete Contact/s\n";
cout << "(5) Quit\n\n";
cout << "Choice: ";
cin >> MenuChoice;
if (MenuChoice == 1)
DisplayList(HeadPointer);
else if (MenuChoice == 2)
SortContacts(HeadPointer);
else if (MenuChoice == 3)
AddPeopleToList(HeadPointer);
else if (MenuChoice == 4)
cout << "choice 4";
}
while(MenuChoice != 5);
}
bool EmptyFileChecker(ifstream &FI, const char *P)//DONE
{
FI.open(P);
if (FI.fail())
return false;
else if (FI.eof())//return 0 if file doesnt exist or if file is empty
return false;
else
return true;
}
void AddPeopleToList(PersonInfo *&HeadPointer)
{
PersonInfo *CurrentPosition;
char UserChoice;
do
{
CurrentPosition = new PersonInfo;
if (CurrentPosition == NULL)
{
cout << "Not enough memmory to make new contact.";
return;
}
cout << "\nEnter First Name: ";
cin >> CurrentPosition->FirstName;
CurrentPosition->FirstName[0] = toupper(CurrentPosition->FirstName[0]);//automatically capitalize first name
cout << "Enter Last Name: ";
cin >> CurrentPosition->LastName;
CurrentPosition->LastName[0] = toupper(CurrentPosition->LastName[0]);//automatically capitalize last name
cin.ignore();//flushes a single newline left in input buffer from previous cin >>
cout << "Enter Adress: ";
cin.getline(CurrentPosition->Address, 40);//using cin.get() to allow for spaces in address
cout << "Enter Phone Number: ";
cin.getline (CurrentPosition->PhoneNumber, 20);//using cin.get() to allow for spaces in number
cout << "Enter Age: ";
cin >> CurrentPosition->Age;
cout << "\nAdd another contact? Y/N: ";
cin >> UserChoice;
cout << "\n";
CurrentPosition->Link = HeadPointer;
HeadPointer = CurrentPosition;
}
while (UserChoice == 'y' || UserChoice == 'Y');
SortContacts(HeadPointer);
}
void RebuildOldList(ifstream &FI, PersonInfo *&HeadPointer, const char *P)
{
PersonInfo *TemporaryPersonPointer;
char EndOfListChecker = 1;//initialized at a not 0 to allow entrance into loop
while (EndOfListChecker != 0)
{
TemporaryPersonPointer = new PersonInfo;
if (TemporaryPersonPointer == NULL)
cout << "Not enough memory to generate the full list";
FI >> TemporaryPersonPointer->FirstName;
FI >> TemporaryPersonPointer->LastName;
FI.ignore();//flushes a single newline from input
FI.getline(TemporaryPersonPointer->Address, 40);
FI.ignore();
FI.getline(TemporaryPersonPointer->PhoneNumber, 20);
FI >> TemporaryPersonPointer->Age;
TemporaryPersonPointer->Link = HeadPointer;
HeadPointer = TemporaryPersonPointer;
FI.get(EndOfListChecker);
while (EndOfListChecker == '\n')
{
FI.get(EndOfListChecker);
}
if (EndOfListChecker != 0)
FI.putback(EndOfListChecker);
}
}
void DisplayList(PersonInfo *HeadPointer)
{
do
{
cout << "\nFirst Name: ";
cout << HeadPointer->FirstName << endl;
cout << "Last Name: ";
cout << HeadPointer->LastName << endl;
cout << "Adress: ";
cout << HeadPointer->Address << endl;
cout << "Phone Number: ";
cout << HeadPointer->PhoneNumber << endl;
cout << "Age: ";
cout << HeadPointer->Age;
cout << "\n\n";
HeadPointer = HeadPointer->Link;
usleep(75000);
}
while (HeadPointer != NULL);
cout << "Press enter to go to main menu: ";
cin.ignore(2);
cout << "\n";
}
void SaveSettings(ofstream &FO, const PersonInfo *HeadPointer, const char *P)
{
FO.open(P);
if (FO.fail())
cout << "Couldn't Open File\n";
while (HeadPointer != NULL)
{
FO << HeadPointer->FirstName << endl;
FO << HeadPointer->LastName << endl;
FO << HeadPointer->Address << endl;
FO << HeadPointer->PhoneNumber << endl;
FO << HeadPointer->Age << endl << endl;
HeadPointer = HeadPointer->Link;
}
FO << (char) 0 << endl;
FO << "Date of Settings: " << Date() << endl;
FO.close();
}
void SortContacts(PersonInfo *&HeadPointer)
{
PersonInfo *MovingPointer1;//used to "crawl" down list
PersonInfo *MovingPointer2;//used to "crawl" down list
PersonInfo *StaticPointer;//always points at first node to give HeadPointer a way to link back to the list at end
PersonInfo *TemporaryPointer;//holds a node during a swap
bool ZeroSwapsOccured = false;//initialized at false to allow entrance into loop once
MovingPointer1 = StaticPointer = HeadPointer;//set all to point at first node
MovingPointer2 = HeadPointer->Link;
while (ZeroSwapsOccured == false)
{
ZeroSwapsOccured = true;
while (MovingPointer2->Link != NULL)
{
if (!NamesInOrder(MovingPointer1->LastName, MovingPointer2->LastName))
{
ZeroSwapsOccured = false;
//Temp = MP1
//MP1 = MP2
//MP2 = TEMP
MovingPointer1->Link = MovingPointer2->Link;
MovingPointer2->Link = MovingPointer1;
HeadPointer->Link = MovingPointer2;
}
}
}
HeadPointer = StaticPointer;//link HeadPointer back to list after sort
}
bool NamesInOrder(const char LastName1[], const char LastName2[])
{
for (int i = 0; LastName1[i] || LastName2[i]; ++i)//go until you get to the end of the larger name
{
if(toupper(LastName1[i]) < toupper(LastName2[i]))
return true;
if(toupper(LastName1[i]) > toupper(LastName2[i]))
return false;
}
return true;//this will only be used if same last name
//build in fucntionality to then go to first name after last name, if both last names are the same
}
string Date()//not my code here - just modified it to read easier
{
char Time[50];
time_t now = time(NULL);
strftime(Time, 50, "%b, %d, %Y", localtime(&now)); //short month name
return string(Time);
}
First - You're reordering the list in both cases.
Second -
Swapping two nodes usually takes five operations:
Change the node one back from the first node to point to the second node.
Change the node one back from the second node to point to the first node.
Store the first node's next pointer in a temporary pointer.
Change the first node's next pointer to the second node's next pointer.
Change the second node's next pointer to the temporary pointer.
Swapping two variables takes at least three operations:
Store the first variable in a temporary variable.
Change the first variable to the second variable.
Change the second variable to the first variable.
But now multiply that by the number of struct members.
The struct should have at least 2 data members - a pointer and a payload - so off the bat you're looking at, at least, 6 operations. Which will increase by 3 for each member in the struct. So you're better off just swapping the nodes.
No memory should be moving. The nodes in a linked list are not ordered in memory but only in relation to each-other via pointer(s) to the next/previous nodes in the list. your operation can be done with only a few pointer assignments.
Swapping the data is more costly and complex. For example, to swap the data, you will need to swap the name, address, numbers, ages etc.
On the other hand, swapping the node means just swapping two memory location address inside your list. So, swapping the nodes is highly preferable.
Secondly, if you add more metaData fields to your node, you won't have to change the sort code to swap the newly added data field.
So you have a linked list that you want to sort. To do it correctly and efficiently you have to use the correct sorting algorithm which in this case is the Merge Sort. For sure you should not swap the nodes' data.
Check this link: http://www.geeksforgeeks.org/merge-sort-for-linked-list/
If node data size is larger, that time it's better to swap node's position rather than swap node's data (swapping data will be bad choice).
Reasons of choosing moving the pointer implementation over swapping the data:
Let's suppose you want to add a new field to your contact list after some time. If you swap data, you will have to change your code every time you make changes to your contact list field.
As fields in contact list increase, overhead for swapping the data will grow.

C++ Reading from a file

I have been trying to do this all day but something is just not OK. I'm trying to make a system that reads students from text file and creates three new files. The three files are: Normal, Failed, New. Everything depends of the student's number. If it has 'D' in the beginning the student should go to the file with failed students. If there is 'I' in front of the number the student should go to the file named "New". If there is nothing in the beginning the student should go to the "Normal" file.
The problem is that if the students data is inserted manually to the file by the user everything is ok. But I have a function that reads student's data and inserts it in the main file. If there is nothing in front of the number everything is ok when I try to read all students from the file. But if there is a letter, the data is not being written in the proper(any) file.
Here is example: Let's have a ready file with data in it:
989123 John Brown //Should go to the "Normal" file
I112233 Steve Round //Should go to the "New" file
D101010 Wayne Bruce //Should go to the "Failed" file
And if I try to read the data and insert it into the proper files everything is ok.
But let's say that the user has choosed the "Add student" option from the applications menu. And the user inserts a new record. For example:
D818181 Some Guy //Should go to the "Failed" file
but it doesn't go there. I don't know what's the reason. If the user has entered a student number without any letter everything is OK but if there is a letter it is not shown in the file. I hope you got my mind. Here is the code. Every help will be appreciated.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
struct Student
{
int number;
string name;
string secondName;
};
Student Failed[50], New[50], Normal[50];
int o = -1;
int v = -1;
int n = -1;
int MakeInt(string number, bool ignoreFirst)
{
int num;
if(ignoreFirst)
{
number[0] = '0';
num = atoi(number.c_str());
}
else
{
num = atoi(number.c_str());
}
return num;
}
void zapis_student(string number, string name, string secondName)
{
if(number[0] == 'D')
{
int num = MakeInt(number, true);
Student temp;
temp.number = num;
temp.name= name;
temp.secondName = secondName;
o++;
Failed[o] = temp;
}
else if(number[0] == 'I')
{
int num = MakeInt(number, true);
Student temp;
temp.number = num;
temp.name = name;
temp.secondName = secondName;
v++;
New[v] = temp;
}
else
{
int num = MakeInt(number, false);
Student temp;
temp.number = num;
temp.name = name;
temp.secondName = secondName;
n++;
Normal[n] = temp;
}
}
void ReadFile()
{
ifstream fp("studenti.txt", ios::in);
if(fp.fail())
{
cout<<"Error!"<<endl;
}
while(fp.good())
{
string number, name, secondName;
fp >> number >> name >> secondName;
zapis_student(number, name, secondName);
}
fp.close();
}
void sortir(Student a[], int br)
{
for(int i = 0; i < br; i++)
{
for(int j = 0; j < br-1; j++)
{
if(a[j].number>a[j+1].number)
{
Student buf = a[j];
a[j] = a[j+1];
a[j+1] = buf;
}
}
}
}
void MakeFile(Student a[], int br, char ime_fail[])
{
ofstream fp(ime_fail);
for(int i = 0; i < br; i++)
{
fp << a[i].number << " " << a[i].name << " " << a[i].secondName << endl;
}
fp.close();
}
void AddStudent()
{
fstream fp("studenti.txt", ios::app);
string number, firstName, secondName;
cin >> number >> firstName >> secondName;
fp << number << " " << firstName << " " << secondName << endl;
fp.close();
}
void SortStudents()
{
sortir(Failed, o);
sortir(New, v);
sortir(Normal, n);
}
int main ()
{ int ans;
do
{ cout<<"******************************Menu***********************************"<<endl;
cout<<"* *"<<endl;
cout<<"* 1. Add student. *"<<endl;
cout<<"* 2. Read file. *"<<endl;
cout<<"* 3. Sort students. *"<<endl;
cout<<"* 4. Make Normal file. *"<<endl;
cout<<"* 5. Make Failed file. *"<<endl;
cout<<"* 6. Make New file. *"<<endl;
cout<<"* 7. Exit! *"<<endl;
cout<<"* *"<<endl;
cout<<"*********************************************************************"<<endl;
cout<<endl<<"Choice: "<<endl;
do
{cin>>ans;} while((ans<1)||(ans>7));
switch(ans)
{ case 1:AddStudent();break;
case 2:ReadFile();break;
case 3:SortStudents();break;
case 4:MakeFile(Normal, n, "Normal.txt");cout<<"Suzdaden e fail NovaGrupa.txt!\n";break;
case 5:MakeFile(Failed, o, "Failed.txt");cout<<"Suzdaden e fail Izklucheni.txt!\n";break;
case 6:MakeFile(New, v, "New.txt");cout<<"Suzdaden e fail Vlizashti.txt!\n";break;
case 7:exit(1);
}
}
while(ans!=7);
}
You have just one single student per type; since you start from -1, you finish the reading with 0, which is the right index for the first element but the wrong count of elements! To fix this, I simply suggest you to start with 0, use the index and then increment. E.g.
int o = 0;
...
Failed[o] = temp;
o++;
(swapped the lines), so that o keeps the count of how many student of that kind you've read so far.
Note: you also need to handle properly the end of file and cope with the case when there's nothing that can be converted to an integer by atoi: you try anyway (and you don't have a way to notice it), and the "normal" count can be one unit greater (after the fix; before the fix, it's the correct count!)
Other suggestions
Do not use atoi (for which you should include cstdlib, and you don't)… do not ignore compiler warnings
Last argument of MakeFile should be const char *
Use better names for variable: o, v, n are poorly named.