Failure of cin.getline()

closed account (jwC5fSEw)
I have the following code as a part of a struct:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    void menu(){
        hasMovie = false;
        money = getMoney();
        cout << "Welcome to the video store. What would you like to do?\n";
        if (hasMovie == false){
            cout << "1. Rent a movie.\n" <<
                    "2. Exit the store.\n";
            cin >> menuOption;
            switch(menuOption){
                case 1:
                    getRentalInfo();
                    break;
                case 2:
                    leaveStore();
                    break;
            }
        }
        else {
            cout << "1. View your rental information.\n" <<
                    "2. Wait a day.\n" <<
                    "3. Exit the store.\n";
            cin >> menuOption;
            switch(menuOption){
                case 1:
                    printInfo();
                    break;
                case 2:
                    advanceTime();
                    break;
                case 3:
                    leaveStore();
            }
        }
    }

    void getRentalInfo(){
        cout << "What is the name of the movie you'd like to rent?\n";
        cin.getline(name,50);
        cout << "What year was it released?\n";
        cin >> releaseYear;
        cout << "How many days would you like to rent it for?\n";
        cin >> rentalLength;
        format = getFormat();
        rentalCost = getRentalCost();
        printInfo();
        hasMovie = true;
    }


When I call getRentalInfo() directly, it runs fine. But when I call menu(), it skips line 38. If I change it to cin, it works, but I need to be able to read the whole line. Any ideas why?
I think Try to Change
cin.getline(name, 50);
to this:
getline(cin, name);
No, it is because you are mixing formatted and unformatted input.

Don't do that.

Every time you ask the user for something, he will always press the ENTER key when done.

So every time the user gives you something, you must remove that ENTER key (newline '\n') from the input stream.

1
2
3
4
5
6
7
8
9
int x = -1;
cout << "What is your favorite whole number? ";
cin >> x;
cin.clear();
cin.ignore( numeric_limits <streamsize> ::max(), '\n' );  // Get rid of the ENTER key
if (x < 0)
  cout << "Hey, that is not a whole number!\n";
else
  cout << "Nice! I like " << x << " too!\n";
1
2
3
4
string name;
cout << "What is your best friend's name? ";
getline( cin, name );  // This gets rid of the ENTER key for you
cout << "Tell " << name << " \"Hello\" for me!\n";

Hope this helps.
closed account (jwC5fSEw)
Adding

1
2
cin.clear();
cin.ignore( numeric_limits <streamsize> ::max(), '\n' )


after each cin didn't help. If I understand you correctly, using cin.getline() and the above two lines after each cin are both compatible inputs, right?
You should really NEVER EVER EVER mix cin >> somevar and cin.getline(somevar). It always ends really badly. It's bad style and it's better to just get rid of one or the other, than to toss in some ignores and "solve" the problem, because the underlying issue (thinking that such behavior is acceptable) is flawed still.
You have probably more than one newline in the buffer. I'm not sure if I know the ignore behavior well enough to say, but when it finds the delimiter (newline) it will discard the one it found and stop, potentially leaving more of them in there, so try removing the delimiter argument and see what happens.

Whoops. Sorry about that. cin skips leading whitespace using formatted input.
Last edited on
closed account (jwC5fSEw)
So what alternatives do I have for reading the numbers? cin.getline takes a char*, not an int.
Sigh.

There is nothing wrong with using both cin >> somevar and getline() as long as you do it correctly: account for the user pressing ENTER after every input.

I've been doing this long enough that "[it] didn't help" doesn't really fly with me. You are doing something wrong.

Post your code, the input you are using, and the output you wish to see.
closed account (jwC5fSEw)
Fair enough. Here is all of my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

struct video{
    char name[50],
    formatChar[15],
    isReturned;
    int releaseYear,
    rentalLength,
    format,
    menuOption;
    float rentalCost,
    money;
    bool inDebt,
    hasMovie;

    void menu(){
        hasMovie = false;
        money = getMoney();
        cout << "Welcome to the video store. What would you like to do?\n";
        if (hasMovie == false){
            cout << "1. Rent a movie.\n" <<
                    "2. Exit the store.\n";
            cin >> menuOption;
            switch(menuOption){
                case 1:
                    getRentalInfo();
                    break;
                case 2:
                    leaveStore();
                    break;
            }
        }
        else {
            cout << "1. View your rental information.\n" <<
                    "2. Wait a day.\n" <<
                    "3. Exit the store.\n";
            cin >> menuOption;
            switch(menuOption){
                case 1:
                    printInfo();
                    break;
                case 2:
                    advanceTime();
                    break;
                case 3:
                    leaveStore();
            }
        }
    }

    void getRentalInfo(){
        cout << "What is the name of the movie you'd like to rent?\n";
        cin.getline(name,50);
        cout << "What year was it released?\n";
        cin >> releaseYear;
        cin.clear();
        cin.ignore( numeric_limits <streamsize> ::max(), '\n' );
        cout << "How many days would you like to rent it for?\n";
        cin >> rentalLength;
        cin.clear();
        cin.ignore( numeric_limits <streamsize> ::max(), '\n' );
        format = getFormat();
        rentalCost = getRentalCost();
        printInfo();
        hasMovie = true;
    }

    float getMoney(){
        float num = rand() % 21 + 10.0;
        return num;
    }

    int getFormat(){
        while(true){
            cout << "What movie format would you like to rent?\n" <<
                    "1. VHS\n" <<
                    "2. DVD\n" <<
                    "3. Blu-ray\n";
            cin >> format;
            switch(format){
                case 1:
                    cout << "You have chosen to rent a VHS.\n";
                    strcpy(formatChar,"VHS");
                    return 1;
                case 2:
                    cout << "You have chosen to rent a DVD.\n";
                    strcpy(formatChar,"DVD");
                    return 2;
                case 3:
                    cout << "You have chosen to rent a Blu-ray.\n";
                    strcpy(formatChar,"Blu-ray");
                    return 3;
                default:
                    cout << "You have not selected a valid choice.\n";
                    break;
            }
        }
    }

    float getRentalCost(){
        cout << "Costs per day are as follows:\n" <<
                "VHS - $.50 per day\n" <<
                "DVD - $1.00 per day\n" <<
                "Blu-ray - $1.50 per day\n";
        rentalCost = rentalLength*format*.50;
        cout << "Therefore, renting " << name << " for " << rentalLength << " days will cost " << rentalCost << " dollars.\n";
        return rentalCost;
    }

    void printInfo(){
        if (hasMovie == false){
            if (rentalCost > money){
                inDebt = true;
                cout << "You can't afford this. Leave.";
                leaveStore();
            }
            else {
                cout << "You are renting " << name << " (" << releaseYear << ").\n" <<
                        "It is a " << formatChar << ".\n" <<
                        "You are renting it for " << rentalLength << " days, which will cost you " << rentalCost << " dollars.";
            }
        }
        else {
            cout << "You are renting " << name << " (" << releaseYear << ").\n" <<
                    "It is a " << formatChar << ".\n" <<
                    "You are renting it for " << rentalLength << " more days, which will cost you " << rentalCost << " dollars.\n";
            if (rentalLength < 0)
                cout << "IT IS LATE!\n";
        }
    }

    void advanceTime(){
        rentalLength--;
        if (rentalLength <=0);
            lateRental();
    }

    void lateRental(){
        while(true){
            if (rentalLength == 0)
                cout << "Your movie is due! Return it today, or you will have to pay a 50% interest for every day it is late. Will you return it? (y/n)";
            else
                cout << "Your movie is late. Return it now, and you'll be saved tomorrow's interest. Will you return it? (y/n)";
            cin >> isReturned;
            if (isReturned == 'y'){
                returnMovie();
                break;
            }
            else if (isReturned == 'n'){
                rentalCost += .5*rentalCost;
                cout << "Fine, we'll just add the interest. If you choose to return it tomorrow, you'll owe " << rentalCost << ".\n";
                break;
            }
            else
                cout << "Not a valid entry.";
        }
    }

    void returnMovie(){
        if (inDebt == true){
            cout << "You can't afford this, I'm calling the police!\n";
            leaveStore();
        }
        else {
            money -= rentalCost;
            cout << "Thank you for the returning the movie. You have " << money << " dollars left.\n";
            leaveStore();
        }
    }

    void leaveStore(){
        if (inDebt == true){
            cout << "Goodbye, come back soon!\n";
        }
        else {
            cout << "I hope they lock you up and throw away the key, you criminal!\n";
        }
    }
};

int main(){
    srand(time(NULL));
    video t;
    t.menu();
    return 0;
}


I haven't gotten around to making it all work like I want it to. The menu() function was written after most of the other code, so I've been having sort of a hard time changing it to work with that. Right now, I expect the menu to be displayed when I input 1. That happens. Then, I expect "What is the name of the movie you'd like to rent?" to be displayed and wait for my input. What happens is "What is the name of the movie you'd like to rent?" is displayed, then a newline, then "What year was it released?" is displayed and then waits for input. I know it has something to do with a) being called from menu(), because it works when I call it directly from main and b) using cin.getline(), because using cin works. I can't figure out what about these things are making it not work. Does that help at all?
cin.clear() does not clear the stream. You MUST use cin.ignore(...)
closed account (jwC5fSEw)
Well, as Duoas recommended above, I'm currently using both cin.clear() and cin.ignore( numeric_limits <streamsize> ::max(), '\n' ); however it isn't fixing the problem I described.
I see several cin >> that do not have a cin.clear()/ignore() after them. Line 82 and 147 come to find. You'll have to fix all of them.
closed account (jwC5fSEw)
Ohhhh, I thought I only had to replace the ones in the erring function. The problem is solved, thanks for all of the help!
Topic archived. No new replies allowed.