Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Having issues with the cin.getline() function in C++

Having issues with the cin.getline() function in C++

Scheduled Pinned Locked Moved C / C++ / MFC
helpc++
10 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Member_14767000
    wrote on last edited by
    #1

    for a short test in my class, we had to write code about pigs that allowed the user to enter information about a set of pigs (e.g. the pigs' names, breed, weight, gender, etc.). We were to create a class called pigs that would be able to hold the pigs' information. There was nothing wrong with the class itself, the problem I'm having is actually in the main function.

    cout << "Enter the pig gender (\\'m\\'/\\'f\\')(if not press \\'enter\\' for none): ";
    cin.getline(pigGender, 10);
    if(pigGender != "\\n")
    {
        while(pigGender != "m" && pigGender != "f")
        {
            cout << "Invalid gender, please enter a valid gender m or f(if not press \\'Enter\\'): ";
            cin.getline(pigGender, 10);
            if(pigGender != "\\n")
            {
                //cout << "if branch, pigGender:" << pigGender; 
                gender = pigGender\[0\];
            }
            else
            {
                //cout << "else branch, pigGender:" << pigGender;
                gender = ' ';
                break;
            }
        }
        pigs\[i\].SetPigGender(gender);
    }
    

    The piece of code above, shows how I'm trying to obtain the pig's gender from the user. I made it so that if the user doesn't know the gender, they can just hit enter to move on (as I did with other features that worked fine). The problem is that when you hit enter, the pigGender string doesn't seem to take the newline character. Also, I understand how the getline function works (takes in a newline and stops), hence I believe when you hit enter, the getline will take in the newline and stop, but here it does not seem to take it in at all. I also made it so that if the user enters a wrong letter (not m or f), then they can still hit enter if they do not know. The commented out codes are checks I implemented to see exactly what was in pigGender. When I enter a charcter that is not a newline it will go to the if branch and dislpay my error message, however, when I hit only enter, it still goes through that if branch instead of the else branch. the checks i commented out show me which branch I am in and the charcter in the pigGender string, and when I hit enter for the newline, there seems to be nothing in the pigGender string. What seems even more bizarre, is that the following code is very similar to what I did above (I actually copied and pasted it and made some changes to make the one above) and it works perfectly.

    cout << "Enter the pig weight(if not press \\'Enter\\'): ";
    cin.getline
    
    K S 2 Replies Last reply
    0
    • M Member_14767000

      for a short test in my class, we had to write code about pigs that allowed the user to enter information about a set of pigs (e.g. the pigs' names, breed, weight, gender, etc.). We were to create a class called pigs that would be able to hold the pigs' information. There was nothing wrong with the class itself, the problem I'm having is actually in the main function.

      cout << "Enter the pig gender (\\'m\\'/\\'f\\')(if not press \\'enter\\' for none): ";
      cin.getline(pigGender, 10);
      if(pigGender != "\\n")
      {
          while(pigGender != "m" && pigGender != "f")
          {
              cout << "Invalid gender, please enter a valid gender m or f(if not press \\'Enter\\'): ";
              cin.getline(pigGender, 10);
              if(pigGender != "\\n")
              {
                  //cout << "if branch, pigGender:" << pigGender; 
                  gender = pigGender\[0\];
              }
              else
              {
                  //cout << "else branch, pigGender:" << pigGender;
                  gender = ' ';
                  break;
              }
          }
          pigs\[i\].SetPigGender(gender);
      }
      

      The piece of code above, shows how I'm trying to obtain the pig's gender from the user. I made it so that if the user doesn't know the gender, they can just hit enter to move on (as I did with other features that worked fine). The problem is that when you hit enter, the pigGender string doesn't seem to take the newline character. Also, I understand how the getline function works (takes in a newline and stops), hence I believe when you hit enter, the getline will take in the newline and stop, but here it does not seem to take it in at all. I also made it so that if the user enters a wrong letter (not m or f), then they can still hit enter if they do not know. The commented out codes are checks I implemented to see exactly what was in pigGender. When I enter a charcter that is not a newline it will go to the if branch and dislpay my error message, however, when I hit only enter, it still goes through that if branch instead of the else branch. the checks i commented out show me which branch I am in and the charcter in the pigGender string, and when I hit enter for the newline, there seems to be nothing in the pigGender string. What seems even more bizarre, is that the following code is very similar to what I did above (I actually copied and pasted it and made some changes to make the one above) and it works perfectly.

      cout << "Enter the pig weight(if not press \\'Enter\\'): ";
      cin.getline
      
      K Offline
      K Offline
      k5054
      wrote on last edited by
      #2

      iostream::getline() strips the trailing delimiter from input. That means that when you hit return only, the string is empty (e.g = ""). You also have an error in all your string comparisons:

      if(weight != "\n")

      is always true (this actually compares the address of weight to the address of the static object "\n". To compare objects of type char * (or char[]), you must use strcmp(). In this case, since you are just interested to see if the only char in the string is '\n' you could say

      if(weight[0] != '\n')

      (note that this still won't work because iostream::getline() strips the newline delimiter from the input. It only looks like the weight is being skipped. As explained above the comparison is always true, so the code block following the comparison is always executed. What is happening is that

      pigweight = atof(weight)

      evaluates with weight = "", which evaluates to zero, so it only seems like the code block was skipped. If you were to change the code to, say

      if(weight != "\n") // This is always true ...
      {
      cerr << "checking weight from user\n";
      // rest of block
      }

      You would always see the "checking weight from user" message, whether you hit return or not.

      M 2 Replies Last reply
      0
      • M Member_14767000

        for a short test in my class, we had to write code about pigs that allowed the user to enter information about a set of pigs (e.g. the pigs' names, breed, weight, gender, etc.). We were to create a class called pigs that would be able to hold the pigs' information. There was nothing wrong with the class itself, the problem I'm having is actually in the main function.

        cout << "Enter the pig gender (\\'m\\'/\\'f\\')(if not press \\'enter\\' for none): ";
        cin.getline(pigGender, 10);
        if(pigGender != "\\n")
        {
            while(pigGender != "m" && pigGender != "f")
            {
                cout << "Invalid gender, please enter a valid gender m or f(if not press \\'Enter\\'): ";
                cin.getline(pigGender, 10);
                if(pigGender != "\\n")
                {
                    //cout << "if branch, pigGender:" << pigGender; 
                    gender = pigGender\[0\];
                }
                else
                {
                    //cout << "else branch, pigGender:" << pigGender;
                    gender = ' ';
                    break;
                }
            }
            pigs\[i\].SetPigGender(gender);
        }
        

        The piece of code above, shows how I'm trying to obtain the pig's gender from the user. I made it so that if the user doesn't know the gender, they can just hit enter to move on (as I did with other features that worked fine). The problem is that when you hit enter, the pigGender string doesn't seem to take the newline character. Also, I understand how the getline function works (takes in a newline and stops), hence I believe when you hit enter, the getline will take in the newline and stop, but here it does not seem to take it in at all. I also made it so that if the user enters a wrong letter (not m or f), then they can still hit enter if they do not know. The commented out codes are checks I implemented to see exactly what was in pigGender. When I enter a charcter that is not a newline it will go to the if branch and dislpay my error message, however, when I hit only enter, it still goes through that if branch instead of the else branch. the checks i commented out show me which branch I am in and the charcter in the pigGender string, and when I hit enter for the newline, there seems to be nothing in the pigGender string. What seems even more bizarre, is that the following code is very similar to what I did above (I actually copied and pasted it and made some changes to make the one above) and it works perfectly.

        cout << "Enter the pig weight(if not press \\'Enter\\'): ";
        cin.getline
        
        S Offline
        S Offline
        Stefan_Lang
        wrote on last edited by
        #3

        k5054 already said it all. But I'd like to add the general advice that you read up on the description of all I/O functions rather than making assumptions about what they return. Especially input functions. Also, it is usually easier to read std::string objects rather than reading input of unknown length into limited size buffers. You can use the function getline(istream&, string) for that. See getline (string) - C++ Reference[^]

        GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)

        K 1 Reply Last reply
        0
        • K k5054

          iostream::getline() strips the trailing delimiter from input. That means that when you hit return only, the string is empty (e.g = ""). You also have an error in all your string comparisons:

          if(weight != "\n")

          is always true (this actually compares the address of weight to the address of the static object "\n". To compare objects of type char * (or char[]), you must use strcmp(). In this case, since you are just interested to see if the only char in the string is '\n' you could say

          if(weight[0] != '\n')

          (note that this still won't work because iostream::getline() strips the newline delimiter from the input. It only looks like the weight is being skipped. As explained above the comparison is always true, so the code block following the comparison is always executed. What is happening is that

          pigweight = atof(weight)

          evaluates with weight = "", which evaluates to zero, so it only seems like the code block was skipped. If you were to change the code to, say

          if(weight != "\n") // This is always true ...
          {
          cerr << "checking weight from user\n";
          // rest of block
          }

          You would always see the "checking weight from user" message, whether you hit return or not.

          M Offline
          M Offline
          Member_14767000
          wrote on last edited by
          #4

          But when I enter a valid weight and hit enter, the program moves on to the next feature (it doesnt go through the if branch).

          1 Reply Last reply
          0
          • K k5054

            iostream::getline() strips the trailing delimiter from input. That means that when you hit return only, the string is empty (e.g = ""). You also have an error in all your string comparisons:

            if(weight != "\n")

            is always true (this actually compares the address of weight to the address of the static object "\n". To compare objects of type char * (or char[]), you must use strcmp(). In this case, since you are just interested to see if the only char in the string is '\n' you could say

            if(weight[0] != '\n')

            (note that this still won't work because iostream::getline() strips the newline delimiter from the input. It only looks like the weight is being skipped. As explained above the comparison is always true, so the code block following the comparison is always executed. What is happening is that

            pigweight = atof(weight)

            evaluates with weight = "", which evaluates to zero, so it only seems like the code block was skipped. If you were to change the code to, say

            if(weight != "\n") // This is always true ...
            {
            cerr << "checking weight from user\n";
            // rest of block
            }

            You would always see the "checking weight from user" message, whether you hit return or not.

            M Offline
            M Offline
            Member_14767000
            wrote on last edited by
            #5

            I think I get what you are saying, but I just ran the program again and if I enter a valid weight (positive number) everything runs normally and at the end it displays the number I entered.

            K 1 Reply Last reply
            0
            • M Member_14767000

              I think I get what you are saying, but I just ran the program again and if I enter a valid weight (positive number) everything runs normally and at the end it displays the number I entered.

              K Offline
              K Offline
              k5054
              wrote on last edited by
              #6

              Sure, but if you do this

              if(weight != "\n")
              {
              // ...
              pigs[i].SetPigWeight(pigWeight);
              }
              else
              pigs[i].SetPigWeight(100.0); // Set default weight to 100.0
              // ...

              Now, when you hit enter, you would expect that the default weight would be used (i.e. set to 100.0), if the comparison is working as you expect. But it won't be, it will be set to zero. Believe me when I tell you that

              if (weight != "\n")

              does not compare objects of type char* (ie c-style strings). You must use strcmp() to compare c-style strings. Better than using iostream::getline, take a look at [std::getline](https://en.cppreference.com/w/cpp/string/basic\_string/getline). Your code might then look something like

              #include
              // ...
              string input_string;
              // ...
              getline(cin, input_string);
              if(input_string.length() != 0) // User entered a value
              {
              // ...
              }

              Furthermore, what happens if you enter one hundred for the weight? It doesn't get set to 100, but zero, since atof("one hundred") == 0.0. A good solution should check that the input is a number. At the very least that the input string contains only the characters "0123456789.". Ideally you would check that there was only one decimal point, too.

              M 1 Reply Last reply
              0
              • S Stefan_Lang

                k5054 already said it all. But I'd like to add the general advice that you read up on the description of all I/O functions rather than making assumptions about what they return. Especially input functions. Also, it is usually easier to read std::string objects rather than reading input of unknown length into limited size buffers. You can use the function getline(istream&, string) for that. See getline (string) - C++ Reference[^]

                GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)

                K Offline
                K Offline
                k5054
                wrote on last edited by
                #7

                Stefan_Lang wrote:

                Also, it is usually easier to read std::string objects rather than reading input of unknown length into limited size buffers. You can use the function getline(istream&, string) for

                Additionally, you should expect your Teacher/TA/Assignment-marker to be an "evil knave of the worst kind", looking to find ways to make your program crash. For any input she/he might choose to cut/paste something like:

                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

                If you use std::getline(), rather than iostream::getline(), you should be able to handle any reasonable input sent your way.

                S 1 Reply Last reply
                0
                • K k5054

                  Stefan_Lang wrote:

                  Also, it is usually easier to read std::string objects rather than reading input of unknown length into limited size buffers. You can use the function getline(istream&, string) for

                  Additionally, you should expect your Teacher/TA/Assignment-marker to be an "evil knave of the worst kind", looking to find ways to make your program crash. For any input she/he might choose to cut/paste something like:

                  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

                  If you use std::getline(), rather than iostream::getline(), you should be able to handle any reasonable input sent your way.

                  S Offline
                  S Offline
                  Stefan_Lang
                  wrote on last edited by
                  #8

                  k5054 wrote:

                  Additionally, you should expect your Teacher/TA/Assignment-marker to be an "evil knave of the worst kind", looking to find ways to make your program crash

                  I've found I learned more from the 'evil knave' types than those who were 'playing nice'. Nothing prepares you better for the real world than nasty traps! :suss:

                  GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)

                  1 Reply Last reply
                  0
                  • K k5054

                    Sure, but if you do this

                    if(weight != "\n")
                    {
                    // ...
                    pigs[i].SetPigWeight(pigWeight);
                    }
                    else
                    pigs[i].SetPigWeight(100.0); // Set default weight to 100.0
                    // ...

                    Now, when you hit enter, you would expect that the default weight would be used (i.e. set to 100.0), if the comparison is working as you expect. But it won't be, it will be set to zero. Believe me when I tell you that

                    if (weight != "\n")

                    does not compare objects of type char* (ie c-style strings). You must use strcmp() to compare c-style strings. Better than using iostream::getline, take a look at [std::getline](https://en.cppreference.com/w/cpp/string/basic\_string/getline). Your code might then look something like

                    #include
                    // ...
                    string input_string;
                    // ...
                    getline(cin, input_string);
                    if(input_string.length() != 0) // User entered a value
                    {
                    // ...
                    }

                    Furthermore, what happens if you enter one hundred for the weight? It doesn't get set to 100, but zero, since atof("one hundred") == 0.0. A good solution should check that the input is a number. At the very least that the input string contains only the characters "0123456789.". Ideally you would check that there was only one decimal point, too.

                    M Offline
                    M Offline
                    Member_14767000
                    wrote on last edited by
                    #9

                    You're right, I copied and pasted that code to try it and it set the pig weight to the default of 0 instead of 100. I understand what you are saying now. Thank you so much for taking out the time to explain this to me in detail. This thing was really frustrating me and you really cleared it up for me, I really appreciate this!

                    K 1 Reply Last reply
                    0
                    • M Member_14767000

                      You're right, I copied and pasted that code to try it and it set the pig weight to the default of 0 instead of 100. I understand what you are saying now. Thank you so much for taking out the time to explain this to me in detail. This thing was really frustrating me and you really cleared it up for me, I really appreciate this!

                      K Offline
                      K Offline
                      k5054
                      wrote on last edited by
                      #10

                      You're very welcome. String comparisons can be tricky in C/C++. I have over 30 years experience with C and it took me a couple of readings of your code to realize

                      if(weight != "\n")

                      did not do what it looks like it should! I'm sure I'm not the only one who looked at that and didn't twig right away that the string comparisons were incorrect.

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups