I have a text file with words and integers. The task is to read only integers from it ignore words. This is an example of such file:
seven 7
I declare an int variable and try to read the ifstream into it (echoing the state of ifstream):
#include <iostream>
#include <fstream>
int main() {
int num = -1;
std::ifstream ifs("file.in");
std::cout << ifs << std::endl;
ifs >> num;
std::cout << ifs << std::endl;
if ( ifs.fail() )
ifs.clear();
std::cout << ifs << std::endl;
ifs >> num;
std::cout << ifs << std::endl;
std::cout << num << std::endl;
return 0;
}
To which I get an output:
1
0
1
0
-1
It's obvious that 'ifs' fails when trying to read a word into an int variable. My question is why does it fail the second time after being cleared?
The first failure doesn't advance the stream position, so the second tries again with exactly the same results. You'll need to skip over the unwanted word, either reading it into a string or using ignore.
Related
I am trying to read a string of three number using sstream but when I try to print them, I am getting a wrong output with four numbers.
Code:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
string a("1 2 3");
istringstream my_stream(a);
int n;
while(my_stream) {
my_stream >> n;
cout << n << "\n";
}
}
Output:
1
2
3
3
Why I get four numbers in the output compared to three numbers in input string?
Here
while ( my_stream )
my_stream is convertible to bool and returns true if there's no I/O error.
See: https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool
So, after the last reading, there's no I/O error yet, so it iterates again and there's an error and nothing is read into n in this statement:
my_stream >> n;
And, std::cout prints the last extracted value again i.e. 3.
The solution could be to directly check I/O error after reading in while (preferred):
while ( my_stream >> n )
{
std::cout << n << '\n';
}
or, print only if the reading is successful using an if:
while ( my_stream )
{
if ( my_stream >> n ) // print if there's no I/O error
{
std::cout << n << '\n';
}
}
Example (live):
#include <iostream>
#include <sstream>
int main()
{
std::string a { "1 2 3" };
std::istringstream iss{ a };
int n {0};
while ( iss >> n )
{
std::cout << n << '\n';
}
return 0;
}
Output:
1
2
3
Relevant: Why is "using namespace std;" considered bad practice?
You are printing the data before checking if readings are successful.
while(my_stream) {
my_stream >> n;
should be
while(my_stream >> n) {
Related (doesn't seem duplicate because eof() isn't used here):
c++ - Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong? - Stack Overflow
I have a text file:
1
2
3
stop
4
The code has to add each number to the previous number to get a new value and it needs to stop when it reads the "stop" in the file.
For example output would be:
1
3
5
Reading has stopped
How can I break the code for my output to be like this?
The "reading has stopped", only has to appear when there is a 'stop' in the file. otherwise the output should just be numbers.
You can read each piece of the file into a string and end if the input is "stop". If the input isn't "stop" you can convert it to an int using std::stoi
#include <string>
#include <iostream>
#include <fstream>
int main() {
std::string numberString;
std::ifstream file{ "filename.txt" };
int previousNumber = 0;
while (file >> numberString)
{
if(numberString == "stop")
{
break;
}
try {
int number = std::stoi(numberString);
std::cout << (number + previousNumber) << " ";
previousNumber = number;
} catch(...) {
std::cout << "invalid number" << std::endl;
}
}
file.close();
std::cout << "Reading has stopped" << std::endl;
}
If your text file has only one string "stop", then there's a very easy solution: you just keep reading integers until the reading fails
int main() {
ifstream ifs("test.txt");
int first = 0;
int second;
while (ifs >> second) {
cout << first + second << ' ';
first = second;
}
cout << "Reading has stopped" << endl;
return 0;
}
The problem with this solution is that if you have other strings in the text file and you want to handle them in a different way, this solution will fail.
Hope it helps.
I have a program that takes a text file and list the words and how many times they are used. It works but I can't figure out how to print out the text file. Above the sorted words and how many times they appear, I want to display the text from the file. How would I do that? I tried several things but it either does nothing or screws up the rest of the code saying there are 0 unique words. And lastly how would print out the results so they are more ... table -ish...
/*
Something like this:
Word: [equal spaces] Count:
ask [equal spaces] 5
anger [equal spaces] 3
*/
Thank you for any assistance you can provide me.
#include <iterator>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <cctype>
using namespace std;
string getNextToken(istream &in) {
char c;
string ans="";
c=in.get();
while(!isalpha(c) && !in.eof())//cleaning non letter charachters
{
c=in.get();
}
while(isalpha(c))
{
ans.push_back(tolower(c));
c=in.get();
}
return ans;
}
string ask(string msg) {
string ans;
cout << msg;
getline(cin, ans);
return ans;
}
int main() {
map<string,int> words;
ifstream fin( ask("Enter file name: ").c_str() ); //open an input stream
if( fin.fail() ) {
cerr << "An error occurred trying to open a stream to the file!\n";
return 1;
}
string s;
string empty ="";
while((s=getNextToken(fin))!=empty )
++words[s];
while(fin.good())
cout << (char)fin.get(); // I am not sure where to put this. Or if it is correct
cout << "" << endl;
cout << "There are " << words.size() << " unique words in the above text." << endl;
cout << "----------------------------------------------------------------" << endl;
cout << " " << endl;
for(map<string,int>::iterator iter = words.begin(); iter!=words.end(); ++iter)
cout<<iter->first<<' '<<iter->second<<endl;
return 0;
}
I would just use a simple for loop like this:
for (int x = 0; x < words.size(); x++){
cout >> words[x] << endl
}
And then modify from there to get your desired format.
I did notice though, that you are not returning a value for main in all paths of the above code, which should give a compile time error, but did not when I compiled it, for some reason. I would remind you that you need to have a return value for main. Unless I am misunderstanding your question. I could not run this program without creating a sample file, and so could not test it without extra work. But the program did compile. I did not expect to, because of the missing return statement. If you can make this reproduce your error without me having to create a sample file of words, ei insert the list of words into the code and minimally reproduce the error, I would be able to help you better. As it is, I hope that I helped you.
Something like this should make it:
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <string>
int main( int argc, char* argv[] )
{
std::string file;
std::cout << "Enter file name: ";
std::cin >> file;
std::fstream in( file.c_str() );
if ( in.good() )
{
std::unordered_map<std::string, int> words;
std::string word;
//Use this to separate your words it could be '\n' or anything else
char cSeparator = ' ';
while ( in >> word )
{
//Print the word
std::cout << word << cSeparator;
++words[word];
}
std::cout << std::endl;
//Headers Word and Count separated by 2 tabs
std::cout << "Word:\t\tCount:" << std::endl;
for ( auto& w : words )
std::cout << w.first << "\t\t" << w.second << std::endl;
}
in.close();
return EXIT_SUCCESS;
}
However this is assuming that the text file only contains the words, if you have other kind of stuff there, you should be able to filter it as you want.
I have been having some problems with my code. I was asked to input elements from an .dat file into an array. For class we have to do this for various files without knowing how many elements will be in each file. The only thing we know is that here will never be more then 5000 elements per file.
One of my input file has the following elements:
5.675207 -0.571210
0.728926 0.666069
2.290909 0.751731 2.004545 0.907396
0.702893 0.646427 5.909504 -0.365045
2.082645 0.871841 5.597107 -0.633507
6.117769 -0.164663 6.091736 -0.190282
5.571074 -0.653433 4.503719 -0.978307
3.983058 -0.745620
3.670661 -0.504729
5.857438 -0.413001
When I run my code:
#define _CRT_NONSTDC_NO_DEPRECATE
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main(int argc, char * argv[])
{
ifstream fin;
ofstream fout;
if (argc < 3)
{
cout << "Incorrect usage: prog.exe filenname number" << endl;
cout << "Exiting now, please try again." << endl;
return -1;
}
fin.open(argv[1]);
if (!fin)
{
cout << "Error opening file \"" << argv[1] << "\", exiting." << endl;
return -1;
}
fout.open(argv[2]);
int count = 0;
int word;
double points[5000];
while (fin >> word)
{
fin >> points[count];
++count;
}
fout << "Numer of points is: " << count/2 << endl;
for (int i = 0; i < count; i++)
{
fout << points[i] << " ";
}
fin.close();
fout.close();
return 0;
}
I outputted the elements just to make sure that they were properly inputted. I get the following and I don't know why.
0.675207 0.57121
0.728926 0.666069
0.290909 0.751731 0.004545 0.907396
0.702893 0.646427 0.909504 0.365045
0.082645 0.871841 0.597107 0.633507
0.117769 0.164663 0.091736 0.190282
0.571074 0.653433 0.503719 0.978307
0.983058 0.74562
0.670661 0.504729
0.857438 0.413001
The first digit is converted to a 0 for some reason and the negative ones become positive. Would anyone know why this is occurring?
int word;
is doing you no favours. First it's an integer so fin >> word only reads the integer portion of the inputs. 5.675207 is read as 5. the .675207 is left in the file stream for fin >> points[count]. Words isn't stored anywhere to the 5 is discarded but the .675207 lives on as 0.675207 in points[0].
Where the negative signs are going I didn't bother trying to figure out because
while (fin >> points[count])
{
++count;
}
fixes everything.
When you read in the numbers from the the file you are extracting them as "word" and then storing them as "points". "word" is an integer and "points" is a double, this will give you unexpected behavior. The compiler should give you warnings about this.
I was given a homework assignment to generate a txt file containing a random number of lines, each with a random amount of integers, ranging between a minimum value and a maximum value. Lots of rand() fun.
In any case, that was the easy part. The second part of the problem is to read over the first file and create a second file that contains some statistics, such as: the sum of all integers in the file, their average, min and max values, and my main issue: the sum of all integers in each line.
I have written the following code:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <cmath>
using namespace std;
int main()
{
string newLine;
stringstream ss;
int newInput = 0, oldInput = 0;
int lineSum = 0;
int lineCounter = 0;
int allSum = 0;
int intCounter = 0;
double averageOfAll = 0;
int minInt = 0;
int maxInt = 0;
.... // generating the first file. No issues here.
ifstream readFile;
readFile.open("inputFile.txt");
ofstream statFile;
statFile.open("stat.txt");
if(readFile.is_open()) {
while (getline(readFile, newLine)) { //my problem should be somewhere
//around here...
ss.str("");
ss << newLine;
while(!ss.eof()) {
oldInput = newInput;
ss >> newInput;
cout << newInput << endl;
lineSum += newInput;
allSum += newInput;
intCounter++;
minInt = min(oldInput, newInput);
maxInt = max(oldInput, newInput);
}
lineCounter++;
statFile << "The sum of all integers in line " << lineCounter
<< " is: " << lineSum << endl;
lineSum = 0;
}
readFile.close();
averageOfAll = static_cast<double>(allSum)/intCounter;
statFile << endl << endl << "The sum of all integers in the whole file: "
<< allSum;
statFile << endl << "The average of value of the whole stream of numbers: "
<< averageOfAll;
statFile << endl << "The minimum integer in the input file: "
<< minInt;
statFile << endl << "The maximum integer in the input file: "
<< maxInt;
statFile << endl << endl << "End of file\n";
} else
cout << endl << "ERROR: Unable to open file.\n";
statFile.close();
return 0;
}
When running the program, it seems like my loops do iterate over all the lines in the file. However, they only collect the integers from the first line, and the rest remains 0.
I would post screenshots of my outputs, but I do not have enough rep :(
can anyone help out?
It worked!
inputFile.txt ^
statFile.txt (my output) ^
And like P0W and James Kanze suggested, it was a flag issue and a misuse of my streamstring. I corrected my code as follows:
.
.
.
while (getline(readFile, newLine)) {
stringstream ss(newLine);
while(ss >> newInput) {
lineSum += newInput;
allSum += newInput;
intCounter++;
minInt = min(minInt, newInput);
maxInt = max(maxInt, newInput);
}
.
.
.
Thank you all!
There are several issues, but the main one is that you're trying
to reuse ss (which should properly be an
std::istringstream). It's possible to do so, but it's fairly
difficult to get right, since streams hold a lot of state which
needs reinitializing. (In this case, the stream memorizes that
it has seen end of file, and doesn't do anything else until that
has been reset.) Your loop should look like:
while ( getline( readFile, newLine ) ) {
std::istringstream ss( newLine );
// ...
}
And once you've got the std::istringstream, you don't want to
loop until eof (which may or may not be set after the last
successful input); you want to loop until an input fails.
(After the input fails, you may want to check eof: if it
isn't set, the input failed because of a format error in the
line; e.g. someone entered "abc" instead of an integer.)
You can try following for your inner while loop
ss << newLine;
while( ss >> newInput )
{
//.... Your logic,
// might need little update
oldInput = newInput;
}
ss.clear( ); // clear the flags !