Program terminates before to start the second input stream - c++

After inserting names, and then terminating the input stream pressing CTRL+D (Unix) or CTRL+Z (Win), the program would to prompt another time, to insert ages, but it isn't so. Please, can you tell me why? Thanks.
here, I use the reference for a printing function not present in this code.
compile online https://onlinegdb.com/BkFNcWSgv - there is the same code below: ↓
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const vector<string>& read_names(vector<string> &n) {
for(string temp; cin >> temp;)
n.push_back(temp);
return n;
};
const vector<double>& read_ages(vector<double> &a) {
for(double temp; cin >> temp;)
a.push_back(temp);
return a;
};
int main()
{
vector<string> name;
vector<string>& nn = name;
vector<double> age;
vector<double>& aa = age;
nn = read_names(name);
aa = read_ages(age);
return 0;
}

The behavior of Ctrl+D depends on your terminal. I tried it in VSCode and there it seems to close the input stream. I wasn't able to reopen it.
In my Linux terminal (Tilix) Ctrl-D sends EOF. After std::cin.clear() the goodbit is set and I can read user input again. https://en.cppreference.com/w/cpp/io/ios_base/iostate
It behaves different in VSCode and Tilix.
The following code works for me. I don't know the behavior in Windows, Mac or other OS.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
const std::vector<std::string>& read_names(std::vector<std::string>& n) {
for (std::string temp; std::cin >> temp;) n.push_back(temp);
return n;
}
const std::vector<double>& read_ages(std::vector<double>& a) {
for (double temp; std::cin >> temp;) a.push_back(temp);
return a;
}
int main() {
std::vector<std::string> name;
std::vector<std::string>& nn = name;
std::vector<double> age;
std::vector<double>& aa = age;
//std::cout << std::cin.rdstate() << '\n';
nn = read_names(name);
//std::cout << std::cin.rdstate() << '\n';
std::cin.clear();
//std::cout << std::cin.rdstate() << '\n';
aa = read_ages(age);
std::cout << nn.size() << '\n';
std::cout << aa.size() << '\n';
//std::cout << std::cin.rdstate() << '\n';
return 0;
}

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";
}

Vectors in C++ Files

Within this function, I am passing multiple files. It was implemented with arrays before, and now I need to convert all of the arrays to vectors. The issue I have is when I read in from the files, it does not stop. Why??
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice, vector<double> &quantity)
{
int x = 0;
string str;
string nTemp;
double pTemp;
int qTemp;
while(!iFile.eof())
{
getline(iFile, nTemp);
iFile.ignore();
itemName.push_back(nTemp);
iFile >> pTemp;
itemPrice.push_back(pTemp);
iFile >> qTemp;
quantity.push_back(qTemp);
cout << itemName.size() << " " << itemPrice.size() << " " << quantity.size() << endl;
}
readIn(appIn, appName, appPrice, appquantity);
readIn(drinkIn, drinkName, drinkPrice, driquantity);
readIn(entreeIn, entreeName, entreePrice, entquantity);
readIn(dessertIn, desName, desPrice, dessquantity);
This is the function and calls. Not sure why when outputting the item name, item price and quantity sizes, it just continually reads in values.
Expanding your code to an executable example:
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice,
vector<double> &quantity)
{
int x = 0;
string str;
string nTemp;
double pTemp;
int qTemp;
while(!iFile.eof())
{
getline(iFile, nTemp);
iFile.ignore();
itemName.push_back(nTemp);
iFile >> pTemp;
itemPrice.push_back(pTemp);
iFile >> qTemp;
quantity.push_back(qTemp);
cout << itemName.size() << " " << itemPrice.size() << " " << quantity.size()
<< endl;
}
}
int main () {
vector<string> nam;
vector<double> price,quantity;
ifstream in;
in.open("data_adamp.txt");
readIn(in,nam,price,quantity);
}
Given ...
$ cat data_adamp.txt
animal a 1 2
beach b 3 4
cart c 4 5
dog d 6 7
... compiling with (GCC version 6.4.0):
$ gcc adamp.cpp -lstdc++ -oadamp
... lets me run:
$ ./adamp
... which does indeed never stop.
One way to solve this problem is to tokenize each line and convert the two rightmost fields to doubles and the rest to the record name, e.g. (using the approach in the highest-ranked answer to How do I iterate over the words of a string?):
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
using namespace std;
// See the highest-scoring answer to https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string/236803#236803
template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
void readIn(ifstream &iFile, vector<string> &itemName, vector<double> &itemPrice,
vector<double> &quantity)
{
string nTemp;
double pTemp;
int qTemp;
string line;
while(getline(iFile,line))
{
char delim = ' ';
vector<string> s = split(line,delim);
istringstream ss;
ss.str(s.back());
ss >> qTemp;
s.pop_back();
ss.str(s.back());
ss.clear();
ss >> pTemp;
s.pop_back();
nTemp = "";
for (int i = 0; i < s.size(); i++)
{
if (i > 0) nTemp.append(" ");
nTemp.append(s[i]);
}
itemName.push_back(nTemp);
itemPrice.push_back(pTemp);
quantity.push_back(qTemp);
cout << nTemp << "++" << pTemp << "++" << qTemp << endl;
}
}
int main () {
vector<string> nam;
vector<double> price,quantity;
ifstream in;
in.open("data_adamp.txt");
readIn(in,nam,price,quantity);
}

How to erase non-alphabet characters from a string without going out of range

I am trying to this function to return without numbers, spaces, or other characters and I am supposed to use the .erase function. I understand that my loop keeps going out of range, but I have no clue how to fix it and I've been stuck on this for a while. If the user types "dogs are a lot of fun" and I need the function to return and output "dogsarealotoffun" Thanks for the help.
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
//function to output string without spaces, numbers, or punctuations
string alphabetOnly (string input){
int size;
int i= 0;
size = (int)input.size();
while (input[i] < size){
if (isalpha(input[i])){
i++;
}
else
input.erase(input[i]);
}
return input;
}
int main() {
string input;
cout << "Enter a string to test: ";
getline(cin, input);
cout << "alphabetOnly: " << alphabetOnly(input) << endl;
}
EDITED: I was too hasty in my previous answer (as I am learning I need to speak from tested code rather than off the top of my head) and needed to debug. The problem is in the else case you need to erase the char, NOT increment i because the length of the string just changed, and also since the length of the string changed you need to reset size to be the new length. Sorry for the hasty answer earlier, I was speaking without actually using the compiled code.
#include <iostream>
#include <cctype>
#include <string>
//function to output string without spaces, numbers, or punctuations
std::string alphabetOnly (std::string input){
int size;
int i= 0;
size = (int)input.size();
while (i < size){
if (isalpha(input[i])){
i++;
}
else{
input.erase(i,1);
//do not increment i here since the index changed becauase of erase
size = (int)input.size();
}
}
return input;
}
int main() {
std::string input;
std::cout << "Enter a string to test: ";
std::getline(std::cin, input);
std::cout << input;
std::cout << "alphabetOnly: " << alphabetOnly(input) << std::endl;
return 0;
}
something like this:
#include <iostream>
#include <string>
#include <algorithm>
//function to output string without spaces, numbers, or punctuations
std::string alphabetOnly (std::string input)
{
auto not_alpha = [](char c) { return !std::isalpha(c); };
input.erase(std::remove_if(begin(input),
end(input),
not_alpha),
std::end(input));
return input;
}
int main() {
std::string input;
std::cout << "Enter a string to test: ";
getline(std::cin, input);
std::cout << "alphabetOnly: " << alphabetOnly(input) << std::endl;
}
http://coliru.stacked-crooked.com/a/340465d41ecd8c8e
There's quite a few things wrong with your code, but to start with here's your main error corrected.
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
//function to output string without spaces, numbers, or punctuations
string alphabetOnly (string input){
int size;
int i= 0;
size = (int)input.size();
while (i < size){
if(isalpha(input[i]))
{
i++;
}
else
input.erase(input.begin( ) + i );
}
return input;
}
int main() {
string input;
cout << "Enter a string to test: ";
getline(cin, input);
cout << "alphabetOnly: " << alphabetOnly(input) << endl;
}
But this is awfully inefficient because you swhift all the remaining unchecked characters each time you delete.
You should use something like
input.erase( remove_if( input.begin(), input.end(), not( isalpha ) ), input.end( ));
This is known as the remove-erase idiom, whihc you can lookup anywhere.

Reading information into array of structs c++

I'm making a program for my c++ class. Ultimately I want my program to perform a quicksort on a text file of contacts in the following format:
Firstname Secondname Number
Each contact is separated by a new line. I've started by counting the number of lines and using dynamic memory allocation to create an array of structs which has the same size as the number of lines.
However, when I tried to read in the information from the text file and output it to the screen, all I get is gibberish. I've had a look around on the internet to try and find a solution but everything I've found seems to use a different syntax to me.
Here's my code so far:
#include <iostream>
#include <fstream>
#include <istream>
char in[20];
char out[20];
using namespace std;
struct contact
{
char firstName[14];
char surName[14];
char number[9];
};
//structure definition
int main(void){
cout << "Please enter the input filename: " << endl;
cin >> in;
ifstream input(in);
if(!input){
cerr << "failed to open input file " << in << endl;
exit(1);
}
cout << "Please enter tne output filename: " << endl;
cin >> out;
// read in the input and output filenames
char a;
int b=0;
while (input.good ())
{
a=input.get ();
if (a=='\n')
{
b++;
}
}
// count the number of lines in the input file
input.seekg (0, ios::beg);
//rewind to beginning of file
contact* list = new contact[b];
//dynamically create memory space for array of contacts
int i = 0.;
while(input){
if(i >= b) break;
if(input >> *list[i].firstName >> *list[i].surName >> *list[i].number) i++;
else break;
}
input.close();
//read information from input file into array of contacts
for(int N = 0; N < b; N++){
cout << list[N].firstName << list[N].surName << list[N].number << endl;
}
ofstream output(out);
int k = 0;
for(int k = 0; k<b; k++){
output << list[k].firstName << " " << list[k].surName << " " << list[k].number << endl;
}
//print out the unsorted list to screen and write to output file
//i've done both here just to check, won't print to screen in final version
output.close();
delete []list;
} // end of main()
You reset the files location to the beginning, but the files eofbit is still labeled as true from when you first read the amount of lines. A quick fix to this is re-opening the file after you read the lines, possibly making the line count a function to clean up code.
int lines(const string path)
{
ifstream tmp(path.c_str());
string temp;
int count = 0;
getline(inFile,temp);
while(inFile)
{
count++;
getline(inFile,temp);
}
tmp.close();
return count;
}
Okay, I put together a quick and dirty method using newer C++ constructs to get you most of the way there. You're on your own for writing to the file (trivial) and the quicksort, though I've put the struct into a vector for you, so sorting the vector is as easy as writing a custom function to compare one struct vs the other. I apologize in advance if some of the code is less than canonical C++. I'm way past my bed time, and way tired, but this was interesting enough of a problem that I wanted to give it a go. Happy coding!
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
#include <sstream>
using namespace std;
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
struct contact
{
std::string firstName;
std::string surName;
std::string number;
contact(std::string& fName, std::string& lName, std::string& num) : firstName(fName), surName(lName), number(num) {}
};
//structure definition
char in[20];
char out[20];
int main()
{
std::vector<contact> contacts;
cout << "Please enter the input filename: " << endl;
cin >> in;
ifstream input(in);
if(!input){
cerr << "failed to open input file " << in << endl;
exit(1);
}
cout << "Please enter tne output filename: " << endl;
cin >> out;
std::string sinput;
// read in the input and output filenames
while (input.good ())
{
getline(input, sinput);
vector<string> tokens = split(sinput, ' ');
if (tokens.size() == 3)
{
contact c(tokens[0], tokens[1], tokens[2]);
contacts.push_back(c);
}
}
input.close();
//read information from input file into array of contacts
std::cout << "Outputting from vector..." << std::endl;
for_each(contacts.begin(), contacts.end(), [](contact& c) {
cout << c.firstName << " " << c.surName << " " << c.number << endl;
});
return 0;
}
Also, just want to give credit that the split methods come from this answer on this very site. Cheers!

need help with vector out of range error

guys, I'm reading from a file and input into a vector, but I keep getting a pop up box with: "vector employees out of range!" error. It is like if I'm trying to access pass the last index in the vector, but if that's the case I don't see... any help appreciated
text file:
123 vazquez 60000
222 james 100000
333 jons 50000
444 page 40000
555 plant 40000
code:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct employees { int id; string lname; double salary; };
void getData(vector<employees>& list, ifstream& inf);
int i = 0;
int main()
{
string filename("file2.txt");
vector<employees> list;
ifstream inf;
inf.open(filename);
getData(list, inf);
inf.close();
for(unsigned int j = 0; j < list.size(); j++)
{
cout << list[j].id << " " << list[i].lname << endl;
}
system("pause");
return 0;
}
void getData(vector<employees>& list, ifstream& inf)
{
int i = 0;
while(inf)
{
inf >> list[i].id >> list[i].lname >> list[i].salary;
i++;
}
}
When you pass list into getData(), it has zero elements in it. You then try to access the element at index i (starting at 0), but there is no such element, hence the error.
You need to insert new elements into the container; the easiest way to do this would be to create a temporary object, read the data into that object, and then insert that object into the container.
employee e;
while (inf >> e.id >> e.lname >> e.salary)
list.push_back(e);
Note that this also fixes your incorrect input loop. In your incorrect loop, the stream could reach EOF or otherwise fail during one of the reads in the loop, but you don't detect that until after you've incremented i.
In your while loop in getData, you need to push_back an employees each time. Or you can define the >> operator for your employees class, and you wouldn't even need the getData function, you could just past an istream_iterator into the vector constructor.
Example using istream_iterator:
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
struct employee { int id; std::string lname; double salary; };
std::istream& operator>>(std::istream& is, employee& e) {
return is >> e.id >> e.lname >> e.salary;
}
int main() {
std::string filename("file2.txt");
std::ifstream inf;
inf.open(filename); //add error checking here
std::vector<employee> list((std::istream_iterator<employee>(inf)), std::istream_iterator<employee>());
for (std::vector<employee>::iterator iter = list.begin(); iter != list.end(); ++iter) {
std::cout << iter->id << " " << iter->lname << std::endl;
}
return 0;
}
list[i].lname should be list[j].lname