Why do I see a seg fault in this? - c++

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
using namespace std;
class student
{
public:
string s;
int age;
};
ostream& operator<<( ostream &output,const student &s)
{
output << s.s << " " << s.age << "\n";
return output;
}
istream& operator >>(istream& in, student& val)
{
return in >> val.s >> val.age;
}
bool valuecmp(const student & a, const student & b)
{
return a.s < b.s;
}
int main (void)
{
vector<student> a;
student b;
cin>>b.s;
cin>>b.age;
fstream myfile;
myfile.open("a1.txt",ios::app);
int i = 0;
myfile << b;
cout<<"File has been written"<<"\n";
myfile.open("a1.txt",ios::in);
for (string line; getline(myfile, line);)
{
istringstream stream(line);
student person;
stream >> person;
a.push_back(person);
cout<<a[i].s<<a[i].age<<"\n";
i++;
}
sort(a.begin(),a.end(),valuecmp);
fstream my;
my.open("a2.txt",ios::out);
student c;
for ( i = 0; i < 2; i++ )
{
cout<<a[i].s<<a[i].age<<"\n";
c = a[i];
my << c;
}
return 0;
}
A simple program to accept user input, store in an object. I have multiple inputs already in the file before running this program. So, when I made this program to accept the input from the user, write in a file, and then sort the contents of the entire file, using, the sort operation and then write the sorted output in a new file.
This accepts user input, shows the message, File has been written, but then shows a seg fault. Why is it happening?

You're getting a segfault on this line
cout<<a[i].s<<a[i].age<<"\n";
because a is empty when you try to access it. a.push_back(person) never gets called so no data is added to your vector. getline() fails the first time.
Hope this leads you in a helpful direction.

Related

C++ program to perform operations using a text file

item,price,qty,ordno,trdno
abc,54,2,123,32
xyz,34,2,345,21
item: string (char[])
price,qty (int)
ordno (long long)
trdno (int)
Make a structure for above mentioned fields
Make a vector (array, or any other container type) to hold multiple instances of this structure
1: Read file
2: read line, split values
3: initialize above mentioned structure object
4: add this object of structure to container
5: when whole file is read.. iterate over the container and print each elements values (serialno, orderno, tradeno, price, qty, item)
I tried this and it is not working-
#include<bits/stdc++.h>
using namespace std;
struct item {
string name;
double price;
int quantity;
int order_no;
int trd_no;
};
int main()
{
int n;cin>>n;
string str, T;
ifstream read("input.txt");
while(getline(read,str))
{
cout<<str<<endl;
}
stringstream X(str); // X is an object of stringstream that references the S string
cout<<endl;
while (getline(X, T, ','))
{
cout << T << endl; // print split string
}
read.close();
return 0;
}
For the code that you are showing, you misplaced just one '}' after the first while. So the code will read in the first while-loop all lines of the file and is then empty. And, then you try to split the lines. This can of course not work.
If you move the closing bracket to in front of read.close(); then your code will work. Like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
struct item {
string name;
double price;
int quantity;
int order_no;
int trd_no;
};
int main()
{
int n; cin >> n;
string str, T;
ifstream read("input.txt");
while (getline(read, str))
{
cout << str << endl;
stringstream X(str); // X is an object of stringstream that references the S string
cout << endl;
while (getline(X, T, ','))
{
cout << T << endl; // print split string
}
}
read.close();
return 0;
}
Caveat: this will not work, if the source file contains the header row! You can read this and throw it away, if needed.
If we follow the instruction of your homework, line by line, and assume that the first line contains header rows, then we would do like the following.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Item {
std::string name;
double price;
int quantity;
long long order_no;
int trd_no;
};
int main()
{
std::vector<Item> items;
std::string str, T;
std::ifstream read("input.txt");
// Read first line and ignore it
std::getline(read, str);
while (std::getline(read, str))
{
std::istringstream X(str);
Item tempItem;
getline(X, T, ',');
tempItem.name = T;
getline(X, T, ',');
tempItem.price = std::stod(T);
getline(X, T, ',');
tempItem.quantity = std::stoi(T);
getline(X, T, ',');
tempItem.order_no = std::stoll(T);
getline(X, T, ',');
tempItem.trd_no = std::stoi(T);
items.push_back(tempItem);
}
read.close();
for (const Item& item : items)
std::cout << item.name << ' ' << item.price << ' ' << item.quantity << ' '
<< item.order_no << ' ' << item.trd_no << '\n';
}
And, with a little bit more advanced C++, where we especially keep data and methods in a class, we could do the following:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <iterator>
// The item
struct Item {
std::string name{};
double price{};
int quantity{};
long long order_no{};
int trd_no{};
// Overwrite extraction operator for easier stream IO
friend std::istream& operator >> (std::istream& is, Item& i) {
char c;
return std::getline(is >> std::ws, i.name, ',') >> i.price >> c >> i.quantity >> c >> i.order_no >> c >> i.trd_no;
}
// Overwrite inserter for easier output
friend std::ostream& operator << (std::ostream& os, const Item& i) {
return os << "Name: " << i.name << "\tPrice: " << i.price << "\tQuantity: " << i.quantity << "\tOrder no: " << i.order_no << "\tTRD no: " << i.trd_no;
}
};
// The Container
struct Data {
std::vector<Item> items{};
// Overwrite extraction operator for easier stream IO
friend std::istream& operator >> (std::istream& is, Data& d) {
// Read header line and ignore it
std::string dummy; std::getline(is, dummy);
// Delete potential old data
d.items.clear();
// Read all new data from file
std::copy(std::istream_iterator<Item>(is), {}, std::back_inserter(d.items));
return is;
}
// Overwrite inserter for easier output
friend std::ostream& operator << (std::ostream& os, const Data& d) {
std::copy(d.items.begin(), d.items.end(), std::ostream_iterator<Item>(os, "\n"));
return os;
}
};
int main()
{
// Open file and check, if it could be opened
if (std::ifstream sourceFileStream("input.txt"); sourceFileStream) {
// Define container
Data data{};
// Read and parse complete source file and assign to data
sourceFileStream >> data;
// Show result
std::cout << data;
}
else std::cerr << "\n\nError: Could not open source file:\n\n";
}

How can I compare the third token from each line using 'getline()'?

Input file: In each row, there's an entry that is a pair of ID - name - GPA. Values are tab-delimited.
20210001 Bill 3.61
20210002 Joe 3.21
20210003 Royce 4.32
20210004 Lucy 2.21
I have to rearrange this file sorted by the GPA (in decreasing order).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main() {
ifstream inputfile("input.txt");
ofstream outputfile("output.txt");
if (inputfile.fail()) {
cout << "Cannot open inputfile" << endl;
}
if (outputfile.fail()) {
cout << "Cannot open outputfile" << endl;
}
if (inputfile.is_open()) {
string line;
while (getline(inputfile, line)) {
string token;
stringstream ss(line);
while (getline(ss, token, '\t')) {
}
}
}
inputfile.close();
outputfile.close();
return 0;
}
I'm not sure what to do next.
When doing I/O from/to streams (like file streams) it usually makes it easier to create a class to keep the data for each record in the file and to create overloads for operator>> (in) and operator<< (out).
Example:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// one line in the file could possibly have this representation in your program:
struct record {
std::uint32_t ID;
std::string name;
double GPA;
};
// an overload to read one line of data from an istream (like an ifstream) using getline
std::istream& operator>>(std::istream& is, record& r) {
if(std::string line; std::getline(is, line)) {
std::istringstream iss(line);
if(not (iss >> r.ID >> r.name>> r.GPA)) {
is.setstate(std::ios::failbit);
}
}
return is;
}
// an overload to write one line to an ostream (like an ofstream)
std::ostream& operator<<(std::ostream& os, const record& r) {
return os << r.ID<< '\t' << r.name << '\t' << r.GPA << '\n';
}
With that boilerplate in place, making the actual program becomes easy.
int main() {
std::ifstream inputfile("input.txt");
// read all records from the file into a vector
std::vector<record> records(
std::istream_iterator<record>(inputfile),
std::istream_iterator<record>{}
);
// sort the records according to GPA
// if you want a decending order, just make it return rhs.GPA < lhs.GPA;
std::sort(records.begin(), records.end(),
[](const record& lhs, const record& rhs) {
return lhs.GPA < rhs.GPA;
}
);
std::ofstream outputfile("output.txt");
// put the result in the output file
std::copy(records.begin(),
records.end(),
std::ostream_iterator<record>(outputfile));
}
There may be a few things in this answer that you haven't seen before. I'll list resources for those I anticipate may require some reading:
operator<< / operator>> overloading. See Stream extraction and insertion
std::istringstream - You put a std::string in it - and then it behaves like any other std::istream (like a std::ifstream).
std::istream_iterator/std::ostream_iterator
std::sort / std::copy are two of the many algorithms in the standard library.
std::vector - A class template acting as a dynamic array where you can add and remove data, like record in this answer.
Lambda expressions - In this answer it's the functor [](const record& lhs, const record& rhs) { ... } used to sort the records.
If you know exactly how many tokens are in a line:
You could simply getline() 3 times with the tab delimiter, and store the values separately.
string id;
string name;
string gpa;
getline(ss, id, '\t');
getline(ss, name, '\t');
getline(ss, gpa, '\t');
This logic would live within your loop that iterates over the lines in the file.
You could use a struct to contain all your fields:
struct user
{
int id; string name; double point;
};
Then insert all of them into a std::vector and finally use sort() with the comp parameter to sort by points.
Code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
using namespace std;
struct user
{
int id; string name; double point;
};
vector<user> users;
void stripInfoFromString(string inp)
{
stringstream cur(inp);
user curUser;
cur >> curUser.id >> curUser.name >> curUser.point;
users.push_back(curUser);
}
bool compareUser(user x, user y)
{
return x.point < y.point;
}
int main()
{
string a1 = "20210001 Bill 3.61";
string a2 = "20210002 Joe 3.21";
string a3 = "20210003 Royce 4.32";
string a4 = "20210004 Lucy 2.21";
stripInfoFromString(a1);
stripInfoFromString(a2);
stripInfoFromString(a3);
stripInfoFromString(a4);
sort(users.begin(), users.end(), compareUser);
cout << fixed << setprecision(2);
for (user cur : users)
{
cout << cur.id << " " << cur.name << " " << cur.point << "\n";
}
}
Output:
20210004 Lucy 2.21
20210002 Joe 3.21
20210001 Bill 3.61
20210003 Royce 4.32
I used standard input/output to minimize the code, you can simply switch for file inputs easily.
More info:
struct : https://en.cppreference.com/w/c/language/struct
sort() : https://en.cppreference.com/w/cpp/algorithm/sort
Also, see here why is using namespace std; considered bad practice.
I would suggest defining a struct to hold the 3 tokens, and then create a std::vector holding instances of that struct for each line. You can then sort that vector on the 3rd token. You already have <vector> in your header includes.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct entry
{
int id;
string name;
double gpa;
};
int main() {
ifstream inputfile("input.txt");
ofstream outputfile("output.txt");
vector<entry> entries;
if (inputfile.fail()) {
cout << "Cannot open inputfile" << endl;
}
if (outputfile.fail()) {
cout << "Cannot open outputfile" << endl;
}
string line;
while (getline(inputfile, line)) {
istringstream iss(line);
entry e;
string token;
getline(iss, token, '\t');
e.id = stoi(token);
getline(iss, e.name, '\t');
getline(iss, token, '\t');
e.gpa = stod(token);
/* alternatively:
iss >> e.id >> e.name >> e.gpa;
*/
entries.push_back(e);
}
inputfile.close();
outputfile.close();
sort(entries.begin(), entries.end(),
[](const entry &e1, const entry &e2){
return e1.gpa > e2.gpa;
}
);
for (const entry &e : entries) {
outputfile << e.id << '\t' << e.name << '\t' << e.gpa << '\n';
}
return 0;
}
Demo

Is there a way to combine two variables?

I have been trying to get my code to dynamically allocate class objects to file to later read but having trouble with getting user input to save into each different object.
I'm trying to have the user input their names, ages and phone numbers and have it save to file where it can be read later hopefully using the same method to run through the file.
I tried using arrays but that can't save all three fields of the object. Is there a dynamic variable that can be used?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
string mName, mID, mPhoneNumber;
int id = 0;
class Student
{
public:
string mName;
string mId;
string mPhoneNumber;
Student(string id = "", string name = "", string phone = "") : mId(id), mName(name), mPhoneNumber(phone)
{}
bool operator==(const Student& obj)
{
return (mId == obj.mId) && (mName == obj.mName) && (mPhoneNumber == obj.mPhoneNumber);
}
/*
* Write the member variables to stream objects
*/
friend ostream& operator << (ostream& out, const Student& obj)
{
out << obj.mId << "\n" << obj.mName << "\n" << obj.mPhoneNumber << endl;
return out;
}
/*
* Read data from stream object and fill it in member variables
*/
friend istream& operator >> (istream& in, Student& obj)
{
in >> obj.mId;
in >> obj.mName;
in >> obj.mPhoneNumber;
return in;
}
};
int main()
{
cin >> id;
Student stud1("1", "Jack", "4445554455");
Student stud2("4", "Riti", "4445511111");
Student stud3("6", "Aadi", "4040404011");
// open the File
ofstream out("students.txt");
// Write objects to file (targets to cout)
out << stud1;
out << stud2;
out << stud3;
out.close();
// Open the File
ifstream in("students.txt");
Student student1;
Student student2;
Student student3;
// Read objects from file and fill in data
in >> student1;
in >> student2;
in >> student3;
in.close();
// Compare the Objects
assert(stud1 == student1);
assert(stud2 == student2);
assert(stud3 == student3);
cout << stud1 << endl;
cout << stud2 << endl;
cout << stud3 << endl;
return 0;
}
You can make use of std::vector in the following manner:
std::vector<Student> my_students;
for (std::size_t i = 0; i < 3; i++) {
Student tmp;
in >> tmp;
my_students.push_back(tmp);
}
std::vector<Student> aVectOfStudents;
aVectOfStudents.emplace_back("","Jack", "4445554455");
aVectOfStudents.emplace_back("","Riti", "4445511111");
aVectOfStudents.emplace_back("","Aadi", "4040404011");
ofstream out("students.txt");
for(auto studIter = aVectOfStudents.begin(); studIter != aVectOfStudents.end(); ++studIter)
{
std::cout << "Insert Id for student: " << studIter->mName << "\n";
std::cin >> studIter->mId;
out<<*studIter;
}
out.close();
You could use the std::vector, to store the Student s and iterate through them to file out/inputs.
#include <vector>
int main()
{
// open the File
std::fstream file{ "students.txt" };
// vector of students
std::vector<Student> students{
{"1", "Jack", "4445554455"},
{ "4", "Riti", "4445511111"},
{"6", "Aadi", "4040404011"}
};
// iterate throut the objects and write objects(i.e. students) to the file
for(const auto& student: students)
file << student;
// reset the stream to the file begin
file.clear();
file.seekg(0, ios::beg);
// clear the vector and resize to the number of objects in the file
students.clear();
students.resize(3);
// read objects from file and fill in vector
for (Student& student : students)
file >> student;
file.close();
return 0;
}

ifstream-istream and function call

I am new to c++ and while i was working with streams i saw the following code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
class Results
{
public:
string const& operator[](int index) const
{
return m_data[index];
}
int size() const
{
return m_data.size();
}
void readnext(istream& str)
{
string line;
getline(str, line);
cout << "line :" << line <<endl;
stringstream lineStream(line);
string cell;
m_data.clear();
while(getline(lineStream, cell, ','))
{
m_data.push_back(cell);
cout << cell<<endl;
}
}
private:
vector<string> m_data;
};
istream& operator>>(istream& str, Results & data)
{
data.readnext(str);
return str;
}
int main()
{
ifstream file("filename.txt");
Results r1;
while(file >> r1)
{
cout << "1st element: " << r1[3] << "\n";
}
}
When the call data.readnext(str) is made:
1)what is the value of str which is passed as an argument? When I print it out and i get 0x7ffd30f01b10 which is an address.
2)in the function getline(str, line); gives line the value of the first row of the file. I don't get why. Shouldn't that be getline(file, line);
I generally don't understand how this works so any help would be highly appreciated
The value is a reference to the std::istream superclass of the instantiated std::ifstream file object.
No. There is no file object visible in the scope of the readnext() function. The code is correct. str is the std::istream & parameter to readnext(), and matches the type of the first parameter to std::getline().

C++ Trying to Overload ifstream to read file into a Class's array

I am trying to overload the ifstream operator >> in order to read from a text file and place the data in a class belonging to State.
The format of the file I am reading from is Name of State > State Capital > Population. I just want to read the name of the state into the array.
I have been having trouble with operator overloading. I somewhat understand it and was able to make the ostream work, but reading in has proven to be more difficult.
Not sure if it makes a difference, but this is for a school assignment and I am still working on it. Just not sure where to go from here.
main.cpp
This is my main CPP file.
#include <iostream>
#include <string>
#include <fstream>
#include "State.h"
using namespace std;
int main(){
State s, h;
string null;
ifstream fin("states.txt");
while(fin.good())
{
fin >> h; //This doesn't read anything in.
fin >> null; //Dumping the Capital City to a null string
fin >> null; //Dumping the Population to a null string
}
cout << s; //Testing my overloaded << operator
system("pause");
return 0;
}
State.cpp
This is a secondary CPP file.
#include "State.h"
#include <fstream>
#include <string>
#include <iostream>
using namespace std;
int i = 0;
string name, x, y;
State::State()
{
arrayStates[50];
}
//Trying to overload the input from fstream
ifstream& operator >> (ifstream& in, State h)
{
for(i = 0; i < 21; i++)
{
in >> h.arrayStates[i];
}
return in;
}
ostream& operator << (ostream& out, State s)
{
for(int i = 0; i < 21; i++)
{
out << s.arrayStates[i] << endl;
}
return out;
}
State.h
This is my header file that contains my class.
#include <iostream>
#include <string>
using namespace std;
class State{
private:
string arrayStates[50];
public:
State();
friend ostream& operator << (ostream& out, State s);
friend ifstream& operator >> (ifstream& in, State h);
};
The error is in this function, as you suggest.
ifstream& operator >> (ifstream& in, State h)
{
for(i = 0; i < 21; i++)
{
in >> h.arrayStates[i];
}
return in;
}
That function makes a temporary copy of your State, calls the copy h, and initializes that copy.
Pass the original State by reference instead. So it refers to the same object.
ifstream& operator >> (ifstream& in, const State &h)