StringStream loop fails - c++

I am reading a text file with this format:
grrr,some text,45.4321,54.22134
I just have my double valued stored in a string variable.
Why is it only giving me the first digit of the string?
If I start over with just one while loop and a text file of this new format:
21.34564
it works as it should.
The thing is, sLine has the the same value as the one when I started over. What is different is the three nested for loops that most likely is causing the problem.
Here is the code that gets me what I want:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <sstream>
using namespace std;
int main()
{
string usrFileStr,
fileStr = "test.txt", // declaring an obj string literal
sBuffer,
sLine,
str;
double dValue ;
int lineCount = 1;
int nStart;
istringstream issm;
fstream inFile; // declaring a fstream obj
// cout is the name of the output stream
cout << "Enter a file: ";
cin >> usrFileStr;
inFile.open( usrFileStr.c_str(), ios::in );
// at this point the file is open and we may parse the contents of it
while ( getline ( inFile, sBuffer ) && inFile.eof() )
{
cout << "Original String From File: " << sBuffer << endl;
cout << "Modified Str from File: " << fixed << setprecision(2)
<< dValue << endl;
}
fgetc( stdin );
return 0;
}
So there it works just like it should. But i cant get it to work inside a for loop or when i have multiple feilds in my text file...
With this code, why is it taken off the decimal?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include <errno.h>
using namespace std;
int main()
{
string usrFileStr,
myFileStr = "myFile.txt", // declaring an obj string literal
sBuffer,
sLine = "";
istringstream inStream;
int lineCount = 1;
int nStart;
double dValue = 0,
dValue2 = 0;
float fvalue;
fstream inFile; // declaring a fstream obj
// cout is the name of the output stream
cout << "Enter a file: ";
cin >> usrFileStr;
inFile.open( usrFileStr.c_str(), ios::in );
// at this point the file is open and we may parse the contents of it
if ( !inFile )
{
cout << "Not Correct " << endl;
}
while ( getline ( inFile, sBuffer ) )
{
nStart = -1 ;
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
cout << sBuffer[ x ];
}
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
cout << sBuffer[ x ];
}
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
sLine = sBuffer[ x ];
inStream.clear();
inStream.str( sLine );
if ( inStream >> dValue )
cout << setprecision(1) << dValue;
}
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
sLine = sBuffer[ x ];
inStream.clear();
inStream.str( sLine );
if ( inStream >> dValue2 )
cout << setprecision(1) << dValue2;
}
cout << ") \n";
lineCount++;
}
cout << "There are a Total of: " << lineCount -1 << " line(s) in the file."
<< endl;
inFile.clear(); // clear the file of any errors
inFile.close(); // at this point we are done with the file and may close it
fgetc( stdin );
return 0;
}
I don't have any other characters to loop over in the first code because im just reading a nice little double value.
In my second code, i have many characters to get to before the one that i want. But regardless, it is still isolated from the other characters and it is still in its own varaible. im to sick to realize what the problem is :/ although i think its the for loops.
I have also tried atof but i get a '0' where the decimal should be.
and strtod is hard because i need im not reading data into a const char *cPtr

Your code is a little tough to read. You probably want to think some point about encapsulation and breaking it up into functions.
Additionally, I would try to avoid reading in single characters and use the various functions and methods for reading data in fields - you can read a whole floating point or integer number using the >> stream extractors.
Finally, a useful skill to learn is how to use a debugger. You can step through the code and inspect the values of variables as you go.
That said, it looks like your problem is here:
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
**** sLine = sBuffer[ x ];
inStream.clear();
inStream.str( sLine );
if ( inStream >> dValue2 )
cout << setprecision(1) << dValue2;
On the line marked with "****", you place exactly one character into the variable called "sLine". Having done so, you convert that one character into a double precision variable dValue2 and then output it. It should be obvious why this one character is converted into the first digit of the number you want.

Using instream>>dvalue is certainly the right way to do things. But sometimes what's right isn't always easiest or necessarily best.
We could do something like this:
int
main()
{
string s = "grrr,some text,45.4321,54.22134";
double a,b;
ASSERT_IS( 2, sscanf( s.c_str(), "%*[^,],%*[^,],%lf,%lf", & a, & b ) );
cout << setprecision(8);
SHOW(a);
SHOW(b);
}
Or perhaps something like this, while less efficient, might be easier to understand...
int
main()
{
string s = "grrr,some text,45.4321,54.22134";
vector<string> v;
StringSplit( & v, s, "," );
cout << setprecision(8);
SHOW(v);
SHOW(atof( v[2].c_str()));
SHOW(strtod(v[3].c_str(), (char**)NULL));
}
Assuming:
#define SHOW(X) cout << # X " = " << (X) f << endl
/* A quick & easy way to print out vectors... */
template<class TYPE>
inline ostream & operator<< ( ostream & theOstream,
const vector<TYPE> & theVector )
{
theOstream << "Vector [" << theVector.size() << "] {"
<< (void*)(& theVector) << "}:" << endl;
for ( size_t i = 0; i < theVector.size(); i ++ )
theOstream << " [" << i << "]: \"" << theVector[i] << "\"" << endl;
return theOstream;
}
inline void
StringSplit( vector<string> * theStringVector, /* Altered/returned value */
const string & theString,
const string & theDelimiter )
{
UASSERT( theStringVector, !=, (vector<string> *) NULL );
UASSERT( theDelimiter.size(), >, 0 );
size_t start = 0, end = 0;
while ( end != string::npos )
{
end = theString.find( theDelimiter, start );
// If at end, use length=maxLength. Else use length=end-start.
theStringVector -> push_back( theString.substr( start,
(end == string::npos) ? string::npos : end - start ) );
// If at end, use start=maxSize. Else use start=end+delimiter.
start = ( ( end > (string::npos - theDelimiter.size()) )
? string::npos : end + theDelimiter.size() );
}
}

Two points:
You might want to use sBuffer.find(',')
You set sLine to the last character before ",", is this intended to be so? You only parse single digit numbers correctly this way.

Related

istream not fully recovering what has been put to stringstream

I use the following set-up:
#include <bits/stdc++.h>
using namespace std;
class foo {
public:
void bar( istream &in, int n ) {
vector<tuple<int,int,int,int>> q;
int x,y,a,b;
for ( q.clear(); in >> x >> y >> a >> b; q.push_back(make_tuple(x,y,a,b)) );
assert( n == q.size() );
}
};
int main() {
stringstream ss;
for ( int i= 0; i < 100; ++i )
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
ss.clear(), ss.seekg(0,std::ios::beg);
(new foo())->bar(ss,100);
}
In fact, my code is more complex than this, but the idea is that I put stuff (long long ints to be exact) into a stringstream and call a function, supplying the created stringstream as istream object. The above example works fine, but in my particular case I put, say, 2 mln tuples. And the problem is that the numbers are not fully recovered at the other end, inside the foo (I get less than 2000000 numbers). Can you envision a scenario when this might happen? Can this in >> x >> y >> a >> b somehow end sooner than the input is exhausted?
EDIT: I have used this check:
if ( ss.rdstate() and std::stringstream::badbit ) {
std::cerr << "Problem in putting stuff into stringstream!\n";
assert( false );
}
Somehow, everything was passing this check.
EDIT: As I said, I do a sanity check inside main() by recovering the input-numbers using the >>-method, and indeed get back the 2 mln (tuples of) numbers.
It is just when the stringstream object gets passed to the foo, it recovers only fraction of the numbers, not all of them.
EDIT: For what it's worth, I am pasting the actual context here. Because of its dependencies, it won't compile, but at least we will be able to see the offending lines. It is the run() method that is not being able to recover the queries supplied by the main() method.
#include <iostream>
#include <algorithm>
#include <chrono>
const unsigned long long PERIOD= 0x1full;
class ExpRunnerJSONOutput : public ExperimentRunner {
std::string answers;
void set_name( std::string x ) {
this->answers= "answers."+x+".txt";
}
public:
ExpRunnerJSONOutput( query_processor *p ) : ExperimentRunner(p) {
set_name(p->method_name);
}
ExperimentRunner *setProcessor( query_processor *p) override {
ExperimentRunner::setProcessor(p);
set_name(p->method_name);
return this;
}
// in: the stream of queries
// out: where to write the results to
virtual void run( std::istream &in, std::ostream &out ) override {
node_type x,y;
value_type a,b;
unsigned long long i,j,rep_period= (16383+1)*2-1;
auto n= tree->size();
std::vector<std::tuple<node_type,node_type,value_type,value_type>> queries;
for ( queries.clear(); in >> x >> y >> a >> b; queries.push_back(std::make_tuple(x,y,a,b)) ) ;
value_type *results= new value_type[queries.size()], *ptr= results;
/* results are stored in JSON */
nlohmann::json sel;
long double total_elapsed_time= 0.00;
std::chrono::time_point<std::chrono::high_resolution_clock,std::chrono::nanoseconds> start, finish;
long long int nq= 0, it= 0;
start= std::chrono::high_resolution_clock::now();
int batch= 0;
for ( auto qr: queries ) {
x= std::get<0>(qr), y= std::get<1>(qr);
a= std::get<2>(qr), b= std::get<3>(qr);
auto ans= processor->count(x,y,a,b); nq+= ans, nq-= ans, ++nq, *ptr++= ans;
}
finish = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish-start);
total_elapsed_time= elapsed.count();
sel["avgtime_microsec"]= total_elapsed_time/nq*(1e-3);
out << sel << std::endl;
out.flush();
delete[] results;
}
~ExpRunnerJSONOutput() final {}
};
void runall( std::istream &in, char *res_file, ExpRunnerJSONOutput *er ) {
in.clear(), in.seekg(0,std::ios::beg);
std::string results_file= std::string(res_file);
std::ofstream out;
try {
out.open(results_file,std::ios::app);
}
catch ( std::exception &e ) {
throw e;
}
er->run(in,out), out.close();
}
using instant= std::chrono::time_point<std::chrono::steady_clock,std::chrono::nanoseconds>;
void sanity_check( std::istream &in, size_type nq ) {
node_type x,y;
value_type a,b;
size_type r= 0;
for ( ;in >> x >> y >> a >> b; ++r ) ;
assert( r == nq );
}
int main( int argc, char **argv ) {
if ( argc < 5 ) {
fprintf(stderr,"usage: ./<this_executable_name> <dataset_name> <num_queries> <result_file> K");
fflush(stderr);
return 1;
}
query_processor *processor;
std::string dataset_name= std::string(argv[1]);
auto num_queries= std::strtol(argv[2],nullptr,10);
auto K= std::strtol(argv[4],nullptr,10);
std::ifstream in;
std::ofstream logs;
try {
in.open(dataset_name+".puu");
logs.open(dataset_name+".log");
} catch ( std::exception &e ) {
throw e;
}
std::string s; in >> s;
std::vector<pq_types::value_type> w;
w.clear();
pq_types::value_type maxw= 0;
for ( auto l= 0; l < s.size()/2; ++l ) {
value_type entry;
in >> entry;
w.emplace_back(entry);
maxw= std::max(maxw,entry);
}
in.close();
const rlim_t kStackSize= s.size()*2;
struct rlimit r1{};
int result= getrlimit(RLIMIT_STACK,&r1);
if ( result == 0 ) {
if ( r1.rlim_cur < kStackSize ) {
r1.rlim_cur= kStackSize;
result= setrlimit(RLIMIT_STACK,&r1);
if ( result != 0 ) {
logs << "setrlimit returned result = " << result << std::endl;
assert( false );
}
}
}
logs << "stack limit successfully set" << std::endl;
instant start, finish;
remove(argv[3]);
auto sz= s.size()/2;
random1d_interval_generator<> rig(0,sz-1), wrig(0,maxw);
auto node_queries= rig(num_queries), weight_queries= wrig(num_queries,K);
assert( node_queries.size() == num_queries );
assert( weight_queries.size() == num_queries );
std::stringstream ss;
ss.clear(), ss.seekg(0,std::ios::beg);
for ( int i= 0; i < num_queries; ++i )
ss << node_queries[i].first << " " << node_queries[i].second << " " << weight_queries[i].first << " " << weight_queries[i].second << "\n";
ss.clear(), ss.seekg(0,std::ios::beg);
sanity_check(ss,num_queries);
start = std::chrono::steady_clock::now();
auto *er= new ExpRunnerJSONOutput(processor= new my_processor(s,w,dataset_name));
finish = std::chrono::steady_clock::now();
logit(logs,processor,start,finish);
runall(ss,argv[3],er), delete processor;
logs.close();
return 0;
}
EDIT: I was wondering if this has to do with ifstream.eof() - end of file is reached before the real end
Now, how to confirm the hypothesis -- that reading stops once we reach a byte with value 26?
EDIT: One more update. After reading things inside the foo, the rdstate() returned 4, fail() == 1 and eof() == 0. So, apparently end-of-file has not been reached.
You are not checking the state of your stream. There is an upper limit on how much you can fit in there - basically the max string size. This is discussed in detailed in this question
Check for errors as you write to the stringstream?
stringstream ss;
for (int i = 0; i < 100000000; ++i) //or some other massive number?
{
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
if (ss.rdstate() & stringstream::badbit)
std::cerr << "Problem!\n";
}
You may want to check specific writes of numbers.
Ultimately, I've used good old FILE * instead of istreams, and everything worked as expected. For some reason, the latter was reading only a part of the file (namely, a prefix thereof), and stopping prematurely with a fail() being true.
I have no idea why.

Frequency table in C++

This is what I have so far; I am trying to have an array with probability of all chars and space in a text file, but I have a problem with the data type.
int main()
{
float x[27];
unsigned sum = 0;
struct Count {
unsigned n;
void print(unsigned index, unsigned total) {
char c = (char)index;
if (isprint(c)) cout << "'" << c << "'";
else cout << "'\\" << index << "'";
cout << " occured " << n << "/" << total << " times";
cout << ", propability is " << (double)n / total << "\n";
}
Count() : n() {}
} count[256];
ifstream myfile("C:\\text.txt"); // one \ masks the other
while (!myfile.eof()) {
char c;
myfile.get(c);
if (!myfile) break;
sum++;
count[(unsigned char)c].n++;
}
for (unsigned i = 0; i<256; i++)
{
count[i].print(i, sum);
}
x[0] = count[33];
int j=68;
for(int i=1;i<27;i++)
{
x[i]=count[j];
j++;
}
return 0;
}
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
double probabilities[256]; // now it can be accessed by Count
int main()
{
unsigned sum = 0;
struct Count {
unsigned n;
double prob;
void print ( unsigned index, unsigned total ) {
// if ( ! n ) return;
probabilities[index] = prob = (double)n/total;
char c = (char) index;
if ( isprint(c) ) cout << "'" << c << "'";
else cout << "'\\" << index << "'";
cout<<" seen "<<n<<"/"<<total<<" times, probability is "<<prob<<endl;
}
Count(): n(), prob() {}
operator double() const { return prob; }
operator float() const { return (float)prob; }
} count[256];
ifstream myfile("C:\\text.txt"); // one \ masks the other
while(!myfile.eof()) {
char c;
myfile.get(c);
if ( !myfile ) break;
sum++;
count[(unsigned char)c].n++;
}
for ( unsigned i=0; i<256; i++ ) count[i].print(i,sum);
return 0;
}
I incorporated various changes suggested - Thanks!
Now, who finds the 4 ways to access the actual probabilities?
you are allocating a buffer with size 1000000 1 million characters.
char file[1000000] = "C:\text.txt";
This is not good as the extra values in the buffer are not guaranteed to be zero, the can be anything.
For Windows to read a file you need something like this. I will not give you the solution, you need to learn using msdn and documentation to understand this fully::
you need to include the #include <windows.h> header from the SDK first.
Look at this example here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363778(v=vs.85).aspx
this example as appending a file to another. Your solution will be similar, instead of writing list to other file, process the buffer to increment your local variables and update the state of the table.
Do not set a large number you come up with for the buffer, as there will risk of not enough buffer space, and thus overflow. You should do like example:
read some bytes in buffer
process that buffer and increment the table
repeat until you reach end of file
while (ReadFile(hFile, buff, sizeof(buff), &dwBytesRead, NULL)
&& dwBytesRead > 0)
{
// write you logic here
}

How would I print numbers from a vector onto a file?

//Here is my code thus far
//HERE I SIMPLY TAKE IN A FILE FULL OF NUMBERS, INCLUDING DECIMAL NUMBERS
ifstream infile;
infile.open("Numbers.txt");
if (!infile) {
cout << "Unable to open the file" << endl;
return;
}
//CREATING VECTORS TO STORE THOSE NUMBERS IN
vector<int> iNumbers;
vector<double> dNumbers;
if (infile) {
int i;
double d;
while (infile >> i && infile >> d) {
iNumbers.push_back(i);
dNumbers.push_back(d);
}
infile.close();
}
/*
NOW ATTEMPTING TO PRINT OR PLACE THOSE NUMBERS INTO TWO DIFFERENT FILES PUTTING THE INTEGERS IN integer.txt AND PUTTING THE DOUBLES IN doubles.txt
*/
ofstream integerOut("integer.txt");
vector<int>::iterator ii;
for (ii = iNumbers.begin(); ii != iNumbers.end(); ++ii)
{
if (ii = int {
}
integerOut << *ii << endl;
cout << *ii << endl;
}
integerOut.close();
ofstream doubleOut("double.txt");
vector<double>::iterator dd;
for (dd = dNumbers.begin(); dd != dNumbers.end(); ++dd)
{
doubleOut << *dd << endl;
cout << *dd << endl;
}
doubleOut.close();
}
//MY CODE ONLY GIVES ME THE FIRST TWO NUMBERS FOR MY integer.txt FILE AND THE LAST DECIMALS FOR MY double.txt. WHAT AM I DOING WRONG?
Further explanation:
I have a file named Numbers.txt with numbers containing
1
5
9.4
3
4
6.3
5
2.2
I am taking the integers and trying to place them into the interger.txt file and I am taking the doubles and placing them into the double.txt file. But in my code I am receiving for integers
1
2
9
3
4
6
5
2
when I want to receive
1
5
3
4
5
only
You can use standard algorithm std::copy. For example
#include <iostream>
#include <fstream>
#include <iterator>
#include <algorithm>
//...
std::ofstream integerOut( "integer.txt" );
if ( integerOut )
{
std::copy( iNumbers.begin(), iNumbers.end(),
std::ostream_iterator<int>( integerOut, " " ) );
}
std::ofstream doubleOut( "double.txt" );
if ( doubleOut )
{
std::copy( dNumbers.begin(), dNumbers.end(),
std::ostream_iterator<double>( doubleOut, " " ) );
}
Or you can write a code where you will control the output yourself. For example
#include <iostream>
#include <fstream>
//...
std::ofstream integerOut( "integer.txt" );
for ( int x : iNumbers )
{
if ( !( integerOut << x << ' ' ) ) break;
}
std::ofstream doubleOut( "double.txt" );
for ( double x : dNumbers )
{
if ( !( doubleOut << x << ' ' ) ) break;
}
As for the input then as I have understood two integers are followed by one double in the file. So you need to read numbers accordingly.
int i1, i2;
double d;
bool valid = true;
while ( valid )
{
if ( valid = infile >> i1 ) iNumbers.push_back( i1 );
if ( valid && ( valid = infile >> i2 ) ) iNumbers.push_back( i2 );
if ( valid && ( valid = infile >> d ) ) dNumbers.push_back( d );
}
If you do not know whether the next number in the file is integer or double you can distiguish them by the presence of the period in the number. For example
std::string value;
while ( infile >> value )
{
if ( value.find( '.' ) != std::string::npos )
{
double d = std::stod( value );
dNumbers.push_back( d );
}
else
{
int i = std::stoi( value );
iNumbers.push_back( i );
}
}

C++: Seg Fault on exit of IF statement

I am reposting this with all of the code this time. I would appreciate not closing the post for at least a little while. I am obviously no expert and I have never run into anything like this before but I do think it can be useful to other members. I tried the comments and agree the error is with destruction but can't find where. I have included the location of the seg fault in comment towards the bottom. I don't have an IDE and don't know how to use the debugger surely built into xterm so I am at a loss!!
#include <iostream>
#include <fstream>
#include <string>
#include "File.h"
using namespace std;
string promptQuit()
{
string userMode;
cout
<<
"Would you like to [q]uit? Enter any other key to continue."
<<
endl;
cin >> userMode;
cin.clear();
cin.ignore( 1000,'\n' );
return userMode;
}
int main()
{
/**************************************************************************/
/* Variable Declarations and Initializations */
/**************************************************************************/
char fileName[256];
char destinationFile[256];
string userMode;
/**************************************************************************/
/* Begin prompting user for what they want to do, starting with */
/* the filename, then what they want to do with the file. Once the user */
/* finishes with a particular file, they may continue with another file. */
/* Therefore, this loop terminates only when the user asks to quit */
/**************************************************************************/
while( userMode != "q" )
{
cout
<<
"Welcome to the file handling system. Please type the name of the "
"file that you wish to read from, write to, or modify followed by "
"the <return> key:"
<<
endl;
cin.getline( fileName, 256 );
File thisFile( fileName );
cout
<<
"Current File: " << thisFile.getFileName() << "\nWhat would you "
"like to do?\n[r]ead, [w]rite, [m]odify, or [q]uit"
<<
endl;
cin >> userMode;
// Invalid entry handling: Reset the failure bit and skip past the
// invalid input in the stream, then notify and re-prompt the user for
// valid input
while( !( (userMode == "w") | (userMode == "r") | (userMode == "q") |
(userMode == "m" ) ) )
{
cout
<<
"Invalid entry, please try again\nWhat would you like to do?\n"
"[r]ead, [w]rite, [m]odify, or [q]uit"
<<
endl;
cin >> userMode;
cin.clear();
cin.ignore( 1000, '\n' );
}
/*********************************************************************/
/* Write Mode: The user is prompted to enter one number at a time */
/* and this number is written to the chosen file. If the user enters*/
/* an invalid number, such as a letter, the user is notified and */
/* prompted to enter a valid real number */
/*********************************************************************/
if( userMode == "w" )
thisFile.writeTo();
/*********************************************************************/
/* Read Mode: The user reads in the entire contents from the file */
/* they have chosen */
/*********************************************************************/
if( userMode == "r" )
thisFile.readFrom();
/*********************************************************************/
/* Modify Mode: The user may either leave the old file unmodified and*/
/* place the modified contents into a new file or actually modify the*/
/* original file. */
/* The user reads in one line from the file at a time and can either */
/* choose to accept this number, replace it, delete it, or accept it */
/* and insert one or more numbers after it. At any time the user may*/
/* also choose to accept the remainder of the numbers in the file */
/*********************************************************************/
if( userMode == "m" )
{
cout
<<
"Do you want to modify the original file?\n[y]es/[n]o?"
<<
endl;
string modify;
cin >> modify;
while( !( ( modify == "y" ) | ( modify == "n" ) ) )
{
cout
<<
"Invalid entry, please try again\nDo you want to modify "
"the original file?\n[y]es/[n]o?"
<<
endl;
cin >> userMode;
cin.clear();
cin.ignore( 1000, '\n' );
}
if( modify == "y" )
{
File tempFile;
thisFile.modify( &tempFile );
}
if( modify == "n" )
{
cout
<<
"Please type the name of the destination file followed by "
"the <return> key:"
<<
endl;
cin.getline( destinationFile, 256 );
File newFile( destinationFile );
thisFile.modify( &newFile );
/****************************************************************/
/****Seg fault occurs here. Never exits this IF but above*******/
/*function does return.Doesn't get past close curly brace********/
/****************************************************************/
}
}
userMode = promptQuit();
}
return 0;
}
Here is the .cpp file
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <math.h>
#include <iomanip>
#include "File.h"
using namespace std;
// Returns ordinal number from input integer num, e.g., 1st for 1
string ordinalString( const int num )
{
stringstream numeric;
numeric << num;
string ordinalUnit;
string ordinal = numeric.str();
switch( num%10 )
{
case 1: ordinalUnit = "st"; break;
case 2: ordinalUnit = "nd"; break;
case 3: ordinalUnit = "rd"; break;
default: ordinalUnit = "th"; break;
}
switch( num )
{
case 11: ordinalUnit = "th"; break;
case 12: ordinalUnit = "th"; break;
case 13: ordinalUnit = "th"; break;
}
ordinal += ordinalUnit;
return ordinal;
}
float promptRealNumber()
{
float validEntry;
// Invalid entry handling: Reset the failure bit and skip past the
// invalid input in the stream, then notify and re-prompt the user for
// valid input
while ( !(cin >> validEntry) )
{
cout << "Invalid Input: Entry must be a real number. Please try again:";
cin.clear();
cin.ignore( 1000, '\n' );
}
return validEntry;
}
File::File()
{
fileName = "temp.txt";
entries = 0;
}
File::File( const char * file_name )
{
entries = 0;
string currentLine;
fileName = file_name;
ifstream thisFile( file_name );
if ( thisFile.is_open() )
{
while ( !thisFile.eof() )
{
getline ( thisFile, currentLine );
entries++;
}
thisFile.close();
}
else
cout << "Error opening file. File may not exist." << endl;
entries--;
}
File::File( const File * copyFile )
{
fileName = copyFile->fileName;
entries = copyFile->entries;
}
void File::promptNumEntries()
{
cout
<<
"Please enter the number of entries you wish to input into "
<< fileName << " followed by the '<return>' key"
<<
endl;
// Invalid entry handling: Reset the failure bit and skip past the invalid
// input in the stream, then notify and re-prompt the user for valid input
while ( !(cin >> entries) || ( floor( entries ) != entries ) )
{
cout << "Invalid Input: Entry must be an integer. Please try again: ";
cin.clear();
cin.ignore ( 1000, '\n' );
}
}
void File::readFrom()
{
string currentLine;
ifstream inFile( fileName.c_str() );
if ( inFile.is_open() )
{
while ( inFile.good() )
{
getline ( inFile, currentLine );
cout << currentLine << endl;
}
inFile.close();
}
else
cout << "Error opening file. File may not exist." << endl;
}
void File::writeTo()
{
ofstream outFile( fileName.c_str() );
string ending;
promptNumEntries();
for( int entry = 1; entry <= entries; entry++ )
{
// Notify the user which entry they are currently entering so if they lose
// their place, they can easily find which number they should be entering.
cout
<<
"Please enter the " << ordinalString( entry ) << " number followed "
"by the <return> key"
<<
endl;
float entryNum = promptRealNumber();
outFile << fixed << setprecision(1) << entryNum << endl;
}
outFile.close();
}
void File::modify( const File * destination_file )
{
ifstream sourceFile( fileName.c_str() );
ofstream destinationFile( destination_file->fileName.c_str() );
string currentLine;
string entryAction;
string insertMore = "y";
float replacementEntry;
float insertEntry;
int entry = 0;
if ( sourceFile.is_open() )
{
while ( !sourceFile.eof() )
{
getline( sourceFile, currentLine );
cout
<<
currentLine << endl << "Do you want to [k]eep this entry, "
"[r]eplace it, [d]elete it, [i]nsert after it, or accept this "
"and [a]ll remaining entries?"
<<
endl;
cin >> entryAction;
// Keep current entry. Also called when inserting an entry since
// this also requires keeping the current entry
if( ( entryAction == "k" ) | ( entryAction == "i" ) )
destinationFile << currentLine << endl;
// Replace current entry
if( entryAction == "r" )
{
cout
<<
"Please type the new entry followed by the <return> key:"
<<
endl;
replacementEntry = promptRealNumber();
destinationFile
<<
fixed << setprecision(1) << replacementEntry
<<
endl;
}
// Deleting the current entry amounts to simply ignoring it and
// continuing to the next entry, if it exists
if( entryAction == "d" );
// Insert one or more entries after current entry
if( entryAction == "i" )
{
while( insertMore == "y" )
{
cout
<<
"Please type the entry to be inserted followed by the "
"<return> key:"
<<
endl;
insertEntry = promptRealNumber();
destinationFile
<<
fixed << setprecision(1) << insertEntry
<<
endl;
cout << "Insert another number?\n[y]es/[n]o?" << endl;
cin >> insertMore;
while( !( (insertMore == "y") | (insertMore == "n" ) ) )
{
cout
<<
"Invalid entry, please try again\nInsert another "
"number?\n[y]es/[n]o?"
<<
endl;
cin >> insertMore;
cin.clear();
cin.ignore( 1000, '\n' );
}
}
}
// Accept all remaining entries
if( entryAction == "a" )
{
destinationFile << currentLine << endl;
while ( entry < entries )
{
getline ( sourceFile, currentLine );
destinationFile << currentLine << endl;
entry++;
}
}
destinationFile.close();
sourceFile.close();
}
}
else
cout << "Error opening file. File may not exist." << endl;
}
void File::copyFileContents( const File * to, const File * from )
{
ifstream fromFile( to->fileName.c_str() );
ofstream toFile( from->fileName.c_str() );
string currentLine;
while( !fromFile.fail() && !toFile.fail() )
{
for( int line = 0; line < from->entries; line++ )
{
getline( fromFile, currentLine );
toFile << currentLine;
}
}
}
Here is the .h file
#include <string>
using namespace std;
class File
{
public:
File();
File( const char * );
File( const File * copyFile );
~File() { delete this; }
string getFileName() { return fileName; }
float numEntries() { return entries; }
void setNumEntries( const float numEntries ) { entries = numEntries; }
void promptNumEntries();
void readFrom();
void writeTo();
void modify( const File * );
void copyFileContents( const File * , const File * );
private:
string fileName;
float entries;
};
I tried commenting out the sourceFile.close() statement and still nothing. I know its a lot of code but whoever can help would be my hero of the century!!
Remove delete(this) from the destructor!
You aren't constructing a File with new (since you're using a static instance on the stack), but the destructor is called anyway. So the delete statement is invalid and probably causes the segfault.
I've once seen a SEG fault on an if statement and the cause of it (after many hours of misery) turned out to be because I was accessing a private data member of the object, but that I had already started to destroy the object.
My guess is that it might be this line as that looks to me that you are destroying a resource that you are still using.:
sourceFile.close();
Try commenting that out and see how it goes.

prefix to infix on stack

I'm trying to implement prefix to infix in c++, that's what i've got so far. The input should be for example something like this:
/7+23
And the ouput:
7/(2+3) or (7/(2+3))
But instead I get:
(/)
That's the code I wrote so far:
void pre_to_in(stack<char> eq) {
if(nowe.empty() != true) {
char test;
test = eq.top();
eq.pop();
if(test == '+' || test == '-' || test == '/' || test == '*') {
cout << "(";
pre_to_in(eq);
cout << test;
pre_to_in(eq);
cout << ")";
} else {
cout << test;
}
}
}
// somewhere in main()
char arr[30];
stack<char> stosik;
int i = 0;
cout << "write formula in prefix notation\n";
cin >> arr;
while(i < strlen(arr)) {
stosik.push(arr[i]);
i++;
}
pre_to_in(stc);
This is a stack. First in, last out. You need reverse input string "32+7/".
You use many stacks. In every enter to pre_to_in() stack is copied. Use reference or pointer, ex: void pre_to_in(stack<char> &eq);
Thats all.
P.S. Unify names (s/nowe/eq/g && s/stc/stosik/g)
cin >> arr;
only reads one "word" of input, not a whole line. Here it's only getting the first slash character.
not sure if you are looking for such solution, anyway for the input you've mentioned it gives the output from you post
it reads tokens from std input
I've built it now under Visual Studio 2005 - to terminate input press Enter, Ctrl+Z, Enter
but on other compilers termination may work in another way
#include <algorithm>
#include <deque>
#include <iostream>
#include <string>
typedef std::deque< std::string > tokens_t;
void pre_to_in( tokens_t* eq )
{
if ( !eq->empty() ) {
const std::string token = eq->front();
eq->pop_front();
if ( ( token == "+" ) || ( token == "-" ) || ( token == "/" ) || ( token == "*" ) ) {
std::cout << "(";
pre_to_in( eq );
std::cout << token;
pre_to_in( eq );
std::cout << ")";
} else {
std::cout << token;
}
}
}
int main()
{
std::cout << "write formula in prefix notation" << std::endl;
tokens_t tokens;
std::copy(
std::istream_iterator< std::string >( std::cin ),
std::istream_iterator< std::string >(),
std::back_inserter( tokens ) );
pre_to_in( &tokens );
}