Trouble with getline()

Here is a small section of code that I am working on. This isn't for a class; I'm just doing this for myself for the practice.

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
struct ride
{
int number;
int date;
string place;
double miles;
double hours;
double minutes;
double time;
double average;
char with;
string notes;
}Rides[a], WRides[b];

void NewRide()
{
     for(row=0; WRides[row].number != 0; row++)
     {}
          WRides[row].number=seq;
          cout << "Enter the Ride Date (yyyymmdd)";
          cin >> d;
          while (d > 20111231 || d < 20090101)
                {
                cout << "That is not a valid date.\n"
                     << "Please enter the Ride Date (yyyymmdd)\n";
                cin >> d;
                }
          WRides[row].date=d;
          cout << "Where was the ride?" << endl;
          getline (cin,WRides[row].place);
          cout << "How many miles was the ride?\n";
          cin >> WRides[row].miles;
          cout << "How many hours (whole) was the ride?\n";
          cin >> WRides[row].hours;
          cout << "How many minutes more was the ride?\n";
          cin >> WRides[row].minutes;
          WRides[row].time=WRides[row].hours+(WRides[row].minutes/60);
          WRides[row].average=WRides[row].miles/WRides[row].time;
          cout << "Did you ride with anyone?\n"
               << "Enter A if you rode alone, B if you rode with Brian\n"
               << "and C if you rode with someone other than Brian.\n";
          cin >> r;
          r = toupper(r);
          cout << r;
          while (r != 'A' && r != 'B' && r != 'C')
               {
               cout << "That is not a valid selection.\n"
                    << "Please enter A if you were alone, B if you were with "
                    << "Brian,\nand C if you were with someone else.\n";
               cin >> r;
               r=toupper(r);
               }
          WRides[row].with=r;
          cout << "Enter any notes for the ride.\n"
               << "If there are no notes, enter 0.\n";
          getline (cin, WRides[row].notes);
      seq++;
      cout << "Do you want to enter another ride? (Y / N)\n";
      cin >> r;
      r = toupper(r);
      while (r != 'Y' && r != 'N')
         {
               cout << "That is not a valid selection\n"
                    << "Do you want to enter another ride? (Y / N)\n";
               cin >> r;
               r=toupper(r);
         }
      if (r == 'Y')
      NewRide();
      else
      CopyRides();
      DspRides(WRides, b);
      MenuMain();
}


Everything seems okay, except for line 30; the getline function. Once I have passed the date entry, I get the output "Where was the ride?" But then it skips to the next line and asks for the miles of the ride. I never get a chance to enter the text into the .place field. Any suggestions on what I have done wrong here would be appreciated.
Add the cin to the while loop like so. That is a different issue but I might as well mention it.
1
2
3
4
5
6
while (cin >> d && d > 20111231 || d < 20090101)
                {
                cout << "That is not a valid date.\n"
                     << "Please enter the Ride Date (yyyymmdd)\n";
                cin >> d;
                }


I think that the problem is mixing cin and getline. cin leaves the carriage return within the stream and then getline extracts a null string. You can confirm by stepping with the debugger and analyzing the string that you are reading into.
http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.6

Also check the articles forum for more articles on this. There are a couple on this subject and it is a rather confusing issue. I'm not sure why cin statements work after one another.
Before the getline() put in a cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n') function.

Reason: before getline() is passed, the input stream has a whole bunch of unread endlines ("\n"). Since getline passes an error if it reads an empty line, it blocks all other input. The ignore function will catch the endlines prior to the getline, preventing any error.

Hope this helps.
Maybe this helps a little and the references are not always obvious. getline reads until it reaches the delimiter character which happens to be '\n' by default. You can override this by specifying the 3rd parameter of the call. the operator>> seems to ignore the '\n' completely. When you use std::cin to extract multiple times into a variable it doesn't seem to matter. Also std::cin stops at whitespace as you know. that is why you need getline to read the entire sentence. That is why you need to ignore call when using getline after the cin.
Re Kempofighter's comment:

Add the cin to the while loop like so. That is a different issue but I might as well mention it.

1
2
3
4
5
6
 while (cin >> d && d > 20111231 || d < 20090101)
                {
                cout << "That is not a valid date.\n"
                     << "Please enter the Ride Date (yyyymmdd)\n";
                cin >> d;
                }



That part of the code actually works as I had written it. Is there a reason why I should change it to how you indicated? I took an intro class this spring, and will be taking a data structures class this summer. But the teacher was horrid at giving us any feedback on better ways to do something. Is doing the cin >> as part of the while statement more correct than doing it outside the statement, as I had done?

I haven't tried the cin.ignore suggestions yet, but will do that.

Thanks for the suggestions.
Your current code will not work if you accidentally enter bad data and d will be left with a stale value. For instance, if you are looping and you enter a valid integer once and an invalid integer the next time then you may end up processing the previously entered value. You really need to test that the stream extraction worked. If you fat finger a key and press a character then your stream extraction will fail. By the way I forgot the parens. Enclose each of the two tests within separate parens so that you don't have to worry about the order of the processing.

Topic archived. No new replies allowed.