How to keep reading after while loop? - c++

I have a .txt file that has a sequence of numbers and spaces on the first line that I wish to read into a vector. Then there is a '$' symbol on the next line. On the line after that is another line containing a sequence of numbers and spaces (like the first) that I'd like to read into another vector. For example
1 2 3 4 5
$
4 3 2 1 6
I've tried everything but can't keep reading after the initial while loop reads in integers. How do I move past the second line and read the third? Right now It just outputs the first line. Currently, this is my code:
int main(int argc, const char * argv[]) {
ifstream file(argv[1]);
if (file.is_open() && file.good()){
int addMe;
vector<int> addMeList;
while(file>>addMe){
cout <<addMe<<endl;
addMeList.push_back(addMe);
}
string skip;
while(file >> skip)
cout << skip << endl;
int searchQuery;
vector<int> searchQueries;
while(file>>searchQuery){
searchQueries.push_back(searchQuery);
}
for (int i=0; i<searchQueries.size();i++)
{
cout << searchQueries[i]<<endl;
}
}
return 0;
}

Two problems:
The first loop will cause the streams failbit to be set (when it attempts to read the '$' from the second line). If that bit is set, you can't read more from the stream. You need
to clear the stream state.
Once you've done the above, the second loop will read the rest of the file.
One possible solution is to read lines instead. Use e.g. std::getline to read a line. Put the line into a std::istringstream, and read the values from that.

The program logic seems to be flawed. Using the first while loop you read the entire file word-by-word till the very end (not till the end of line), after that trying to read again fails, which is evaluated as false, thus it never even gets into the other loops. Instead, consider reading line by line using getline and then breaking it into ints using istringstream.
Here's how I'd improve it:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream> // include this header to use istringstream
using namespace std;
int main() {
ifstream file("text.txt"); // my test file; Replace with yours
if (file.is_open() && file.good()) {
string lineIn; // general line to read into
int i; // general int to read into
vector<int> addMeList;
// int addMe; // not needed anymore
getline(file, lineIn); // read a line 1
istringstream istr(lineIn); // string stream we can use to read integers from
while (istr >> i) {
cout << i << endl;
addMeList.push_back(i);
}
// string skip; // not needed anymore
getline(file, lineIn); // skips line 2
// int searchQuery; // not needed anymore
vector<int> searchQueries;
getline(file, lineIn); // read a line 2
istringstream istr2(lineIn); // string stream we can use to read integers from
while (istr2 >> i) {
searchQueries.push_back(i);
}
for (int i = 0; i < searchQueries.size(); i++)
{
cout << searchQueries[i] << endl;
}
}
return 0;
}
Input file:
1 2 3 4 5
$
4 3 2 1 6
Output:
1
2
3
4
5
4
3
2
1
6

Related

Stop input loop when input is done | std::cin

I want to write a function that gets a set of integers and saves them to a vector.
To get the integers I'm using a while loop.
Enter the vector elements: 1 2 3 4 5
I want the loop to stop looking for input after the last element is inputted or until a non-numberis inputted, however I'm having trouble with it.
It is an assignment, so it needs to read input from std::cin.
This is my code:
#include <iostream>
#include <vector>
bool NumInVect(int num, std::vector<int> vect)
{
bool numInVect = false;
for (int i = 0; i < vect.size(); i++)
{
if (vect[i] == num)
{
numInVect = true;
}
}
return numInVect;
}
int main() {
std::vector<int> tempVect;
std::vector<int> finalVector;
std::cout << "Enter the vector elements: ";
int currVal;
while (std::cin >> currVal)
{
std::cout << "-\n";
if (!NumInVect(currVal, tempVect))
{
tempVect.push_back(currVal);
}
std::cout << currVal << std::endl;
}
//the code never reaches this loop, since its stuck in the while loop
std::cout << "knak\n";
for (int i = 0; i < tempVect.size(); i++)
{
std::cout << tempVect[i];
}
}
I've tried doing multiple things like using std::cin.eof()/.fail(), std::cin >> currVal in the while loop, a do-while loop, but I can't seem to figure out how to get this to work. Does anyone have any tips on what to look into or how to approach this?
If your intention is to get all the input from a given line, and add individual numbers to the vector, then you want to read a line of input into a string, then use an istringstream to process that line of input.
A simplified example:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main() {
std::vector<int> tempVect;
std::string line;
std::getline( std::cin, line );
std::istringstream iss( line );
int curVal;
while ( iss >> curVal ) {
tempVect.push_back( curVal );
}
}
You should add a condition in your while loop so that it breaks when you want like:
if (temptVect.size() >= 5)
break;
I want the loop to stop looking for input after the last element is inputted or until a non-numberis inputted,
This loop should do exactly that.
while (std::cin >> currVal)
{
std::cout << "-\n";
if (!NumInVect(currVal, tempVect))
{
tempVect.push_back(currVal);
}
std::cout << currVal << std::endl;
}
This test while (std::cin >> currVal) will fail if read does not work and exit the loop. Since currVal is an integer, it will fail as soon as it tries to read something that is not an integer (note space and new lines are completely ignored).
What may be the issue is that std::cin is buffered. You can type a long time before filling up the buffer and causing the operator>> to do anything. To force this operator to read you have to force a flush this is usually done by hitting <enter> on the keyboard.
After the buffer is flushed it will read all the numbers on the input and exit the loop if a read fails. So you need to explicitly type not a number before hitting the <enter>.
eg:
1 2 3 4 5 X<enter>
or:
1<enter>
2<enter>
3<enter>
4<enter>
5<enter>
X<enter>
You need that non number to force the read to fail and the loop to exit.
Alternatively, you could say I want to read all the numbers on one line then exit the loop.
In that case: You should read a line and the processes the line. This is only a slight change from your above code.
std::string line; // Hold a line of text
std::getline(std::cin, line); // Read a line of text.
std::stringstream lineStream(line); // Convert string into stream
while (lineStream >> currValue) // Read each integer from the stream.
{ // Exits when the read fails to read
// a number becuase it is empty.
// The other stuff like before.
}

Getting unexpected numbers when reading integers from an array

I am trying to read integers from a file to an array, but when I try to read the elements of said array, I get numbers that have little to nothing to do with the numbers in the file.
#include <fstream>
#include <istream>
#include <iterator>
#include <string>
using namespace std;
//Main Function
int main()
{
//Declare variables and ask user for file names
string f1, f2;
int s1, s2, n = 0;
cout<<"Please enter the names of the files you would like to merge, file extensions included."<<endl;
cout<<"File 1 Name: ";
cin>>f1;
cout<<"File 2 Name: ";
cin>>f2;
//Opening files
ifstream fs1, fs2;
fs1.open(f1);
fs2.open(f2);
//Checking if both files exist
if (fs1 && fs2)
{
//Getting length of files
s1 = distance(istream_iterator<int>(fs1), istream_iterator<int>());
s2 = distance(istream_iterator<int>(fs2), istream_iterator<int>());
//Declaring arrays and writing values to them
int a1[s1], a2[s2];
while(!fs1.eof())
{
fs2 >> a2[n];
n++;
}
//Closing files
fs1.close();
fs2.close();
//Reading array
for (int i=0; i<s2; i++)
{
cout<<a2[i]<<endl;
}
}
//If the requested files do not exist
else
{
cout<<"No file exists with that name."<<endl;
}
}
I have two text files, file1.txt and file2.txt. The code opens the files, determines the number of integers within, and creates an array with the number of integers.
file1.txt: 45 69 87 3 9 32 11 9 6 66
file2.txt: 4
The output I get when reading the array for file1.txt (a1[]) gives very unexpected numbers:
File 1 Name: file1.txt
File 2 Name: file2.txt
0
0
1878276352
6421656
4
6422016
3756032
48
16
4199922
As you can see, this is not the output I expected. file2.txt only consists of the number 4, and its ouput was simply 16
I am somewhat new to c++ and programming in general, so you might have to bear with me. Does anybody see what I've done wrong?
I am using Code::Blocks and gcc is my compiler. Thank you for your time.
Tested, using std:
std::vector<int> read_file(std::string filename) {
int n;
std::vector<int> vector;
std::ifstream file;
file.open(filename);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
std::istringstream is(line);
while (is >> n) {
vector.push_back(n);
}
}
file.close();
}
return vector;
}
int main() {
std::vector<int> vector = read_file("file1.txt");
for (auto element: vector) {
std::cout << element << std::endl;
}
}
Note: int a1[s1], a2[s2]; doesn't comply with the ISO C++ standard. For details, see Why aren't variable-length arrays part of the C++ standard? If you cannot know the length of an array prior to runtime, consider using std::vector.
It is as #user4581301 says, you need to rewind the files, since std::distance() will read the files to the end.
Otherwise you will already be at the end of the files, and you won't read any data into your arrays, which means your arrays will be holding uninitialized memory.
Here is a solution:
// Rewind the files
fs1.clear();
fs2.clear();
fs1.seekg(0);
fs2.seekg(0);
// Read into array 1
for (n = 0; fs1 >> a1[n]; ++n) {}
// Read into array 2
for (n = 0; fs2 >> a2[n]; ++n) {}
seekg() sets the position in the stream to the given offset. seekg(0) resets to the beginning of the stream.
clear() clears the stream's internal error state flags, including the eofbit.

finding a word from a file and substitution into other file

I have two text files like these:
11.txt:
1 5.66
2 4.95
3 2.55
4 0.99
5 2.87
NB.txt:
1 2 3 4 5
4 5 3 2 1
3 4 5 1 2
I have written the below code to fine, for example, "1" from File 1, and search it in File 2, then substitute "1" with "5.66". and repeat it for other numbers, i.e. 2,3,4,5. but I don't know why it doesn't work. additionally, it doesn't read the first line of 11.txt.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
string line;
double AtomId, Atom_radius,search ;
ifstream AtomId_file ("11.txt");
string namefile;
if (AtomId_file.is_open()){
for (int linenox = 0; getline (AtomId_file,line) && linenox < 6; linenox++){
if (linenox == 0) AtomId_file>>AtomId>>Atom_radius;
}
cout<<"AtomId: "<<AtomId<<" Atom_radius: "<<Atom_radius<<endl;
cout<<namefile<<"\n";
}
ifstream NB("NB.txt");
size_t pos;
if (NB.is_open())
{
search = AtomId;
getline(NB,line);
pos=line.find(search);
if(pos!=string::npos)
{
search = Atom_radius;
cout <<"Found!";
}
}
ofstream myfile;
myfile.open ("12.txt");
myfile << search << "\n";
}
the output in 12.txt is:
2
instead of :
5.66 4.95 2.55 0.99 2.87
0.99 2.87 2.55 4.95 5.66
2.55 0.99 2.87 5.66 4.95
I understand that your are new to C++.
I analyzed your code and put in tons of comments, where the errors are. You need to change your design. Before starting to type in code, you must first write down, what should be done. Then, and this is most important, you think (without taking any language into consideration) how you can solve the problem. This is most important. Also for you later programming career. The design is most important. So think 3 hours, how it could be done. Search possible design solutions in the internet. Write it on a piece of paper or somewhere.
Then, after hours of thinking, select an apropriate language and check, how it could be implemented.
I show a standard C++ solution below. You will not understand it immediately. So please try to understand the design first. Then lookup all used C++-statements in the internet and try to understand.
Read some good C++ books, before starting to code.
Please see first your commented code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std; // You should not use this line at all. Use qualified names.
int main()
{
string line;
double AtomId, Atom_radius, search; // These variables are not initalized
ifstream AtomId_file("r:\\11.txt");
string namefile;
if (AtomId_file.is_open()) { // You should not use is_open but simply if (AtomId_file)
// Here you have a loop running from 0,1,2,3,4,5. That are 6 loops. But you have only 5 lines in your sourcefile
// The you read one line, each time the loops runs. So in the beginning, this will read the first line
for (int linenox = 0; getline(AtomId_file, line) && linenox < 6; linenox++) {
// And only for the first loop event, when linenox==0, you read then next line "2 4.95"
// So you read already lines. But not more.
// ypu need to read line by line (only one per loop) and then store the result in an appropriate STL Container
if (linenox == 0) AtomId_file >> AtomId >> Atom_radius;
}
// Since you assigned the data only once, the values will be 2, 4.95
// They will never change
cout << "AtomId: " << AtomId << " Atom_radius: " << Atom_radius << endl;
// The variable namefile has never been initailized and is always emtpy, So ""
cout << namefile << "\n";
}
ifstream NB("r:\\NB.txt");
size_t pos; // Not initialized
if (NB.is_open()) // Not recommended. Use "if (NB) instead". In general, use more meaningful variable names
{
search = AtomId; // search is now 2 and never somthing else
getline(NB, line); // Read exactly one (and only this one time) a line containing 1, 5.66
pos = line.find(search); // So, 2 will never be found
if (pos != string::npos) // Always false, can never be true
{
search = Atom_radius; // Will never be executed
cout << "Found!"; // Will never be executed
}
}
ofstream myfile; // You can write directly ofstream myfile("12.txt");
myfile.open("12.txt");
myfile << search << "\n"; // And the output will always be 2.
}
And here is a correct and working example:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <iterator>
int main() {
// Open the file 11.txt and check, if it could be opened
if (std::ifstream file11("11.txt"); file11) {
// Define variable id and attribute and initialize them to theire default values.
unsigned int id{};
double attribute{};
// Here we will store all values (id, attribute) of all lines that we read in the follwing loop
std::unordered_map<unsigned, double> replacement{};
// Read in a llop ALL lines and extract id and attribute, and, check if this worked
while (file11 >> id >> attribute) {
// Create a new replacement value for id
replacement[id] = attribute;
}
// So, now, all data from file 11.txt is read and stored.
// We will now read the next file and store the data
// Open next input file NB.txt and check, if that worked
if (std::ifstream fileNB("NB.txt"); fileNB) {
// And already now, open output file 12.txt and check, if open worked
if (std::ofstream myfile("12.txt"); myfile) {
// Read a complete line and check, if that worked. Read all lines in a loop
for (std::string line; std::getline(fileNB, line); ) {
// Put the line in a std::istringstream, so that we can extract each single value
std::istringstream iss(line);
// We will store the single values of the just read line into a vector
// This we do, because we do not know, how many values will be in that line
// We use a so called iterator, to iterate over all elements in the just read line
// The result will be stored in a vector
// The istream_iterator will call the ">>"-operator, until the line is empty
// For the vector, we use its range constructor
std::vector values(std::istream_iterator<unsigned>(iss), {});
// Now go through all values, replace them and out the result into the output file
for (const unsigned& u : values) myfile << replacement[u] << " ";
myfile << "\n";
}
}
}
}
return 0;
}
Of course there are many other possible solutions

How to read each number individually from lines when reading from a file

Needing guidance on how to read numbers from a file and setting each individual number from the rows to set up functions
I have read through the file and was able to print out the numbers onto the screen, but I'm running into some understanding on how am I going to be able to print use on of those numbers for a specific function that I am wanting to use. For instance I have
string line;
while(getline(file,line)){
cout<<line<<"\n";
}
/* What the file is and what it prints out onto the screen
3 6
2 3 2
2 1 6
2 1 4
1 2 3
1 1 2
2 1 8
*/
For instance I want to use the 3 and 6 for a function such as
create_list(int x, int y){}
In other words each set set of numbers in each row will be representing input to some functions
Parsing variable number of integers from input line
It is not clear from the question what you are trying to do. As mentioned in the comments, you can parse the file directory using the ifstream. I am lazy and always parse files with getline(<ifstream>, str) and then parse the lines using an istringstream. I make fewer mistakes this way.
One of the questions was why you have multiple line lengths. No matter, I made up functions that were called depending on whether there were 1, 2, or 3 integers for each input line.
The great thing about parsing the input using a stream, is that the stream processor can parse ints, doubles, or whatever.
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
int square(std::vector<int> &ints)
{
return ints[0] * ints[0];
}
int rectangle(std::vector<int> &ints)
{
return ints[0] * ints[1];
}
int volume(std::vector<int> &ints)
{
return ints[0] * ints[1] * ints[2];
}
int main()
{
std::ifstream file;
file.open("example.txt");
std::string str;
while (getline(file, str)) {
int parsed_int;
std::vector<int> ints;
int index = 0;
std::stringstream stream(str);
while (stream >> parsed_int) {
ints.push_back(parsed_int);
++index;
}
int answer = 0;
// index is the number of integers read on this line from the file
switch (index) {
case 0:break;
case 1:answer = square(ints);
break;
case 2:answer = rectangle(ints);
break;
case 3:answer = volume(ints);
break;
default:break;
}
std::cout << "Answer is " << answer << "\n";
}
}

read space delimited number from file up to newline character

I have a text file that contains the following data.
The first line is this:
5 4 3 2 1
The second line is this:
1 2 3 4 5
I am trying to read data from one line at a time because my first linked-list object is going to use the data from the first line and my second linked-list object is going to use data from the second line. The best I have been able to come up with is the following function:
void polynomial::allocate_poly(std::ifstream& in, const char* file, const char* number)
{
in.open(file);
std::string str;
char b;
int m = 0;
for(int i = 0; !in.eof(); ++i)
{
in >> b;
m = b - '0';
a.insert(m);
}
There is a few problems with this approach. I have tried different binary operators in my for loop such as b == '\n' and none of them seem to trigger when b is a newline character.
Also allocating the numbers from the file this way it looks like
5 5 4 3 2 1 1 2 3 4 5 , so it seems to be copying an extra 5 somewhere, I am not sure if this is the eof bit or not.
I have also attempted to use the getline function but for some reason it seems to only copy the first integer and then dumps the rest of the file. I know certainly I am not using it correctly but all the examples I can find are for typing the file name such as cin.getline and I want to be able to pass my file name as a command line argument when running the program instead.
My question is how can I allocate the numbers on the first row up to the newline char and then pass the ifstream in variable to another object to allocate the second line? Thanks for your help.
You don't say what a is, but never mind: If you want line based parsing, you need to have getline in the outer loop. Also, never use eof, as it doesn't do what you want. Rather use the implicit conversion to bool to check if an operation succeeded.
Here's the typical gig:
#include <sstream>
#include <fstream>
#include <string>
std::string line;
std::ifstream infile("myfile.txt");
while (std::getline(infile, line)) // this does the checking!
{
std::istringstream iss(line);
char c;
while (iss >> c)
{
int value = c - '0';
// process value
}
}
However, this conversion from char to int is cumbersome and fragile. Why not read an integer directly?
int value;
while (iss >> value) { /* ... */ }
Edit: Based on your comment, here's the code to read exactly two lines:
std::string line;
int val;
if (std::getline(infile, line))
{
std::istringstream iss(line);
while (iss >> value) { /* process first line */ }
}
if (std::getline(infile, line))
{
std::istringstream iss(line);
while (iss >> value) { /* process second line */ }
}