Misses one item in first iteration of loop

I am rather puzzled. When I run the code below it misses out the prompt for input of the prompt "ENTER DESCRIPTION OF LOAD: " and its input in the first iteration of the loop. Thereafter, it is included. I have an earlier programm and it works perfectly. The only difference is that I have incorporated the function "double enterInteger(const string& prmp)" in the later program, which shouldn't have any effect.

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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335

#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <cmath>        
#include <iomanip>     
#include <vector>       
#include <sstream>    
#include <windows.h>
#include <conio.h>
#include <cctype>

using namespace std;

/* Keeps window open upon completion.  */
inline void keep_window_open()
{
    char ch;
    cin >> ch;
}



// Set console window size (Windows Only!)
void SetWindow(int Width, int Height)
{
    _COORD coord;
    coord.X = Width;
    coord.Y = Height;

    _SMALL_RECT Rect;
    Rect.Top = 0;
    Rect.Left = 0;
    Rect.Bottom = Height - 1;
    Rect.Right = Width - 1;

    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);      // Get Handle
    SetConsoleScreenBufferSize(Handle, coord);            // Set Buffer Size
    SetConsoleWindowInfo(Handle, TRUE, &Rect);            // Set Window Size
}



// DECLARE GLOBAL VARIABLES
double  L,  rl, rr, ra, rb;
int    j, k, nl, ns;
double vk, mk, mm, sm, z, z1, z2,wl;
double s, t;
double b, d, ec, i2;
string ldType;
string a1, a2, a3, a4, a5, a6;



// Set cursor position on the screen
void gotoxy(int x, int y)
{
    HANDLE hConsoleOutput;
    COORD dwCursorPosition;

    dwCursorPosition.X = x;
    dwCursorPosition.Y = y;
    hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hConsoleOutput,dwCursorPosition);
}



// Enter row of spaces at 0,24
void EnterRowOfSpaces()
{
    gotoxy(0,24);
    cout << string(80, ' ');
}



// Print a bar in prompt area at 0,23
void PrintBar()
{
    gotoxy(0,23);
    cout << string(80, '=');
}


//Print a line of dashes at 0,14
void PrintLine()
{
    //gotoxy(0,14);
    cout << string(80, '-');
}


// Clear 7 rows in display area
void Clear7Rows()
{
    gotoxy(0,15);
    string sp(80, ' ');
    cout << sp;
    for (int i=0; i<5; ++i)
        cout << '\n' << sp;
}


// Enter numeric character by character in the controlled
// range 0-9, -, .
double enterNumber(const string& prmp)
{
	string num;

	cout << prmp;

	for (char ch; ((ch = getch()) != '\n') && (ch != '\r');)
		if (isdigit(ch) || ((ch == '.') && (num.find('.') == string::npos)) || ((ch == '-') && num.empty())) {
			num += ch;
			cout << ch;
		} else
			if ((ch == '\b') && !num.empty()) {
				cout << ch << ' ' << ch;
				num.erase(prev(num.end()));
			} else
				if (ch != '\b')
					cout << '\a';

	return num.empty() ? 0.0 : stod(num);
}


// Enter Integer without minus
double enterInteger(const string& prmp)
{
	string num;

	cout << prmp;

	for (char ch; ((ch = getch()) != '\n') && (ch != '\r');)
		//if (isdigit(ch) || ((ch == '.') && (num.find('.') == string::npos)) || ((ch == '-') && num.empty())) {
		if (isdigit(ch) ) {
			num += ch;
			cout << ch;
		} else
			if ((ch == '\b') && !num.empty()) {
				cout << ch << ' ' << ch;
				num.erase(prev(num.end()));
			} else
				if (ch != '\b')
					cout << '\a';

	return num.empty() ? 0.0 : stod(num);
}


// integer
void getInt(const string & prompt, int & value)
{
    gotoxy(0,24);
    EnterRowOfSpaces();
    gotoxy(0,24);
    cout << prompt;
    //cin  >> value;
    //cin.ignore(1000, '\n');
    value = enterInteger("");
}


// double
void getNum(const string & prompt, double & value)
{
    gotoxy(0,24);
    EnterRowOfSpaces();
    gotoxy(0,24);
    cout << prompt;
    value = enterNumber("");
}



// Input string
void getStr(const string & prompt, string & value)
{
    gotoxy(0,24);
    EnterRowOfSpaces();
    gotoxy(0,24);
    cout << prompt;
    getline(cin, value);
}


//Enter the data function
void EnterData()
{
    gotoxy(0,0);
    cout << "\t\t\tSIMPLE BEAM DESIGN";

    gotoxy(0,13);
    cout << "PROMPT INFORMATION AREA:";
    gotoxy(0,14);
    PrintLine();

    gotoxy(0,22);
    cout << "ENTER DATA BELOW, WHEN PROMPTED:"  << endl;
    PrintBar();

   gotoxy(0,15);
   cout << "DECIDE HOW MANY SECTIONS AT WHICH YOU WISH TO CALCULATE THE" << endl;
   cout << "SHEAR FORCE AND BENDING MOMENT." << endl;
   cout << "THE MORE SECTIONS YOU CHOOSE, THE GREATER THE ACCURACY." << endl;
   cout << "USUALLY, A FIGURE OF 21 IS USED, BUT ON LARGE SPANS, YOU MIGHT" << endl;
   cout << "WISH TO USE ,SAY, 51 SECTIONS." << endl;
   cout << "THE NUMBER CHOSEN MUST BE AN ODD NUMBER." << endl;


    getInt("ENTER NUMBER OF SECTIONS TO BE CONSIDERED ALONG BEAM ", ns);
    getInt("ENTER NUMBER OF LOADS ON THE SPAN: ", nl);
    nl = nl + 1;

    getNum("ENTER SPAN OF BEAM (metres): ", L);

    gotoxy(0,0);
    cout << "No Of Sections: " << ns
         << "   No of Loads: " << nl
         << "  Span of Beam: " << L << " metres";


    Clear7Rows();
	gotoxy(0,24);
	EnterRowOfSpaces();

   gotoxy(0,20);
   cout << "BEAM SECTION (ENTER BEAM DIMENSIONS): "<< endl;
   gotoxy(0,24);
   cout << "ENTER BEAM WIDTH - e.g. 400 - (mm): ";
   cin >> b;
   EnterRowOfSpaces();

   gotoxy(0,24);
   cout << "ENTER BEAM DEPTH - e.g. 600 - (mm): ";
   cin >> d;
   i2 = b* pow(d,3)/12;

   Clear7Rows();
	EnterRowOfSpaces();

	gotoxy(0,16);
   cout << "ELASTIC MODULUS WILL VARY DEPENDING ON THE BEAM MATERIAL" << endl;
   cout << "FOR THE PURPOSE OF THIS PROGRAM CALCULATION WE WILL MAKE" << endl;
   cout << "ec = 25000 N/sq.mm." << endl;

   gotoxy(0,24);
   cout << "ENTER ELASTIC MODULUS - e.g. 25000 - (N/sq.mm):  ";
   cin >> ec;

   gotoxy(0,1);
   cout << "Elastic Modulus (N/sq.mm) = " << ec
           << "  M.Inertia mm^4 = " << (i2/(pow(10,12))) << endl;


   gotoxy(0,3);
   cout.width(5); cout << left << "Load No" ;
   cout.width(9); cout << left << " Load Type";
   cout.width(25); cout << left << " Description";
   cout.width(10); cout << right << " Load";
   cout.width(10); cout << right << " Start";
   cout.width(10); cout << right << " Cover" << '\n';


    vector<int> tl( nl + 1 );   
    vector<double> vs( ns + 1 );
    vector<double> ms( ns + 1 );
    vector<double> W( nl + 1 );
    vector<double> a( nl + 1 );
    vector<double> c( nl + 1 );
    vector<double> dist( ns );
    vector<double> ds( ns );

    double dk, zd, k1, mx;
    double dm = 0, sd = 0;

    vector<double> s1( ns + 1 );
    vector<string> desc( nl + 1 );


    // LOOP FOR NUMBER OF LOADS

    for (int j = 1; j<nl; j++)
    {
        ostringstream oss;
        oss << "LOAD NUMBER " << j
              <<":  ENTER TYPE OF LOAD (1, 2, 3 or 4): ";

        getInt(oss.str(), tl[j]);

        getStr("ENTER DESCRIPTION OF LOAD: ", desc[j]);

        getNum("ENTER LOAD, W (kN): ", W[j]);

        getNum("ENTER DISTANCE OF START OF LOAD FROM LEFT SUPPORT (metres): ", a[j]);

        getNum("ENTER LENGTH OF LOAD COVER - 0 IF PL (metres): ", c[j]);
        cout << endl;


        // Display loads information on screen
      gotoxy(0,4);
      for (int j = 1; j<nl; j++) {         // start the FOR loop for loads
            //cout << "ENTER DESCRIPTION";
            //cin >> desc[j];
      cout.width(9); cout << left << j;
      cout.width(5); cout  << left << tl[j];
      cout.width(4); cout << "  ";
      cout.width(25); cout << left << desc[j];
      cout.width(10); cout << right << setprecision(2) << showpoint << fixed <<W[j];
      cout.width(10); cout << right << setprecision(2) << showpoint << fixed << a[j] ;
      cout.width(10); cout << right << setprecision(2) << showpoint << fixed << c[j] << '\n';

    }
    }
}


int main()
{
    SetWindow(80,30);

    EnterData();
    Clear7Rows();
    gotoxy(0,24);

    EnterRowOfSpaces();
    gotoxy(0,24);

    return 0;
}
I have just submitted a query with code. My apologies for not including the comments that go with the original code. I had to delete to get below the 9000 allowed characters. However, running the code should identify the problem.
Be careful when switching between the extraction operator<< and getline() the extraction operator<< leaves the end of line character in the input buffer that must be extracted before you call getline().


@jlb
Thank you for your response.
I have tried to extract the end of line character by inserting
cin.ignore(1000, '\n');
at the beginning of the getstr() function as below:

1
2
3
4
5
6
7
8
9
10
11
void getStr(const string & prompt, string & value)
{
    cin.ignore(1000, '\n');
    gotoxy(0,24);
    EnterRowOfSpaces();
    //cin.ignore(1000, '\n');
    gotoxy(0,24);
    cout << prompt;
    getline(cin, value);
    //cin.ignore(1000, '\n');
}


You can see with the comments. I have tried it in other locations as well. It works, but has the downside that, in the second iteration and thereafter I have to hit the enter key twice before the prompt comes up to enter "ENTER DESCRIPTION OF LOAD: ".

Is there another way to extract the end of line character that will only require the single enter hit?
Usually it is a logical misunderstanding to try to pair the ignore() with the getline().

Yes, the getline() is where the problem shows up, it is the symptom. But to fix it, you need to find the cause. That cause will usually be found in some other part of the code, for example where you have a cin >> statement.

If you are lucky, you will be able to trace the sequence of execution and find which cin >> was most recently executed before this function. If you are unlucky, there may be many different possibilities. But the solution is the same, place the cin.ignore(1000, '\n'); just after the cin >>. That will cure the cause rather than the symptom.
@Chervil
Thank you for your response.
There are only two functions that immediately precede the prompt "ENTER DESCRIPTION OF LOAD: " which is followed by getline(). These are getint(), which calls EnterInteger(). I have placed cin.ignore() and cin.ignore(1000, '\n') all over these two functions to try to get over the problem, without success.

What I can't get my head around is that they work perfectly for the first iteration of the loop, but thereafter you have to hit Enter twice after entering the number of loads. The iterations are exact repeats, so I can't see why there is any difference.

Can this be explained?
Can you explain what exactly you're trying to do in your double enterNumber() and enterInteger() functions? Please explain the functions line by line.


And note mixing conio functions with C++ streams is a really bad practice.

Lastly because of all of those non-standard items being used I can't actually run your program so I can only guess as to what is causing the problems.


@jlb
Thank you for your response.
enterNumber() allows the entry of characters one at a time and is checked before display that it is in the range 0-9, - or .
If it is not in this range it is ignored. Completion of the entry is by hitting Enter.
Similarly, enterInteger() does the same thing but only allows the range 0-9.

An example of enterNumber() is shown below:

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
#include <conio.h>
#include <cctype>
#include <string>
#include <iostream>
#include <iomanip>

using namespace std;

double enterNumber(const string& prmp)
{
	string num;

	cout << prmp;

	for (char ch; ((ch = getch()) != '\n') && (ch != '\r');)
		if (isdigit(ch) || ((ch == '.') && (num.find('.') == string::npos)) || ((ch == '-') && num.empty())) {
			num += ch;
			cout << ch;
		} else
			if ((ch == '\b') && !num.empty()) {
				cout << ch << ' ' << ch;
				num.erase(prev(num.end()));
			} else
				if (ch != '\b')
					cout << '\a';

	return num.empty() ? 0.0 : stod(num);
}

int main()
{
	//auto number =enterNumber("Enter a number: ");
	double number =enterNumber("Enter a number: ");

	cout << "\nNumerical input: " << fixed << setprecision(2) << number;
}



and enterInteger():

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
#include <conio.h>
#include <cctype>
#include <string>
#include <iostream>

using namespace std;

double enterInteger(const string& prmp)
{
	string num;

	cout << prmp;

	for (char ch; ((ch = getch()) != '\n') && (ch != '\r');)
		//if (isdigit(ch) || ((ch == '.') && (num.find('.') == string::npos)) || ((ch == '-') && num.empty())) {
		if (isdigit(ch) ) {
			num += ch;
			cout << ch;
		} else
			if ((ch == '\b') && !num.empty()) {
				cout << ch << ' ' << ch;
				num.erase(prev(num.end()));
			} else
				if (ch != '\b')
					cout << '\a';

	return num.empty() ? 0.0 : stod(num);
}

int main()
{
	auto num =enterInteger("Enter a number: ");

	cout << "\nNumerical input: " << num;
}


It took a long time to get code together to achieve this, so if there is a way without using conio.h, I would appreciate if it could be provided.

Does this help?

Why are you even worrying about checking the numbers before you display them?

This doesn't achieve the identical effect, since conio / getch behave in a different way. But it does at least validate the input, after it is entered. Note that through the use of a template, the same function is used for both integer and double values.

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
#include <string>
#include <iostream>
#include <windows.h>

using namespace std;

// Set cursor position on the screen
void gotoxy(int x, int y)
{
    HANDLE hConsoleOutput;
    COORD dwCursorPosition;

    dwCursorPosition.X = x;
    dwCursorPosition.Y = y;
    hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hConsoleOutput,dwCursorPosition);
}

template <typename T>
void getNumber(const string & prompt, T & value)
{

    gotoxy(0,24);
    cout << string(80, ' ');
    gotoxy(0,24);
    cout << prompt;
    while ( !(cin  >> value) )
    {
        cin.clear();
        cin.ignore(1000, '\n');
        gotoxy(0,24);
        cout << string(80, ' ');
        gotoxy(0,24);
        cout << prompt;
    }
    cin.ignore(1000, '\n');
}

int main()
{   
    int num;
    getNumber("Enter an Integer: ", num);    
    cout << "\nInteger input: " << num << '\n';
    
    double dnum;
    getNumber("Enter Floating-point: ", dnum);    
    cout << "\nFloating-point input: " << dnum << '\n';

}

Something of that style was discussed earlier today by Handy Andy and myself:
http://www.cplusplus.com/forum/beginner/225093/#msg1028833
http://www.cplusplus.com/forum/beginner/224986/#msg1028831


I've not attempted to run the original code, so I don't know whether this addresses the problem you are having. It might be irrelevant, something else might be involved, so far I didn't study the rest of the code..
@jlb
I just want to do it this way. It saves a lot of error checking later and I know that I have not entered something I shouldn't.
@Chervil has come up with an alternative, where unacceptable characters are stripped out. Thank you Chervil. However, I have other similar methods, but the one I really like is the calculator type input, checked character by character.

I have looked further on CPlusPlus and have found some code by Duthomhas on 18 August 2008 that does the same as getch() without conio.h.

Enter Integer (without minus)
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
#include <cstdio>
#include <cctype>
#include <string>
#include <iostream>
#include <windows.h>

using namespace std;

// This code from Duthomhas in CPlusPlus Forum
// 18 August 2008
TCHAR getkeypress()
  {
  DWORD mode, count;
  HANDLE h = GetStdHandle( STD_INPUT_HANDLE );
  if (h == NULL) return 0;  // not a console
  GetConsoleMode( h, &mode );
  SetConsoleMode( h, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT) );
  TCHAR c = 0;
  ReadConsole( h, &c, 1, &count, NULL );
  SetConsoleMode( h, mode );
  return c;
  }

double enterInteger(const string& prmp)
{
	string num;

	cout << prmp;

	for (char ch; ((ch = getkeypress()) != '\n') && (ch != '\r');)
	//for (char ch; ((ch = cin.get()) != '\n') && (ch != '\r');)
		//if (isdigit(ch) || ((ch == '.') && (num.find('.') == string::npos)) || ((ch == '-') && num.empty())) {
		if (isdigit(ch) ) {
			num += ch;
			cout << ch;
		} else
			if ((ch == '\b') && !num.empty()) {
				cout << ch << ' ' << ch;
				num.erase(prev(num.end()));
			} else
				if (ch != '\b')
					cout << '\a';

	return num.empty() ? 0.0 : stod(num);
}

int main()
{
	auto num =enterInteger("Enter a number: ");

	cout << "\nNumerical input: " << num;
}




and, EnterNumber (0-9, -, .)

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
#include <cctype>
#include <string>
#include <iostream>
#include <iomanip>
#include <windows.h>

using namespace std;

// This code from Duthomhas in CPlusPlus Forum
// 18 August 2008
TCHAR getkeypress()
  {
  DWORD mode, count;
  HANDLE h = GetStdHandle( STD_INPUT_HANDLE );
  if (h == NULL) return 0;  // not a console
  GetConsoleMode( h, &mode );
  SetConsoleMode( h, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT) );
  TCHAR c = 0;
  ReadConsole( h, &c, 1, &count, NULL );
  SetConsoleMode( h, mode );
  return c;
  }

double enterNumber(const string& prmp)
{
	string num;

	cout << prmp;

	for (char ch; ((ch = getkeypress()) != '\n') && (ch != '\r');)
		if (isdigit(ch) || ((ch == '.') && (num.find('.') == string::npos)) || ((ch == '-') && num.empty())) {
			num += ch;
			cout << ch;
		} else
			if ((ch == '\b') && !num.empty()) {
				cout << ch << ' ' << ch;
				num.erase(prev(num.end()));
			} else
				if (ch != '\b')
					cout << '\a';

	return num.empty() ? 0.0 : stod(num);
}

int main()
{
	//auto number =enterNumber("Enter a number: ");
	double number =enterNumber("Enter a number: ");

	cout << "\nNumerical input: " << fixed << setprecision(2) << number;
}


I've entered the function getkeypress() into my program and removed conio.h and it all works except for the requirement for the double hit of Enter mentioned in earlier posts. I just don't see why it should be happening.

Topic archived. No new replies allowed.