help me understand this cin/fstream behavior

D

Danny Anderson

Hola-
I didn't get any responses on a previous post, so I am trying to reword my
problem and post compile-able code that exhibits the behavior I am
describing.

On the second iteration of the loop below, the file opened is the default
(which in this case is ".csv", which makes a 'hidden' file for Linux
folk). The step that prompts for a file name step is skipped completely.
Why? Is this a cin issue or does it have something to do with the
filestream?

As always, comments and suggestions appreciated, Danny

//---start code
#include <iostream>
#include <string>
#include <vector>
#include <fstream>


using namespace std;


//---function prototypes

void pause(string s);
bool user_is_not_finished();
string get_filename(string filetype);



int main()
{

string foo;
ofstream dataOut;


do
{
//---open report file for writing
dataOut.open(get_filename("report").c_str()); if(!dataOut)
{cout << "ERROR: couldn't open output file..."; return 1;}
else
{cout << "ready to start...\n" << endl;}

//---get information for report
cout << "Enter some text: ";
getline(cin, foo);
dataOut << foo << endl;
dataOut.close();

}while(user_is_not_finished() );

pause("end of program...");
return 0;
}
}
//---function definitions


void pause(string s)
{
char c;
cout << endl << s << "...enter a key to continue: "; cin >> c;
}
}

bool user_is_not_finished()
{
char user_choice;
bool is_not_finished;

cout << endl <<"[Q]uit program or enter another [r]eport? "; cin >>
user_choice;

while(user_choice!='Q'&& user_choice!='q'&& user_choice!='r'&&
user_choice!='R')
{
//---keep prompting until a valid answer is encountered cout <<
"[Q]uit program or enter another [r]eport? "; cin >> user_choice;
}
if(user_choice=='r'|| user_choice=='R')
{
is_not_finished=true;
}
else
{
is_not_finished=false;
}
}
return is_not_finished;
}
}

/* get_filename(string filetype)
* purpose: get the name of the file to be opened *
* input: a string that is either "report" or "material list". other
strings * can be valid as long as they are defined in the function body
* output: a string that can be sent to the a fstream.open command (after
* being converted to a c_str
*/

string get_filename(string filetype)
{
string filename;
string dummy;

if(filetype=="report")
{
cout << "Output file? [bldg_report] ";

getline(cin, filename);
// if(filename.empty())
// {filename="bldg_report.csv";}
//else
{filename+=".csv";}
}
else if(filetype=="material list")
{
cout << "Material List Filename? [dfi_master_mtl.txt] ";
getline(cin, filename);
if(filename.empty())
{filename="dfi_master_mtl.txt";}


}
return filename;
}
 
A

Alf P. Steinbach

Hola-
I didn't get any responses on a previous post, so I am trying to reword my
problem and post compile-able code that exhibits the behavior I am
describing.

On the second iteration of the loop below, the file opened is the default
(which in this case is ".csv", which makes a 'hidden' file for Linux
folk). The step that prompts for a file name step is skipped completely.
Why? Is this a cin issue or does it have something to do with the
filestream?

As always, comments and suggestions appreciated, Danny

//---start code
#include <iostream>
#include <string>
#include <vector>
#include <fstream>


using namespace std;


//---function prototypes

void pause(string s);
bool user_is_not_finished();
string get_filename(string filetype);



int main()
{

string foo;
ofstream dataOut;


do
{
//---open report file for writing
dataOut.open(get_filename("report").c_str()); if(!dataOut)
{cout << "ERROR: couldn't open output file..."; return 1;}
else
{cout << "ready to start...\n" << endl;}

Suggest formatting this more readable.

Place 'if' at the start of separate line.


//---get information for report
cout << "Enter some text: ";
getline(cin, foo);
dataOut << foo << endl;
dataOut.close();

}while(user_is_not_finished() );

pause("end of program...");
return 0;
}
}

What's that second brace? This might be the problem.


//---function definitions


void pause(string s)
{
char c;
cout << endl << s << "...enter a key to continue: "; cin >> c;
}
}


What's that second brace? This might be the problem.


bool user_is_not_finished()
{
char user_choice;
bool is_not_finished;

cout << endl <<"[Q]uit program or enter another [r]eport? "; cin >>
user_choice;

while(user_choice!='Q'&& user_choice!='q'&& user_choice!='r'&&
user_choice!='R')
{
//---keep prompting until a valid answer is encountered cout <<
"[Q]uit program or enter another [r]eport? "; cin >> user_choice;
}
if(user_choice=='r'|| user_choice=='R')
{
is_not_finished=true;
}
else
{
is_not_finished=false;
}
}

What's that second brace? This might be the problem.


return is_not_finished;
}
}


What's that second brace? This might be the problem.

/* get_filename(string filetype)
* purpose: get the name of the file to be opened *
* input: a string that is either "report" or "material list". other
strings * can be valid as long as they are defined in the function body
* output: a string that can be sent to the a fstream.open command (after
* being converted to a c_str
*/

string get_filename(string filetype)
{
string filename;
string dummy;

if(filetype=="report")
{
cout << "Output file? [bldg_report] ";

getline(cin, filename);
// if(filename.empty())
// {filename="bldg_report.csv";}
//else
{filename+=".csv";}
}
else if(filetype=="material list")
{
cout << "Material List Filename? [dfi_master_mtl.txt] ";
getline(cin, filename);
if(filename.empty())
{filename="dfi_master_mtl.txt";}


}
return filename;
}
 
M

Mike Wahler

Danny Anderson said:
Hola-
I didn't get any responses on a previous post, so I am trying to reword my
problem and post compile-able code that exhibits the behavior I am
describing.

On the second iteration of the loop below, the file opened is the default
(which in this case is ".csv", which makes a 'hidden' file for Linux
folk). The step that prompts for a file name step is skipped completely.
Why? Is this a cin issue or does it have something to do with the
filestream?

As always, comments and suggestions appreciated, Danny

//---start code
#include <iostream>
#include <string>
#include <vector>
#include <fstream>


using namespace std;


//---function prototypes

void pause(string s);
bool user_is_not_finished();
string get_filename(string filetype);



int main()
{

string foo;
ofstream dataOut;


do
{
//---open report file for writing
dataOut.open(get_filename("report").c_str()); if(!dataOut)
{cout << "ERROR: couldn't open output file..."; return 1;}
else
{cout << "ready to start...\n" << endl;}

//---get information for report
cout << "Enter some text: ";
getline(cin, foo);
dataOut << foo << endl;
dataOut.close();

}while(user_is_not_finished() );

pause("end of program...");
return 0;
}
}
//---function definitions


void pause(string s)
{
char c;
cout << endl << s << "...enter a key to continue: "; cin >> c;
}
}

bool user_is_not_finished()
{
char user_choice;
bool is_not_finished;

cout << endl <<"[Q]uit program or enter another [r]eport? "; cin >>
user_choice;

while(user_choice!='Q'&& user_choice!='q'&& user_choice!='r'&&
user_choice!='R')
{
//---keep prompting until a valid answer is encountered cout <<
"[Q]uit program or enter another [r]eport? "; cin >> user_choice;
}
if(user_choice=='r'|| user_choice=='R')
{
is_not_finished=true;
}
else
{
is_not_finished=false;
}
}
return is_not_finished;
}
}

/* get_filename(string filetype)
* purpose: get the name of the file to be opened *
* input: a string that is either "report" or "material list". other
strings * can be valid as long as they are defined in the function body
* output: a string that can be sent to the a fstream.open command (after
* being converted to a c_str
*/

string get_filename(string filetype)
{
string filename;
string dummy;

if(filetype=="report")
{
cout << "Output file? [bldg_report] ";

getline(cin, filename);
// if(filename.empty())
// {filename="bldg_report.csv";}
//else
{filename+=".csv";}
}
else if(filetype=="material list")
{
cout << "Material List Filename? [dfi_master_mtl.txt] ";
getline(cin, filename);
if(filename.empty())
{filename="dfi_master_mtl.txt";}


}
return filename;
}

You have other issues to address first:

f:\danny.cpp(45) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(45) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(45) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(50) : error C2143: syntax error : missing ';' before '{'
f:\danny.cpp(50) : error C2447: missing function header (old-style formal
list?)
f:\danny.cpp(54) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(54) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(54) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(57) : error C2143: syntax error : missing ';' before '{'
f:\danny.cpp(57) : error C2447: missing function header (old-style formal
list?)
f:\danny.cpp(79) : error C2143: syntax error : missing ';' before 'return'
f:\danny.cpp(80) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(80) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(80) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(81) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(81) : error C2143: syntax error : missing ';' before '}'
f:\danny.cpp(92) : error C2143: syntax error : missing ';' before '{'
f:\danny.cpp(92) : error C2447: missing function header (old-style formal
list?)
Error executing cl.exe.

swaptest.exe - 18 error(s), 0 warning(s)
 
D

Danny Anderson

I must not have done a very good job on the cut and paste the first
go-round. My apologies. This is the exact example code that I compiled
on my machine- I promise! :)

//example for usenet
#include <iostream>
#include <string>
#include <vector>
#include <fstream>


using namespace std;


//---function prototypes

void pause(string s);
bool user_is_not_finished();
string get_filename(string filetype);



int main()
{

string foo;
ofstream dataOut;


do
{
//---open report file for writing
dataOut.open(get_filename("report").c_str());
if(!dataOut)
{cout << "ERROR: couldn't open output file..."; return 1;}
else
{cout << "ready to start...\n" << endl;}

//---get information for report
cout << "Enter some text: ";
getline(cin, foo);
dataOut << foo << endl;
dataOut.close();

}while(user_is_not_finished() );

pause("end of program...");
return 0;
}

//---function definitions


void pause(string s)
{
char c;
cout << endl << s << "...enter a key to continue: ";
cin >> c;
}


bool user_is_not_finished()
{
char user_choice;
bool is_not_finished;

cout << endl <<"[Q]uit program or enter another [r]eport? ";
cin >> user_choice;

while(user_choice!='Q'&& user_choice!='q'&& user_choice!='r'&& user_choice!='R')
{
//---keep prompting until a valid answer is encountered
cout << "[Q]uit program or enter another [r]eport? ";
cin >> user_choice;
}
if(user_choice=='r'|| user_choice=='R')
{
is_not_finished=true;
}
else
{
is_not_finished=false;
}

return is_not_finished;
}



string get_filename(string filetype)
{
string filename;
string dummy;

if(filetype=="report")
{
cout << "Output file? [bldg_report] ";

getline(cin, filename);
// if(filename.empty())
// {filename="bldg_report.csv";}
//else
{filename+=".csv";}
}
else if(filetype=="material list")
{
cout << "Material List Filename? [dfi_master_mtl.txt] ";
getline(cin, filename);
if(filename.empty())
{filename="dfi_master_mtl.txt";}

}

return filename;
}
 
A

Alf P. Steinbach

I must not have done a very good job on the cut and paste the first
go-round. My apologies. This is the exact example code that I compiled
on my machine- I promise! :)

Goodie.

OK, the program is performing exactly as you describe, and also exactly
as it should according to the Holy Standard.

It isn't performing as you expect, sort of "skipping" one input operation,
because you have the equivalent of the following:


#include <iostream>
#include <string>

int main()
{
char c;
std::string s;

std::cout << "A char, please: " << std::flush;
std::cin >> c;

std::cout << "A line, please: " << std::flush;
std::getline( std::cin, s );

std::cout << "Finished!" << std::endl;
}


When the first read operation is finished there is a 'newline' character,
the one marked the end of the first line, left in the buffer.

The second read operation interprets this as an empty line entered by the
user.

What you need to do to get the behavior you have so far expected is to
clear the read buffer, e.g. by using a skip operation or readline.
 
M

Martin Eisenberg

Danny Anderson wrote:

[code snipped]

Hi,

I've played around with your code a bit. Any comments are
appreciated.

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <cassert>

using namespace std;


//---function prototypes

// void pause(string s);
/* I chose a more descriptive name. Also, the
message is not related to the pausing as such.
*/

void wait_for_user();

// bool user_is_not_finished();
/* Function names containing "not" eventually
lead to confusing double negations. Turn the
condition around or formulate it positively.
Besides, returning the two-valued bool doesn't
accomodate extension.
*/

typedef enum { dReport, dMaterialList, dQuit } UserDesire;

UserDesire get_user_desire();

// string get_filename(string filetype);
/* Identifying the file types by strings
is imho not appropriate in this program.
It might be in some situations where the
wanted type is specified by an entity
outside your code, or where the available
file types are runtime-configurable.
*/

string get_output_filename(UserDesire desire);


//---

int main()
{
string out_text;
ofstream out_file;
UserDesire desire = get_user_desire();

while(desire != dQuit) {
out_file.open(get_output_filename(desire).c_str(), ios::app);
if(!out_file) {

// Note the "cerr".

cerr << "ERROR: couldn't open output file...\n";
return 1;
}

cout << "Enter some text: ";
getline(cin, out_text);
out_file << out_text << endl;

out_file.close();
desire = get_user_desire();
}

cout << "end of program...";
wait_for_user();
return 0;
}


//---function definitions

void wait_for_user()
{
string foo;
cout << "\n ...hit <Enter> to continue.";
getline(cin, foo);
}


UserDesire get_user_desire()
{
string user_choice;

// The loop terminates upon valid input.

while(true) {
cout << "Add to [r]eport, add to [m]aterial list, [q]uit? ";
getline(cin, user_choice);
if(!user_choice.empty()) {
switch(tolower(user_choice[0])) {
case 'r' : return dReport;
case 'm' : return dMaterialList;
case 'q' : return dQuit;
}
}
}
}


string get_output_filename(UserDesire desire)
{
assert(desire != dQuit);

static const string DEFAULT_REPORT_FILE
(
// "bldg_report"
""
);
static const string DEFAULT_MATERIAL_FILE("dfi_master_mtl.txt");

string filename;

switch(desire) {
case dReport :
cout << "Report file? [" << DEFAULT_REPORT_FILE << "] ";
getline(cin, filename);
if(filename.empty())
{ filename = DEFAULT_REPORT_FILE; }

filename += ".csv";
break;

case dMaterialList :
cout << "Material List Filename? ["
<< DEFAULT_MATERIAL_FILE << "] ";
getline(cin, filename);
if(filename.empty())
{ filename = DEFAULT_MATERIAL_FILE; }
break;

default :

// If we get here, this function is incomplete.

assert(false);
}

return filename;
}


//---end of file
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,836
Messages
2,569,750
Members
45,545
Latest member
rapter____0

Latest Threads

Top