help me understand this cin/fstream behavior

Discussion in 'C++' started by Danny Anderson, Jan 24, 2004.

  1. 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;
    }
     
    Danny Anderson, Jan 24, 2004
    #1
    1. Advertising

  2. On Fri, 23 Jan 2004 19:57:21 -0500, "Danny Anderson" <> wrote:

    >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;
    >}
     
    Alf P. Steinbach, Jan 24, 2004
    #2
    1. Advertising

  3. Danny Anderson

    Mike Wahler Guest

    "Danny Anderson" <> wrote in message
    news:p...
    > 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)
     
    Mike Wahler, Jan 24, 2004
    #3
  4. 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;
    }
     
    Danny Anderson, Jan 24, 2004
    #4
  5. On Sat, 24 Jan 2004 08:03:39 -0500, "Danny Anderson" <> wrote:

    >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.
     
    Alf P. Steinbach, Jan 24, 2004
    #5
  6. 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
     
    Martin Eisenberg, Jan 26, 2004
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. TaiwanNoWhere

    cin and cin.clear() problem

    TaiwanNoWhere, Oct 13, 2003, in forum: C++
    Replies:
    8
    Views:
    4,109
    P.J. Plauger
    Oct 17, 2003
  2. Chris Mantoulidis

    std::cin.ignore() and std::cin.clear()

    Chris Mantoulidis, Jan 6, 2004, in forum: C++
    Replies:
    5
    Views:
    17,178
    Kevin Saff
    Jan 6, 2004
  3. Armando
    Replies:
    6
    Views:
    749
    Armando
    Jan 29, 2004
  4. Aleander

    cin and cin.getline()

    Aleander, Mar 6, 2005, in forum: C++
    Replies:
    5
    Views:
    8,705
    Alex Vinokur
    Mar 6, 2005
  5. Fernando
    Replies:
    4
    Views:
    1,687
    Fernando
    Nov 16, 2011
Loading...

Share This Page