I read numbers from a file, apply 3 functions and print out to another file:
int main(int argc, char** argv) {
std::ifstream fin;
fin.open("input.txt");
std::ofstream fout;
fout.open("output.txt", std::ios::app);
char arr[50];
int a,b;
int N;//number to factor
while (!fin.eof()){
//Print backward
fin >> arr;
PrintBackward( arr );
fout << endl;
//Greatest common divisor
((fin >> a) >> b);
fout << gcd( a, b );
fout << endl;
//Find prime factor
fin >> N;
PrimeFactor(N);
fout << endl;
}
fin.close();
fout.close();
return 0;
}
After running, the result is duplicated:
olleh
3
2 3 7
olleh
3
2 3 7
I read a similar article but it's about reading into 1 variable so it seems not to be feasible.
If I set a break at the end of the while loop, it's fine. Is there any way not to use break?
while (!whatever.eof()) is essentially always wrong, and will never detect the end of the file correctly. In your case, it's easiest to coalesce the reads together, and then do all the processing, something like this:
while (fin >> arr >> a >> b >> N) {
PrintBackwards(arr);
fout << "\n";
fout << gcd(a, b) << "\n";
fout << PrimeFactor(N) << "\n";
}
The crucial part is to check the result of the read, instead of checking and reading separately from each other.
A couple more bits of advice: I'd use an std::string instead of an array. I'd also separate reversing the string from printing it, so you can have something like:
fout << reverse(arr) << "\n"
<< gcd(a, b) << "\n"
<< PrimeFactor(N) << "\n";
Emphasizing the commonality between the operations tends to be a good thing.
Edit: Just for fun, I'll point out another way you could do things if you wanted. Since you're basically reading and processing the four items as a group, you could make that grouping a bit more explicit:
struct item {
std::string arr;
int a, b, N;
friend std::istream &operator>>(std::istream &is, item &i) {
return is >> arr >> a >> b >> N;
}
};
struct process {
std::string operator()(item const &i) {
std::ostringstream buffer;
buffer << reverse(arr) << "\n" << gcd(a, b) << "\n" << PrimeFactor(N);
return buffer.str();
}
}
With this, you can let the standard library deal with all the details of the reading and writing, checking end of file, etc.:
std::transform(std::istream_iterator<item>(fin),
std::istream_iterator<item>(),
std::ostream_iterator<std::string>(std::cout, "\n"),
process());
My guess is that you're checking eof too early - it's only set when you try to read and the read fails because you're at the end of the file. Try adding this after fin >> arr:
if (fin.eof()) break;
Actually you should be checking for errors after every IO operation - not to do so is sloppy coding and won't be robust.
Related
TEXT FILE IM READING
1 1 1
1.2 -2.3 0.4
-2 -3 -4
+0 -2 8.85
2.345
My code:
#include <iostream>
#include <fstream>
using namespace std;
double readFile(ifstream &myfile, double &a, double &b, double &c);
int main()
{
int counter = 0;
double a, b, c;
string line, inputFile, outputFile;
cout << "Enter the name of your input file: ";
cin >> inputFile;
cout << "Enter the name of your output file: ";
cin >> outputFile;
ifstream myfile(inputFile);
if(myfile.is_open())
{
while(!myfile.eof())
{
readFile(myfile, a, b, c, counter);
calculations(a, b, c);
}
}
else cout << "unable to open file";
return 0;
}
double readFile(ifstream &myfile, double &a, double &b, double &c)
{
//Reads one line of the file
myfile >> a >> b >> c;
cout << a << " " << b << " " << c << endl;
}
What i want to do is that if the last line does not have 3 values i want to have some sort of stop code where it stops the processing if it has less than 3 values and the leftovers values from the previous line wont be assigned
Your biggest issue is that >> skips leading whitespace, so it doesn't differentiate between a ' ' (space) or '\n' -- it's just whitespace. To handle it correctly, you need to read each line into a std::string and then create a std::stringstream from the line.
Then read your three double values from the std::stringstream with >>. That way you can read no more double values than are present in the line. Otherwise if you just try and use >>, you will happily read 2 double values from one line and the third from the next without any indication of that happening.
You next need your function to indicate success/failure of reading the three double values from the line. A return type of bool is all you need. If you read three valid double values, return true and do your calculations() otherwise, if you return false, stop trying to read from the file.
A short example would be:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
bool read3doubles (std::ifstream& f, double& a, double& b, double& c)
{
std::string line {}; /* std::string to hold line */
if (getline (f, line)) { /* if line read from file */
std::stringstream ss(line); /* create stringstream from line */
if (ss >> a >> b >> c) /* if 3 doubles read from line */
return true; /* return true */
}
return false; /* otherwise, return false */
}
void calculations (double& a, double& b, double& c)
{
std::cout << a << " " << b << " " << c << '\n';
}
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least 1 argument given */
std::cerr << "error: insufficient number of arguments.\n"
"usage: " << argv[0] << " <filename>\n";
return 1;
}
std::ifstream f (argv[1]); /* open file-stream with 1st argument */
double a, b, c;
if (!f.good()) { /* validate file open for reading */
std::cerr << "errro: file open failed '" << argv[1] << "'.\n";
return 1;
}
while (read3doubles(f, a, b, c)) /* while 3 doubles read from file */
calculations (a, b, c); /* do your calculation */
}
(note: the calculations() function just outputs the three doubles when successfully read)
Example Use/Output
Using your input in the file dat/3doubles.txt, you would have:
$ ./bin/read3doubles dat/3doubles.txt
1 1 1
1.2 -2.3 0.4
-2 -3 -4
0 -2 8.85
Let me know if you have further questions.
std::istream sets failbit when operator>> failed to extract value from stream. In your code, failbit will be set if it fails to parse 3 values that can be parsed into double, and you can query if failbit is set by std::failbit().
double readFile(ifstream &myfile, double &a, double &b, double &c)
{
myfile >> a >> b >> c;
if(myfile.fail())
{
// failbit is set if one of a, b or c is not parsed successfully.
// do some stop code here.
}
cout << a << " " << b << " " << c << endl;
}
Remember, std::istream does nothing for further operation if failbit is set. If you're needed to continue reading from the stream, you should clear failbit by calling std::clear().
I added a different function that chops a line by space and converts them to numbers. Your main function remains largely unaffected. Though I made some changed like adding a std::vector, early return to remove some nesting.
Also, I changed the main while condition from eof to std::getline.
Operations on std::string_view are very cheap.
This way you can check on every line that the number of values read is always what you need.
For bad input, you can easily debug if a line/ word is not number by printing it in the exception catcher.
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
void read_values(std::string_view line, std::vector<double> &values);
void calculations(int, int, int);
int main()
{
string inputFile, outputFile;
cout << "Enter the name of your input file: ";
cin >> inputFile;
cout << "Enter the name of your output file: ";
cin >> outputFile;
ifstream myfile(inputFile);
if (!myfile.is_open()) {
cout << "unable to open file";
return -1;
}
std::string line;
std::vector<double> values;
while (std::getline(myfile, line, '\n')) {
read_values(line, values);
std::cout << values.size();
}
return 0;
}
void read_values(std::string_view line, std::vector<double> &values)
{
while (!line.empty()) {
const std::string_view::size_type pos_space{line.find(' ')};
try {
values.push_back(std::stod(std::string(line.substr(0, pos_space))));
}
catch (const std::invalid_argument &ex) {
std::cout << ex.what() << std::endl;
return;
}
line.remove_prefix(pos_space + 1);
}
}
I have a code like this, concerning stringstream. I found a strange behavior:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
int p, q;
fstream file;
string str;
stringstream sstr;
file.open("file.txt", ios::in);
if(file.is_open()) {
while(getline(file, str)) {
sstr << str;
sstr >> p >> q;
cout << p << ' ' << q << endl;
sstr.str("");
}
}
file.close();
return 0;
}
Suppose I have file.txt as
4 5
0 2
with return after 5 in the first line and 2 in the second line. The program gives me:
4 5
4 5
which means p and q are not correctly assigned. But I checked that each time sstr.str() with get the correct string of the line.
Why stringstream has a behaviour like this?
The stream is in a non-good state after reading the second integer, so you have to reset its error state before resuming.
Your real mistake was to not check the return value of the input operations, or you would have caught this immediately!
The simpler solution may be to not try to reuse the same stream, but instead make it anew each round:
for (std::string line; std::getline(file, line); )
{
std::istringstream iss(line);
if (!(iss >> p >> q >> std::ws) || !iss.eof())
{
// parse error!
continue;
}
std::cout << "Input: [" << p << ", " << q << "]\n";
}
When you read p, then q, you reach the end of your stream and the flag eofbit is set and you can't do anything anymore.
Just clear() it and your code will work as you expect.
But you may want to use directly file instead, and file.close(); will have a better place within your if:
fstream file;
file.open("file.txt", ios::in);
if(file.is_open()) {
int p, q;
while(file >> p >> q) {
cout << p << ' ' << q << endl;
}
file.close();
}
Your code has some redundant lines: fstream could be opened during the definition and no explicit file close() is needed, as it is automatically destroyed at the end of main().
Additionally, in your file reading loop, the line: sstr << str should be replaced with stringstream sstr(line); if you want to initialize a new stringstream for each line, which will make the line: sstr.str(""); redundant as well.
Applying the above corrections, here is your code:
int main() {
int p, q;
fstream file("file.txt", ios::in);
// check status
if (!file) cerr << "Can't open input file!\n";
string line;
// read all the lines in the file
while(getline(file, line)) {
// initialize the stringstream with line
stringstream sstr(line);
// extract line contents (see Note)
while (sstr >> p >> q) {
// print extracted integers to standard output
cout <<"p: " << p <<" q: "<< q << endl;
}
}
return 0;
}
Note: The line while (sstr >> p >> q) assumes that a line contains only integers, separated by white space.
I have a program that puts some strings and integers in a structure.
now I want to make it so if the program is opened it gets all information from the file and if the program is closed I want to save all info to the same file so I can find it the next time.
What is the best way to do that with one file to put it all in or a seperate file per each variable?
If I have figured that out I need to know how to find a specific line and than read the info from there. (like the name of line 59 goes to the 59th place in a structure array.),
then I have to overwrite certain info like the amount of games played and how many of them are won, lost or tied. (it is a little game.)
Here is the structure:
struct Recgame{
char name[20];
char surname[20];
int games; //needs to be overwritable in file
int won; //needs to be overwritable in file
int same; //needs to be overwritable in file
int lost; //needs to be overwritable in file
int place; //needs to be overwritable in file
int money; //needs to be overwritable in file
} info[100];
The C++ way to do this, is writing an stream-inserter and a stream-extractor for the struct Recgame.
The prototypes are:
std::ostream& operator<<( std::ostream& out, const Recgame& recgame );
std::istream& operator>>( std::istream& in, Recgame& recgame );
After this, You can easy write the infos to a file
ofstream file("afile.txt");
for( int i=0; i<n; ++i ) // n should be the number of the objects
file << info[i];
the implementation of the writing could be:
std::ostream& operator<<( std::ostream& out, const Recgame& recgame )
{
// make sure, that the char-arrays contain a closing char(0) -> ends
out << recgame.name << "\n";
out << recgame.surname << "\n";
out << recgame.games << " " << recgame.won << " " << recgame.same << " " <<
recgame.lost << " " << recgame.place << " " << recgame.money << "\n";
return out;
}
the implementation of the reading extractor
std::istream& operator>>( std::istream& in, Recgame& recgame )
{
in >> std::skipws; // skip leading spaces
in.getline( recgame.name, 20 ).ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); // requires #include <limits>
in.getline( recgame.surname, 20 ).ignore( std::numeric_limits< std::streamsize >::max(), '\n' );
in >> recgame.games >> recgame.won >> recgame.same >>
recgame.lost >> recgame.place >> recgame.money;
return in;
}
read it from file:
ifstream file("afile.txt");
int n = 0; // number of read objects
for( ; n < N && file >> info[n]; ++n ) // -> const int N = 100;
;
if( file.eof() )
cout << "Ok - read until end of file\n";
cout << "read " << n << " objects" << endl;
You can use fwrite function in C to write the structure in a binary file, and fread to read it back again.
If you want to use C++ style file I/O, then you need to overload << and >> operator.
I'm having an issue with istringstream not storing the values it reads. Here is what I have:
if(inputFile.good()){ //Make sure file is open before trying to work with it
//Begin Working with information
cout << "\tIn File: " << input << endl;
cout << "------------------------------------" << endl;
int number_of_lines = 0;
std::string line;
while (std::getline(inputFile, line)){
++number_of_lines;
}
Time times[number_of_lines];
double math[number_of_lines];
std::string input;
int hh, mm;
for(int loop=0;loop<number_of_lines;loop++){
std::getline(inputFile, input);
std::istringstream(input) >> mm >> hh >> math[loop];
cout << "hours = " << hh << endl;
times[loop].setTimeHours(hh);
times[loop].setTimeMinutes(mm);
times[loop].show();
cout << "*" << math[loop] << endl;
}
std::cout << "Number of lines in text file: " << number_of_lines << "\n" << endl;
}else{
cout << "Could not open file!!!" << endl;
}
The file I'm reading looks like this:
90 1 3.0
1 1 100.0
2 34 5.1
And the output when I run:
In File: data04.txt
------------------------------------
hours = 0
Operation To Be Done = 0:2336552*1.15384e-317
hours = 0
Operation To Be Done = 0:2336552*1.58101e-322
hours = 0
Operation To Be Done = 0:2336552*1.15397e-317
Number of lines in text file: 3
Anyone know why its not storing the values?
There are several key problems in this code
It doesn't check if inputs are successful. You always need to make sure you verify that the input operations worked before you process the data you read. Failing so will cause random data to be processed.
You first read to the end of the stream and then hope that the stream magically restarted. That won't work. Read the stream just once and keep appending to a std::vector<Time> (or similar container). Aside from only traversing the file once, on UNIXes the file size can change while reading.
C++ doesn't have variable sized arrays although some compiler may offer an extension similar to C's variable sized array. In C++ you'd use a std::vector<Time> instead.
First and foremost, your program is wrong. After the while loop ends, there is nothing more to read in the file (unless you seekg() back to the beginning), so the std::getline() call in the for loop body basically does nothing.
A second problem is that concerns are not properly separated.
Here is how I would have implemented this program:
struct line_data
{
Time t;
double x;
};
// This handles reading a single Time value.
std::istream & operator >> (std::istream & is, Time & t)
{
int hh, mm;
if (is >> hh >> mm)
{
// Not happy with the following two lines, too Java-like. :-(
t.setTimeHours(hh);
t.setTimeMinutes(mm);
}
return is;
}
// This handles reading a single line of data.
std::istream & operator >> (std::istream & is, line_data & ld)
{
std::string s;
if (std::getline(is, s))
{
std::istringstream iss(s);
// Ensure errors are propagated from iss to is.
if (!(iss >> ld.t >> ld.x))
is.setstate(std::ios::failbit);
}
return is;
};
// This handles processing a single line of data.
struct line_manip // satisfies concept OutputIterator<line_data>
{
std::back_insert_iterator<std::vector<Time>> ti;
std::back_insert_iterator<std::vector<double>> xi;
line_manip(std::vector<Time> & ts, std::vector<double> & xs)
: ti(std::back_inserter(ts))
, xi(std::back_inserter(xs))
{
}
line_manip & operator = (const line_data & ld)
{
ti = ld.t;
xi = ld.x;
return *this;
}
line_manip & operator * () { return *this; }
line_manip & operator ++ () { return *this; }
line_manip & operator ++ (int) { return *this; }
};
int main()
{
std::ifstream ifs("input.txt");
std::vector<Time> ts;
std::vector<double> xs;
std::copy(std::istream_iterator<line_data>(ifs),
std::istream_iterator<line_data>(),
line_manip(ts, xs));
// ...
}
I have some trouble with reading of a file in C++. I am able to read only integers or only alphabets. But I am not able to read both for example, 10af, ff5a. My procedure is as follows:
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cerr << "You should provide a file name." << std::endl;
return -1;
}
std::ifstream input_file(argv[1]);
if (!input_file) {
std::cerr << "I can't read " << argv[1] << "." << std::endl;
return -1;
}
std::string line;
for (int line_no = 1; std::getline(input_file, line); ++line_no) {
//std::cout << line << std::endl;
-----------
}
return 0;
}
So what I am trying to do is, I am allowing the user to specify the input file he wants to read, and I am using getline to obtain each line. I can use the method of tokens to read only integers or only alphabets. But I am not able to read a mix of both. If my input file is
2 1 89ab
8 2 16ff
What is the best way to read this file?
Thanks a lot in advance for your help!
I'd use a std::stringstream, and use std::hex since 89ab and 16ff look like hex numbers.
Should look like this:
std::string line;
for (int line_no = 1; std::getline(input_file, line); ++line_no)
{
std::stringstream ss(line);
int a, b, c;
ss >> a;
ss >> b;
ss >> std::hex >> c;
}
You will need to #include <sstream>
Using
std::string s;
while (input_file >> s) {
//add s to an array or process s
...
}
you can read inputs of type std::string which could be any combination of digits and alphabets. You don't necessarily need to read input line by line and then try to parse it. >> operator considers both space and newline as delimiters.