Why does my simple while loop printf 2x?

Discussion in 'C Programming' started by DFS, May 15, 2014.

  1. DFS

    Geoff Guest

    At this time I see none. The behavior meets the requirements.
     
    Geoff, May 26, 2014
    1. Advertisements

  2. DFS

    Stefan Ram Guest

    The documentation comment was:

    |//============================================================================
    |// Get user's yes/no answer from console input.
    |// Argument: "y" or "n" indicating the default answer expected.
    |// Blank reply means accept default answer.
    |//============================================================================

    It says: »Get user's yes/no answer«.
    Erroneous input is no »yes/no answer«.

    Also, it seems that the meaning of the bool result
    (true/false) is not given in the documentation comment at
    all. This would mean that the user of the library cannot not
    learn what a result of »true« or »false«, respectively,
    means.

    Outside of the documentation comment you then wrote:

    |This function receives an argument string, either "y" or "n"
    |depending on what you expect to be default and returns
    |accordingly.

    We could decide to take that as a part of the documentation,
    but »returns accordingly« is a little bit vague.
     
    Stefan Ram, May 26, 2014
    1. Advertisements

  3. DFS

    Geoff Guest

    //
    //============================================================================
    // Get user's yes/no answer from console input.
    // Argument: "y" or "n" indicating the default answer expected.
    // Blank reply means accept default answer.
    // Return: true only if "Y" or "y" or if '\n' received and
    // argument is "y" else return false.
    //============================================================================
    //

    Better?
     
    Geoff, May 26, 2014
  4. DFS

    James Kuyper Guest

    Your function treats an invalid answer the same as a valid answer of "N"
    or "n", which is also the same way it treats a default answer of "n"
    that is confirmed. Your documentation should reflect that fact:

    // Check for a yes answer from console input.
    // Argument: "y" or "n" indicating default answer expected.
    // Blank reply means accept default answer.
    // Return: true only if "Y" or "y" is received or if a default
    // answer of "y" is accepted. Otherwise, return false.
     
    James Kuyper, May 26, 2014
  5. I think you really need to consider this question.
    Yes, I understood your intent. Unfortunately I've run out of
    explanations so I simply offer you a test program that provides fake
    input to both functions and shows the results:

    #include <iostream>
    #include <iomanip>
    #include <algorithm>

    const char *answer;

    void getline(std::istream &is, std::string &line)
    {
    line = answer;
    }

    bool GetYesNo (std::string yn)
    {
    std::string str;

    getline(std::cin, str);
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    std::transform( yn.begin(), yn.end(), yn.begin(), ::tolower);

    // if expecting y and get blank or y, return true
    if ((yn.compare(0, 1, "y") == 0 && str.compare(0, 1, "") == 0) ||
    str.compare(0, 1, "y") == 0)
    return true;

    // if expecting n and get n or blank, return false
    if ((yn.compare(0, 1, "n") == 0 && str.compare(0, 1, "") == 0) ||
    str.compare(0, 1, "n") == 0)
    return false;
    else
    return false;
    }

    bool BensYesNo (std::string yn)
    {
    std::string str;

    getline(std::cin, str);
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    std::transform( yn.begin(), yn.end(), yn.begin(), ::tolower);

    return str.compare(0, 1, "") == 0 && yn.compare(0, 1, "y") == 0 ||
    str.compare(0, 1, "y") == 0;
    }

    int main()
    {
    const char *alist[] = { "yes", "no", "other", "" };
    std::cout << " default answer results\n";
    for (auto deflt : alist)
    for (auto a : alist) {
    answer = a;
    std::cout << std::setw(9) << deflt << std::setw(9) << answer
    << " " << GetYesNo(deflt)
    << " " << BensYesNo(deflt) << "\n";
    }
    return 0;
    }

    The output is:

    default answer results
    yes yes 1 1
    yes no 0 0
    yes other 0 0
    yes 1 1
    no yes 1 1
    no no 0 0
    no other 0 0
    no 0 0
    other yes 1 1
    other no 0 0
    other other 0 0
    other 0 0
    yes 1 1
    no 0 0
    other 0 0
    0 0

    In every case, the two functions agree. (I've included some unusual
    default strings, but that's because the test code is simpler that way.)
    That may be, but I can't yet see what's missing. Can you give an example?
     
    Ben Bacarisse, May 26, 2014
  6. DFS

    Tim Rentsch Guest

    This idea can be turned to advantage by adding a parameter to the
    function to allow a caller to give a prefix string before the
    first iteration, thusly -

    static int skip_to_EOL( int c );

    int
    confirmation( const char *start_text ){
    printf( "%sEnter Y or N (not case-sensitive): ", start_text );
    fflush( stdout );

    int first = toupper( getchar() ), last = skip_to_EOL( first );

    return first == 'N' || first == 'Y' ? first
    : last == EOF ? last
    : confirmation( "The first character must be Y or N.\n" );
    }

    int
    skip_to_EOL( int c ){
    return c == EOF || c == '\n' ? c : skip_to_EOL( getchar() );
    }

    This version also returns EOF if/when EOF is reached in the input
    stream (rather than looping infinitely).
     
    Tim Rentsch, Jun 10, 2014
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.