I'm quite new to C++. I'm writing a program that reads data from a file and puts it into an object. I'm doing this to try to understand the iostream better.
Each line of the file contains an alphanumeric ID in the format nxn, where n is some integer, and x is some character, a color, another integer, and then a location. Here's an example
17832X9647 "blue" 100 "New York City"
Unfortunately, the code that I've written doesn't get all of the final string, since it has spaces in it. So, I tried writing a function that would return all of the text inside double quotes (not including the double quotes) and putting it inside the input stream, while still preserving the whitespaces and discarding the double quotes. Unfortunately, that also did not work, so now I'm sitting here scratching my head, not knowing what to do, and it's because I fundamentally don't understand how the iostream works. What can I do to fix this? I would really, really not like to restructure my whole program, because I want to learn exactly how I'm treating the iostream wrong. Getting this thing to work in the most efficient way isn't important to me, just that I understand more about the iostream.
Here is my code.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
string ReadDoubleString(istream & in)
{
string output_string;
char ch = '\"';
in.ignore(ch); //i'm thinking that this will make the extraction skip any double quotes
in >> output_string;
return output_string;
}
//begin class declaration and implementation for Widget
class Widget
{
friend istream& operator>>(istream&, Widget&);
public:
string ID;
string color;
int Age;
string location;
void setAttributes(string, string, int, string);
};
void Widget::setAttributes(string ID, string color, int Age, string location)
{
this->ID = ID;
this->color = color;
this->Age = Age;
this->location = location;
}
istream& operator>>(istream& in, Widget& output_widget)
{
int input_ID_pt1;
char input_ID_pt2;
int input_ID_pt3;
string full_ID;
string input_color;
int input_Age;
string input_location;
in >> input_ID_pt1 >> input_ID_pt2 >> input_ID_pt3;
input_color = ReadDoubleString(in);
in >> input_Age;
input_location = ReadDoubleString(in);
full_ID = to_string(input_ID_pt1) + input_ID_pt2 + to_string(input_ID_pt3);
output_widget.setAttributes(full_ID, input_color, input_Age, input_location);
return in;
}
//end class declaration and implementation for Widget
int main()
{
string file_name;
cout << "enter file name" << endl;
cin >> file_name;
ifstream newFile(file_name);
if (newFile.is_open())
{
Widget w1;
newFile >> w1;
cout << w1.ID << endl;
cout << w1.color << endl;
cout << w1.Age << endl;
cout << w1.location << endl;
}
else
{
cout << "could not open file!" << endl;
}
return 0;
}
My program ends up returning this when I use the data from earlier.
17832X9647
//empty line
0
//empty line
//empty line
Thank you so much for reading.
Related
I am trying to learn C++. I created a program that inputs a name and then says "Hello, <name>!". But when I enter "Aditya Singh" as the name, it outputs "Hello, Aditya!", which is not what I expected.
My code:
#include <iostream>
#include <string>
using namespace std;
// I created the class because I was learning C++ Classes
class MyClass {
public:
void setName(string inp) {
name = inp;
}
string getName() {
return name;
}
private:
string name;
};
int main() {
// Input Name
string inpName;
cout << "Please enter your name\n";
cin >> inpName;
// Say hello
MyClass name;
name.setName(inpName);
cout << "Hello, " << name.getName() << "!" << endl;
}
Does this happen because of a white space in the string? How can I output a string with a white space then?
This is because cin >> inpName reads a word at a time, so yes, it is because of the whitespace within the input. It seems what you need is a mechanism to read until the newline character \n. This functionality is already there, just replace cin >> inpName by
std::getline(cin, inpName); // Store everything until \n in inpName
I am new to programming and I am having trouble reading data from a file and entering it into a struct array, while keeping track of each data being entered:
The file would contain:
Name, ID Number, and GPA
Courtney Love 1234569 3.5
Bob Joe 1234570 3.0
Dave Henry 1234571 2.9
struct Student
{
string name;
int id;
float GPA;
void printStudent();
};
Declare an array of Student type that can hold up to 5 members:
Student a_members[5];
Open the file, read in each line and store the data in the array, keep track of each student read in:
fstream file_;
file_.open ("students.txt");
if(file_.is_open())
{
while(file_.good())
{
}
}
else
{
cout << "File is not open"<< endl;
}
return 0;
I am stuck on the "while" conditional statement. After that I don't know what I should do to input the data from the file line by line and place into the "struct array". As of right now, I feel like I have tried everything! I deleted everything and figured it was best to start over. It was becoming too complicated! Maybe I am just not understanding the concept. If anyone can point me in the right direction, please do so! Thank you!
You should not use good(), just like you should not use eof().
(Neither is used in any decent beginner-level material, yet every beginner manages to find them. And then they wonder why it didn't work.)
You should instead rely on the fact that a stream itself is "true-ish" if it's in a good state, and just keep reading until it isn't.
Idiomatic C++ would look like this:
std::ifstream file("students.txt");
Student s;
while (file >> s.name >> s.id >> s.GPA)
{
// Process the student
}
or, a fancy version:
std::istream& operator>> (std::istream& is, Student& s)
{
return is >> s.name >> s.id >> s.GPA;
}
std::ifstream file("students.txt");
Student s;
while (file >> s)
{
// Process the student
}
(In your code, you'll need to also keep track of how many Students you've read.)
Here is one from possible solutions:
#include <iostream>
#include <vector>
#include <fstream>
struct Student
{
Student() : first_name(), surname(){}
char first_name[64];
char surname[64];
int id;
float GPA;
void printStudent()
{
std::cout << "Name: " << first_name << " " << surname << " ID: " << id << " GPA: " << this->GPA << std::endl;
}
};
std::vector<Student>student;
bool LoadFile(const char* filename)
{
if (filename == NULL)return false;
std::fstream stream(filename, std::ios::in);
if (!stream.is_open())return false;
else
{
char buffer[255]; // for solution 1!
while (!stream.eof())
{
memset(buffer, 0, sizeof(buffer));
Student _student;
#pragma region SOLUTION_1
//stream.getline(buffer, sizeof(buffer));
//sscanf(buffer, "%s %s %d %f", _student.first_name, _student.surname, &_student.id, &_student.GPA);
#pragma endregion
#pragma region SOLUTION_2
stream >> _student.first_name >> _student.surname >> _student.id >>_student.GPA;
#pragma endregion
student.push_back(_student);
student[student.size() - 1].printStudent();
}
}
return true;
}
int main()
{
LoadFile("students.txt");
getchar();
return 0;
}
This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
Closed 1 year ago.
I have started working on a program, and for the life of me I can't find a bug which continuously searches the eof and doesn't end. It is most certainly a problem with my fileread and widthcount functions, and they most likely have the same error. Is there a fix for this? It just keeps looping.
The file input is this
12.43 62.38 Los Angeles
21 59 Columbus, Ohio
0 15.58 Green Bay, Wisconsin
This continues for another 10 lines.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;
void fileread(ifstream &ifFile, char newline, double &temp1, double &temp2, string city);
void widthcount(ifstream &ifFile, int &maxCount, char newline);
int main() {
double temp1, temp2, minTemp, maxTemp;
int maxCount;
char newline=' ';
string FileRead, city;
ifstream ifFile;
cout << "Please enter the location of the input file: ";
cin >> FileRead;
ifFile.open(FileRead.c_str());
if (ifFile.fail()) {
perror(FileRead.c_str());
exit(1);
}
widthcount(ifFile, maxCount, newline);
while(!ifFile.eof()) {
widthcount(ifFile, maxCount, newline);
}
ifFile.close();
ifFile.open(FileRead.c_str());
fileread(ifFile, newline, temp1, temp2, city);
while(!ifFile.eof()) {
fileread(ifFile, newline, temp1, temp2, city);
cout << left << setw(20) << city
<< right << setw(6) << fixed << setprecision(2) << temp1
<< right << setw(6) << fixed << setprecision(2) << temp2 << endl;
}
}
void fileread(ifstream &ifFile, char newline, double &temp1, double &temp2, string city) {
int charcount = 0;
ifFile >> temp1 >> temp2;
while (newline == ' ')
ifFile.get(newline);
while (newline != '\n' || !ifFile.eof()) {
charcount++;
ifFile.get(newline);
}
}
void widthcount (ifstream &ifFile, int &maxCount, char newline) {
double temp1, temp2;
int charcount = 0;
ifFile >> temp1 >> temp2;
ifFile.get(newline);
while (newline != '\n' && !ifFile.eof()) {
charcount++;
ifFile.get(newline);
cout << newline;
}
if (charcount > maxCount)
maxCount = charcount;
}
You need to check for failure (test .fail()), not end of file.
Typically .fail() is checked by using the stream object directly as condition.
E.g. while( f ) is equivalent to while( !f.fail() ).
Checking specifically for eof() is almost always a mistake -- for example, if you encounter some other error before reaching the end of the file, eof will remain false, but reading will fail (but since eof remains false, your loop will continue attempting to read and failing, forever).
Personally, I'd structure the code quite a bit differently. I'd start by creating a struct to represent one "record" from the file:
struct city {
double temp1, temp2; // horrible names, but I don't know what they represent.
std::string name;
};
Then I'd overload operator>> to extract the data for one city from a stream, and operator<< to display the data for a city:
std::istream &operator>>(std::istream &is, city &c) {
is >> c.temp1 >> c.temp2;
std::getline(is, c.name);
return is;
}
std::ostream &operator<<(std::ostream &os, city const &c) {
return cout << left << setw(20) << c.name
<< right << setw(6) << fixed << setprecision(2) << c.temp1
<< right << setw(6) << fixed << setprecision(2) << c.temp2;
}
Then I'd use those to read and write the data as god intended (with an algorithm):
int main(int argc, char **argv) {
// For the moment, cheat and take the file name from the command line
std::ifstream ifFile(argv[1]);
std::copy(std::istream_iterator<city>(ifFile),
std::istream_iterator<city>(),
std::ostream_iterator<city>(std::cout, "\n"));
return 0;
}
As an aside, I'd note that although you call widthcount, you never seem to use any result from it. At least for now, I've skipped over doing anything similar, since it didn't affect the result.
You should try something like
double t1,t2;
string s1,s2;
ifstream ifs;
ifs.open(Filename.c_str());
ifs>>t1>>t2>>s1>>s2;
while(ifs)
{
.......
do the calculations
.......
ifs>>t1>>t2>>s1>>s2;
}
This works for all the cases.If ,after the first read,ifs enters the fail state then rest of the file reading will be skipped and lines after the while loop will be executed.Other wise, rest of the lines will be read in the loop.You can change your requirement based on whether you want to read a string,a character or a line.
Saving the vector to a file works fine. But I'm looking for a simple way to load the saved data back into the vector.
This is a follow up question to two I asked previously.
1) C++ Trouble Inputting Data into Private Vector (invalid use)
2) Outputting Vector of Type Class
What's a simple way to iterate through the file and push_back() each element?
This is the class:
class Account
{
private:
string firstName;
string lastName;
string accountPass;
int accountID;
float accountBalance;
public:
static Account createAccount( int, float, string, string, string ); //creates new account
int getAccountID() const { return accountID; }
string getPass() const { return accountPass; }
string getFirstName() const { return firstName; }
string getLastName() const { return lastName; }
float getBalance() const { return accountBalance; }
friend std::ostream& operator << (std::ostream&, const Account&);
friend class BankingSystem;
}; //end of class Account
Account Account::createAccount( int ID, float balance, string pass, string first, string last )
{
Account a;
a.accountID = ID;
a.accountPass = pass;
a.firstName = first;
a.lastName = last;
a.accountBalance = balance;
return a;
}
std::ostream & operator << (std::ostream & os, const Account & acc)
{
os << setw(6) << acc.getAccountID();
os << setw(4) << acc.getPass();
os << setw(9) << acc.getFirstName();
os << setw(9) << acc.getLastName();
os << setw(9) << setprecision(2) << fixed << acc.getBalance();
return os;
}
If Accounts are the only thing written in your file you can read them all into your vector (or any push_back-able container) with this 1-liner:
std::copy(std::istream_iterator<Account>(file), std::istream_iterator<Account>(), std::back_inserter(vec));
You'll also need an operator>> analogous to the operator<< you already have.
Found the answer in this Question Using vector of user defined class type objects
for me it was solved by using:
while(!inBankSysFile.eof())
{
Account a;
inBankSysFile >> a.accountID;
inBankSysFile >> a.accountPass;
inBankSysFile >> a.firstName;
inBankSysFile >> a.lastName;
inBankSysFile >> a.accountBalance;
accounts_.push_back(a);
}
If you don't have any dynamic memory, you can read and write it to binary pretty easily using ifstream::read and ofstream::write and vector::data. Here's an example:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
class Time
{
public:
Time(): hh(0),mm(0),ss(0) {}
Time(int h,int m,int s):hh(h),mm(m),ss(s) {}
int hh,mm,ss;
};
int main()
{
Time time1(11,22,33);
Time time2(44,55,66);
vector<Time> timeList;
timeList.push_back(time1);
timeList.push_back(time2);
vector<Time> timeList2;
timeList2.resize(2,Time());
ofstream fout;
fout.open("test.txt");
if(fout.is_open())
{
// vector.data returns a pointer to the beginning of its stored data
// 1st param: the location to read data from
// 2nd param: the amount of bytes to write to the file
fout.write((const char*)timeList.data(),sizeof(Time)*timeList.size());
fout.close();
}
ifstream fin;
fin.open("test.txt");
if(fin.is_open())
{
// 1st param: the location to write data to
// 2nd param: the amount of bytes to read from the file
// NOTE: make sure you've sized the vector appropriately before writing to it.
fin.read((char*)timeList2.data(),sizeof(Time)*timeList2.size());
for(int i=0;i<timeList2.size();++i) {
cout << timeList2[i].hh << ":" << timeList2[i].mm << ":" << timeList2[i].ss << "\n";
}
fin.close();
}
return 0;
}
NOTE: Reading/writing objects that use dynamic memory (including objects containing classes that contain dynamic memory, such as std::string), will require additional processing logic to handle reading and writing that data.
NOTE: Beware of variances in structural alignment padding when using the sizes of any objects.
I have a txt file that contains name, id number, mobilenumber, and location in comma separated line.
example
Robby, 7890,7788992356, 123 westminister
tom, 8820, 77882345, 124 kingston road
My task is to retrieve
Look up all of an employee's information by name.
Look up all of an employee's information by ID.
Add the information of an employee.
Update the information of an employee.
SO far I have read the file and stored the information in a vector. Code is shown below.
For tasks
1)Look up all of an employee's information by name. I will iterate in the vector and prints information containing the name . I will be able to do that
2) simialry in text file I will look for id and prints information about that.
BUT I am clueless about point 3 & 4.
I am posting my code below
void filter_text( vector<string> *words, string name)
{
vector<string>::iterator startIt = words->begin();
vector<string>::iterator endIt = words->end();
if( !name.size() )
std::cout << " no word to found for empty string ";
while( startIt != endIt)
{
string::size_type pos = 0;
while( (pos = (*startIt).find_first_of(name, pos) ) != string::npos)
std:cout <<" the name is " << *startIt<< end;
startIt++;
}
}
int main()
{
// to read a text file
std::string file_name;
std::cout << " please enter the file name to parse" ;
std::cin >> file_name;
//open text file for input
ifstream infile(file_name.c_str(), ios::in) ;
if(! infile)
{
std::cerr <<" failed to open file\n";
exit(-1);
}
vector<string> *lines_of_text = new vector<string>;
string textline;
while(getline(infile, textline, '\n'))
{
std::cout <<" line text:" << textline <<std::endl;
lines_of_text->push_back(textline);
}
filter_text( lines_of_text, "tony");
return 0;
}
#include <string>
#include <iostream>
#include <vector>
#include <stdexcept>
#include <fstream>
struct bird {
std::string name;
int weight;
int height;
};
bird& find_bird_by_name(std::vector<bird>& birds, const std::string& name) {
for(unsigned int i=0; i<birds.size(); ++i) {
if (birds[i].name == name)
return birds[i];
}
throw std::runtime_error("BIRD NOT FOUND");
}
bird& find_bird_by_weight(std::vector<bird>& birds, int weight) {
for(unsigned int i=0; i<birds.size(); ++i) {
if (birds[i].weight< weight)
return birds[i];
}
throw std::runtime_error("BIRD NOT FOUND");
}
int main() {
std::ifstream infile("birds.txt");
char comma;
bird newbird;
std::vector<bird> birds;
//load in all the birds
while (infile >> newbird.name >> comma >> newbird.weight >> comma >> newbird.height)
birds.push_back(newbird);
//find bird by name
bird& namebird = find_bird_by_name(birds, "Crow");
std::cout << "found " << namebird.name << '\n';
//find bird by weight
bird& weightbird = find_bird_by_weight(birds, 10);
std::cout << "found " << weightbird.name << '\n';
//add a bird
std::cout << "Bird name: ";
std::cin >> newbird.name;
std::cout << "Bird weight: ";
std::cin >> newbird.weight;
std::cout << "Bird height: ";
std::cin >> newbird.height;
birds.push_back(newbird);
//update a bird
bird& editbird = find_bird_by_name(birds, "Raven");
editbird.weight = 1000000;
return 0;
}
Obviously not employees, because that would make your homework too easy.
So, first off, I don't think you should store the information in a vector of strings. This kind of task totally calls for the use of a
struct employee {
int id;
std::string name;
std::string address;
//... more info
};
And storing instances of employees in an
std::vector<employee>
You see, using your strategy of storing the lines, searching for "westminster" would net me Robbie, as his line of text does include this substring, but his name isn't westminster at all. Storing the data in a vector of employee structs would eliminate this problem, and it'd make the whole thing a lot more, well, structured.
Of course you'd need to actually parse the file to get the info into the vector. I'd suggest using a strategy like:
while(getline(infile, textline, '\n')) {
std::stringstream l(textline);
getline(l,oneEmp.name, ','); //extract his name using getline
l >> oneEmp.id; //extract his id
//extract other fields from the stringstream as neccessary
employees.push_back(oneEmp);
}
As for adding information: when the user enters the data, just store it in your employees vector; and when you should need to update the file, you may simply overwrite the original data file with a new one by opening it for writing & dumping the data there (this is obviously a rather wasteful strategy, but it's fine for a school assignment (I suppose it's school assignment)).
Start by splitting the CSV line into separate fields and then populate a struct with this data
eg:
struct Employee
{
std::string name;
std::string id_number;
std::string mobilenumber;
std::string location;
};
std::vector<Employee> employees; // Note you dont need a pointer
Look at string methods find_first_of, substr and friends.