C++: cin with white spaces to strings without getline function - c++

I am in the middle of a college project which kind of looks like a students' database.
Each line of the text file follows this "model":
age ; full_name ; avg
I need to read the text file and store everything in a vector of structs and I could do that if the name was only one word.
Well, obviously, age is an int, avg is a double, but what about the full name?
I can't just use file >> full_name;, with full_name being a string because it would stop reading to it once it gets to a whitespace. The getline() function would store everything in one place so I am not sure what to do.
Please share your knowlegde with this young mind x)

As many others pointed out, you can use std::getline to read chars till a delimiter.
Consider this snippet of code as a starting point:
int age;
std::string name;
double average;
// ... Open the file which stores the data ...
// then read every line. The loop stops if some of the reading operations fails
while ( input >> age &&
std::getline(input, name, ';') && // consume the first ;
std::getline(input, name, ';') && // read the name
input >> average ) {
// do whatever you need with the data read
cout << "age: " << age << " name: " << name << " average: " << average << '\n';
}

Related

Read a binary file until the end c++

I have class player that contains some attributes.
I m filling a file with player's data but i want to assign a new id number every time the function is called in a way that the new player's id will be increased every time.
So i made this while loop to read number of players and update the player's new id but this doesn't work and nothing is written in the file.
void Player::create_player()
{
fstream file;
Player plyr; string passwordt;
int aget = 0;
long int id_nmbert = 0;
string emailt, ingame_namet, full_namet,yes;
file.open("player_database.dat", ios::binary | ios::app);
if (!file.is_open())
throw exception();
while (file >> yes) ///
id_nmbert++; ///
cout << "insert player's full name" << endl;
cin >> full_namet;
plyr.full_name = full_namet;
cout << "insert player's age" << endl;
cin >> aget;
plyr.age = aget;
cout << "insert player's email" << endl;
cin >> emailt;
plyr.email = emailt;
cout << "insert player's password" << endl;
cin >> password;
plyr.password = passwordt;
cout << "insert player's ingame name" << endl;
cin >> ingame_namet;
plyr.ingame_name = ingame_namet;
plyr.id_nmber = id_nmbert;
file.write((char*)&plyr, sizeof(Player));
file.close();
}
Tried This but it's even worse.
while (!file.eof())
id_numbert;
There are similar questions but not in c++ :).
I'd recommend storing the players in a text file that you parse instead of storing them as binary data.
This has a lot of advantages.
The biggest difficulty with your approach is that you need to design a binary format for your player object.
Something like
id+N1+'fullname'+N2+'email'+N3+'ingame-name'
4 bytes id, N1 number of characters in fullname(4 bytes),
the characters in fullname as indicated by N1
same for N2 + email and so on.
This requires fairly complicated logic for reading and writing a player.
On the other hand you could have a text file looking like
1
Yassin Mrabet
20
player#gamers.net
playerino1336
2
Captain Giraffe
55
player1#gamers.net
playerino1337
This is a lot easier to write code for.
A new player every fifth getline.
A sample readPlayer member could look like (should probably be static, not super important right now)
Plkayer Player::readPlayer(istream& in){
std::string str_id;
std::getline(in, str_id);
std::string fullname;
std::getline(in, fullname);
std::string str_age;
std::getline(in, str_age);
std::string email;
std::getline(in, email);
std::string player_name;
std::getline(in, player_name);
int age = std::stoi(str_age);
int id = std::stoi(str_id);
if(!in) // read was unsuccessful.
handle_bad_read();
return Player(id, fullname, age, email, player_name);
}
The return statement of course requires a constructor that accepts exactly those arguments, but that constructor will be useful in many other situations too.
The question isn't much specific as for what doesn't work, however, for keeping track of the ID I suggest using a static variable at the top of the function like this:
static int playerid = 0;
The static keyword means that it will only set the variable to zero once, and it will not delete the data after the end of the function. Which means you just save the 'playerid' into the file, then increase it by 1. The next time the function will be called, playerid will be larger by 1.
Edit: while (!file.eof()) doesn't work because you're using ios::app, it already starts at file.eof(), so the loop shouldn't do anything.

C++ file input with mixed delimiters and data types

I am trying to input data from a text file:
The line format is as follows...
String|String|int double
Example:
Bob|oranges|10 .89
I can get the line in as a string using
Getline(infile, line)
I don't understand how to break the line into the distinct variables from the string variable.
Thanks
for a start you could write some good old fashioned c code using strchr.
Or use string.find / find_first_of if you are using std::String
http://www.cplusplus.com/reference/string/string/find_first_of/
You marked this as C++. So perhaps you should try to use formatted extractors ...
Here is a 'ram' file (works just like a disk file)
std::stringstream ss("Bob|oranges|10 .89");
// this ^^^^^^^^^^^^^^^^^^ puts one line in file
I would use getline for the two strings, with bar terminator
do {
std::string cust;
(void)std::getline(ss, cust, '|'); // read to 1st bar
std::string fruit;
(void)std::getline(ss, fruit, '|'); // read to 2nd bar
Then read the int and float directly:
int count = 0;
float cost;
ss >> count >> cost; // the space char is ignored by formatted extraction
std::cout << "\ncust: " << cust << "\n"
<< " " << count << " " << fruit
<< " at $" << cost
<< " Totals: " << (float(count) * cost) << std::endl;
if(ss.eof()) break;
}while(0);
If you are to handle more lines, you need to find the eoln, and repeat for every record of the above style.
This approach is extremely fragile (any change in format will force a change in your code).
This is just to get your started. It has been my experience that using std::string find and rfind is much less fragile.
Good luck.

Reading multiple lines from a file using getline()

I am trying to read in and then output the contents of a text file with three lines, as follows:
Bob Dylan 10 9
John Lennon 8 7
David Bowie 6 5
For each line, I just want to output the line, i.e. firstName LastName number1 number2.
I'm using the following code for this:
int num1;
int num2;
string firstName;
string lastName;
string fullName;
ifstream inFile;
inFile.open("inputFile.txt");
while (getline(inFile, firstName))
{
inFile >> firstName >> lastName >> num1 >> num2;
fullName = firstName + " " + lastName;
cout << fullName << " " << num1 << " " << num2 << endl;
}
inFile.close();
There are 2 problems with the output from this. First, the first line is not output, although from experimentation I know that it DOES read it in. Second, after the last 2 lines are read in and output (as desired), the program displays everything in the last line EXCEPT the first name (in this case the last thing it prints is Bowie 6 5).
Can someone use this simple example to explain how the getline function works when reading in multiple lines from a file? (I don't even know if it's the best way, but it's the only way I know as of yet). Here are some specific questions.
First, does the while loop conditional getline(inFile, firstName) return a boolean? If so, how can it be true (i.e. how can the while loop start) if I haven't given firstName a value yet? Is it the case that the program reads the first line and if there's something there, then it executes the while loop, but starting with the second line, because it already used the first to check for content?
Second, if firstName does have a value, and if that value is the first name on the first line ("Bob" in this case), why isn't the first line output at all? I've been racking my brain trying to figure out where it went to.
Third, after the program reads in and displays the last two lines, the program moves to the next line and encounters nothing but blanks, right? Then what would be the value of firstName? Would it be blank, or would it still be "David"? If it's blank, why does the while loop execute again? But if it's "David", then why does the program not output that value along with the others?
Btw, I am working out of a textbook (not for homework), and it covers getline, but not for multiple lines. But then the exercises involve multiple lines, so I'm a bit lost.
You are trying to read each line twice.
while (getline(inFile, firstName)) // reads the line
{
// reads the next line and overwrites firstName!
inFile >> firstName >> lastName >> num1 >> num2;
Change it to:
while ( inFile >> firstName >> lastName >> num1 >> num2 )
{
fullName = firstName + " " + lastName;
cout << fullName << " " << num1 << " " << num2 << endl;
}
EDIT: To answer your questions:
How does getline() work?
Reads the entire line up to '\n' character or the delimiting character specified. http://www.cplusplus.com/reference/string/string/getline/?kw=getline
After reading the line, the control goes to the next line in the file.
Also, it returns a boolean value of true if the read operation was successful, else false.
The extraction operator truncates on all whitespaces by default. It also returns a boolean value indicating whether the operation was successful.

using fstream object to store information from a file into variables

I have the following block of code that i am using to read a text file of the following format:
firstname lastname id mark
firstname lastname id mark
Following is the block of code.
void DBManager::ReadFile(void){
fstream myfile; /*fstream object that will be used for file input and output operations*/
char* fn; /*pointer to the storage which will hold firstname*/
char* ln; /*pointer to the storage which will hold lastname*/
int id; /*integer var to hold the id*/
float mark; /*float var to hold the mark*/
/*read in the filename*/
g_FileName = new char[1024]; /*allocate memory on the heap to store filename*/
cout << "Please enter the filename:";
cin >> g_FileName;
/*open file*/
myfile.open(g_FileName, ios::in | ios::out);
if(myfile.is_open()){ /*check if the file opening is successful*/
cout << "File reading successful !\n";
/*read information from the file into temporary variables before passing them onto the heap*/
while (!myfile.eof()) {
fn=(char*) new char[1024];
ln=(char*) new char[1024];
myfile >> fn >> ln >> id >> mark;
cout << fn << " " << ln << " " << id << " " << mark << " " << endl;
}
myfile.close();
}
else{ /*else print error and return*/
perror("");
return;
}
}
The above block of code works ! :)
But I am surprised as to how myfile knows it is supposed to hold one line at a time and how its being smart enough about setting the four variables.
I am new to C++ , and hence this might be covered in some sort of documentation. But i would be happy to have some insight from you'll or a link to somewhere i can understand fstream objects better.
In C++, std::fstream is a type of stream which works specifically for files. When reading from a file, the interface for std::fstream is almost identical to std::cin. Input streams are programmed to read the next word or number when asked with the >> operator. They know where words and numbers are because they are separated by white space. In the default locale, spaces, tabs and newlines are considered to be white space. You can change the locale to include other characters, like commas, and have those be skipped while reading from a file. Basically, when reading with input streams, newlines and spaces are treated the same.
Some nice explanation for learning about streams is here: http://www.cprogramming.com/tutorial/c++-iostreams.html
I'm not sure what the question is. However, the code has several problems:
You should always check input after having tried to read.
Testing for eof() to determine if there is more to read doesn't work.
You have a memory leak, allocating memory in every iterator.
Reading without a constraint into a char array is unsafe, i.e., it is prone to buffer overrides (one of the major attack vectors).
You want to use a loop looking something like this:
std::string fn, ln;
while (myfile >> fn >> ln >> id >> mark) {
...
}

input from txt file to arrays

I have a text file with a line like:
James Dean 10 Automotive 27010.43
and I need to read that file and put each of the 4 above into arrays.
char nameArray[MAX][NAME_MAX];
int yearArray[MAX];
char departmentArray[MAX][DEP_MAX];
double payArray[MAX];
while(i < MAX && infile) {
infile.getline(nameArray[i], 20);
infile >> yearArray[i];
infile.getline(departmentArray[i], 15);
infile >> payArray[i];
cout << nameArray[i] << " " << yearArray[i] << " " << departmentArray[i] << " " << fixed << setprecision(2) << payArray[i] << endl;
i++;
}
The code is cut down just to give you an idea of what I am trying to do, but when I run this, I get something like:
James Dean -858993460 -92559631349317830000000000000000000000000000
000000000000000000.00
Thanks for the help.
==== Edit ==========================================
I changed from getline to get, thanks for that. I have to use get and not >> because some of the lines I am reading in are more than just "James Dean", they are up to 20 char long...ex: "William K. Woodward" is another one.
So, if I just use get, then it reads the first line in fine, but then I get the same messed up text for the second line.
Here is the code:
infile.get(nameArray[i], 20);
infile >> yearArray[i];
infile.get(departmentArray[i], 15);
infile >> payArray[i];
The getline functions takes an input stream and a string to write to. So, two getline calls read in two lines. Your input mechanism is broken. Either, use getline or the stream extraction operator (i.e. >>) but not both.
If you plan to use getline you need to parse the string (which is effectively one line of input) into tokes, and then store them in appropriately typed arrays. The second and fourth tokens are numbers, hence you will need to convert these from string to int or double.
The operator >> approach:
string name, surname;
int year;
double pay;
while (infile) {
infile >> name >> surname >> year >> department >> pay;
namearray[ i ] = name + " " + surname;
// ...
payarray[ i ] = pay;
++i;
}
The getline approach:
string line;
while (getline(infile, line)) {
parse(line, tokens);
namearray[ i ] = token[ 0 ] + " " + token[ 1 ];
// ...
payarray[ i ] = strTodouble(token[ 4 ]);
++i;
}
// parse definition
void parse(string line, vector<string>& token) {
// roll your own
}
double strToDouble(string s) {
// ...
}
I dont see where you define infile but I will assume that it is an ifile . In that case you should use it the same way u use cin to get input.
Why do you do a getline () ?
That function will stop only at an '\n' char or at an EOF char. So it means, you start reading the int after the end of the line, some random data.
Correct me if i'm wrong, but are there 20 or 19 characters in that first string (James Dean) before the number (10) ?