Thread: Problem with reading strings

  1. #1
    Registered User
    Join Date
    Nov 2004
    Posts
    73

    Problem with reading strings

    Hi everyone,

    My program is having a small problem with getting input from the user. If I try to add a customer the first time, it runs through every input line and gets the user's input with no problem but every time I try to add a customer to the program after the first add, for some reason it skips the part where it allows the user to enter their name and it goes directly to where it asks for the user's address and then continues on fine. So for every time I try to add a customer after I add the first one, it is skipping the line where it allows the user to enter their name and goes directly to the address input line.

    Note: all user input fields in the getdata() method are of string data type except for obviously the account balance. I've used getline to ensure the entire line of text is read and printed out and not just the first word which was a problem I was having before.

    Here is the code:

    Code:
    #include <iostream>
    #include <string>
    #include <cctype>
    #include <conio.h>
    #include <stdlib.h>
    #include "custclass.h"
    
    Customer:: Customer() {              // constructor
       acc_bal = 0.00;
    }
    
    void Customer::getdata() {
       int pcodelen;
       int pcode_flag = 0;
       int i;
       cout << "\nEnter your name: ";
       getline(cin, name);
       cout << "\nEnter your address: ";
       getline(cin, address);
       cout << "\nEnter your city: ";
       getline(cin, city);
       while (pcode_flag == 0) {
          cout << "\nEnter your postal code: ";
          getline(cin, pcode);
          pcodelen = pcode.length();
          if (pcodelen == 6 && isalpha(pcode[0]) && isalpha(pcode[2]) && isalpha(pcode[4]) && isdigit(pcode[1]) && isdigit(pcode[3]) && isdigit(pcode[5])) {
             pcode_flag = 1;
          }
          else {
             cout << "\nInvalid postal code entry.\n";
          }
       }
       cout << "\nEnter current account balance: ";
       cin >> acc_bal;
       cout << "\n\nCustomer added successfully. Press any key to return to main menu.";
       getche();
    }
    
    void Customer::deposit() {
       float dep;
       cout << "\nEnter amount to be deposited: ";
       cin >> dep;
       acc_bal += dep;
       cout << "\nNew account balance is: $" << acc_bal;
       cout << "\n\nPress any key to return to main menu.";
       getche();
    }
    
    void Customer::withdraw() {
       float wdraw;
       cout << "\nEnter amount to be withdrawn: ";    cin >> wdraw;
       if (wdraw > acc_bal) {
          cout << "\nCan't withdraw more money than what there is in the account. Press any key to return to main menu.";
          getche();
       }
       else {
          acc_bal -= wdraw;
          cout << "\nNew account balance is: $" << acc_bal;
          cout << "\n\nPress any key to return to main menu";
          getche();
       }
    }
    
    void Customer::showdata() {
       cout << "\nName: " << name;
       cout << "\nAddress: " << address;
       cout << "\nCity: " << city;
       cout << "\nPostal Code: " << pcode;
       cout << "\nAccount Balance: $" << acc_bal << endl;
       cout << "\n\nPress any key to return to main menu.";
       getche();
    }
    
    int main() {
    
       char choice;
       int flag = 0;
       int count = 0;
       int recnum;
       Customer cust[10];
    
       while (flag == 0) {
          cout << "\t\t\n\n" << "Main Menu";
          cout << "\t\n\n" << "Select by letter:";
          cout << "\t\n" << "a - Add a customer.";
          cout << "\t\n" << "d - Deposit money.";
          cout << "\t\n" << "w - Withdraw money.";
          cout << "\t\n" << "s - Show Account Information.";
          cout << "\t\n" << "q - Quit Application.\n\n";
          cout << "\t" << "Choice: ";
          choice = getche();
          switch(choice) {
             case 'a':
                system("cls");
                if (count >= 10) {
                   cout << "Can't add anymore records. Press any key to return to main menu.";
                   getche();
                   break;
                }
                count += 1;
                cust[count].getdata();
                system("cls");
                break;
    
             case 'd':
                system("cls");
                cout << "\nEnter customer number: ";
                cin >> recnum;
                cust[recnum].deposit();
                system("cls");
                break;
    
             case 'w':
                system("cls");
                cout << "\nEnter customer number: ";
                cin >> recnum;
                cust[recnum].withdraw();
                system("cls");
                break;
    
             case 's':
                system("cls");
                cout << "\nEnter customer number: ";
                cin >> recnum;
                cust[recnum].showdata();
                system("cls");
                break;
    
             case 'q':
                flag = 1;
                break;
    
             default:
                cout << "\nInvalid selection. Press a key to return to main menu.";
                getche();
          }
    
          if (flag == 1) {
             break;
          }
    
       }
       return 0;
    }
    This is baffling me as to why it's skipping the name input line when I try to add a customer for every run of adding a customer except for the first one which works fine.

    Does anybody know how to correct this issue?

    Also one other problem I'm having is that the program consistently is crashing after adding about 9 or 10 customers and I think that has to do with not flushing the input or output buffers. Is that indeed the problem? If it is, how can I ensure that buffers are always cleared?

    All of this working with strings and user input is very picky with C++. Then again, it is for all programming languages.

    Thanks.

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    This is a common problem. A previous call to cin using the >> operator left a newline in the stream and getline() is terminating immediately on it, thus appearing to skip that part of the input.
    My best code is written with the delete key.

  3. #3
    Registered User Finchie_88's Avatar
    Join Date
    Aug 2004
    Posts
    154
    all you need to do is put in "name.clear();" without the quotation marks and problem solved


  4. #4
    Registered User
    Join Date
    Nov 2004
    Posts
    73
    I'm trying to use your suggestion with using name.clear(); but it is giving me a compiler error: no matching function to call...

    am I missing something?

  5. #5
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Add the following at the places indicated:

    Code:
    #include <limits>
    
    ...
    
    void Customer::getdata() {
       int pcodelen;
       int pcode_flag = 0;
       int i;
       cin.ignore(numeric_limits<streamsize>::max(),'\n');
       cout << "\nEnter your name: ";
       getline(cin, name);
       cout << "\nEnter your address: ";
       getline(cin, address);
       cout << "\nEnter your city: ";
       getline(cin, city);
       while (pcode_flag == 0) {
          cout << "\nEnter your postal code: ";
          getline(cin, pcode);
          pcodelen = pcode.length();
          if (pcodelen == 6 && isalpha(pcode[0]) && isalpha(pcode[2]) && isalpha(pcode[4]) &&
              isdigit(pcode[1]) && isdigit(pcode[3]) && isdigit(pcode[5])) {
             pcode_flag = 1;
          }
          else {
             cout << "\nInvalid postal code entry.\n";
          }
       }
       cout << "\nEnter current account balance: ";
       cin >> acc_bal;
       cout << "\n\nCustomer added successfully. Press any key to return to main menu.";
       getche();
    }
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  6. #6
    Registered User
    Join Date
    Nov 2004
    Posts
    73
    I'm getting a file does not exist compile error with the #include <limits> statement that you suggested above.

  7. #7
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    This line:

    cin >> recnum;

    waits for the user to enter some input. Then, the user can type something in and hit Return. However, when the user hits Return, an invisible \n or "newline" character is entered after the input ('\n' is considered a single character). So, if the user types in 10 and hits Return, the input actually looks like this:

    10\n

    Now, let's examine how that input is handled. The >> operator is programmed to skip all leading whitespace, read in data, and stop reading in data when the first white space character is encountered(e.g. spaces, tabs, and newlines). And, very importantly, the terminating whitespace character is not read in. So, with this input:

    10\n

    1) The >> operator skips any leading whitespace--there's no whitespace in front of 10, so
    2) The >> operator reads in 10, and
    3) The >> operator stops reading when it encounters the whitespace character \n
    4) The >> operator does not read in the \n, and leaves the \n in the input stream.

    Thereafter, the input stream looks like this:

    \n

    Sometime later, these lines are executed:

    cout << "\nEnter your name: ";
    getline(cin, name);

    which is an instruction to read in more input. Specifically, getline() grabs all the input it can including whitespace until it hits the end of the line, which is indicated by a newline. Very importantly, unlike the operator>>, getline() reads in the \n character at the end of the line. In your case, there is still a \n left in the input stream, and as far as getline() is concerned that is good input, so it doesn't need to wait for any user input, and therefore getline() does it's thing and reads in the \n. Since a \n causes getline() to terminate, exectution continues.

    (By the way where is the variable 'name' ever declared? I have a hard time believing your program will even compile.)

    The lesson is: if you are going to be switching between the >>operator and getline(), you need to remove the '\n' character that is inserted at the end of the input when the user hits Return, and which the >>operator leaves in the input stream. You can remove a trailing whitespace character like this:

    cin>>data;
    cin.ignore(1);

    cin.ignore() will remove the designated number of characters from the stream.

    Note that cin.ignore() is not necessary when you do something like this:

    cin>>data;

    and then the user enters:

    10\n

    and then you do something like this:

    cin>>data2;

    Since the >> operator skips leading whitespace, the second cin skips over the \n remaining in the input stream from the first cin as it searches for something to read, and when it can't find anything to read, it stops and waits for the user to enter something.
    Last edited by 7stud; 06-04-2005 at 06:37 PM.

  8. #8
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by goron350
    I'm getting a file does not exist compile error with the #include <limits> statement that you suggested above.

    What compiler do you have?

    I guess you could take out the #include <limits> and change the other line I suggested to something more simple like:

    Code:
    cin.ignore(80,'\n');
    That should work.

    [edit]On second thought, the ignore should probably go after the last cin >> acc_bal; you have that reads in data. If it is before the first getline, then the first time you get to the code it will wait for you to press the enter key which would be a pain.[/edit]
    Last edited by hk_mp5kpdw; 06-05-2005 at 11:10 AM.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  9. #9
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Quote Originally Posted by Finchie_88
    all you need to do is put in "name.clear();" without the quotation marks and problem solved
    Since the poster is unable to read in name, what is name.clear() supposed to accomplish?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with comparing strings!
    By adrian2009 in forum C Programming
    Replies: 2
    Last Post: 02-28-2009, 10:44 PM
  2. Slight problem with socket reading!!!
    By bobthebullet990 in forum C Programming
    Replies: 5
    Last Post: 02-15-2006, 09:55 AM
  3. problem with reading and writing
    By yahn in forum C++ Programming
    Replies: 2
    Last Post: 01-03-2006, 04:38 PM
  4. reading file problem
    By samsam1 in forum Windows Programming
    Replies: 4
    Last Post: 01-15-2003, 06:03 PM
  5. problem with an array of strings in C
    By ornamatica in forum C Programming
    Replies: 14
    Last Post: 05-01-2002, 06:08 PM