trying to use the getline() function after an initial use of cin

Pages: 12
I have been attempting to use the getline() input stream to read a string immediately after reading in a number using cin object, but I noticed that when I run the program, after it prompts for the first number to be entered, it seems to skip the prompt for the string and jumps to the next loop then requests for the next number to be entered without prompting for the string.

I tried to correct this by inserting a for loop after the first input function has been called. This seemed to work but there are still issues.

The code is below.

I'd be glad to get your suggestions as to how I can implement the getline() in this 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
#include<iostream>
#include<string>

using std::cout;
using std::endl;
using std::cin;

using std::string;
using std::getline;

void getNum(double num, int& i);
void getStr(string aStr, int& i);

int main()
{
	double nNum;		
	string sStr;		

	int index{};

	for (int i{}; i < 6; ++i)
	{
		cout << "Please enter a number or 0 to exit: ";
		cin >> nNum;		           //Reads input from keyboard

		if (nNum != 0)
			getNum(nNum, index);									//Calls number fxn
		else
			break;
		for (int i{}; i < 2; ++i)
		{
			cout << "Type a string of characters: " << endl;
			
			getline(cin, sStr);   //Reads a string from the keyboard
			getStr(sStr, index);  //Calls string fxn
		}
	}

	cout << endl;
	return 0;
}

//Function body to input number
void getNum(double num, int& index)
{
	double aNumber[6];
	string sStr;

	aNumber[index++] = num;		//Store the string in an array
}

//Function body to input strings
void getStr(string sStr, int& index)
{
	string aString[6];
	aString[index++] = sStr;
}  
Last edited on
The cin input stream is buffered. After entering each value such as
 
cin >> nNum;
there will remain at least a trailing newline character '\n' in the buffer.

If you clear the buffer after the cin >>, then the next input operation becomes more guaranteed to behave in a predictable way.
1
2
    cin >> nNum;                 // leaves at least a trailing newline
    cin.ignore(1000, '\n');      // empty input buffer 


http://www.cplusplus.com/reference/istream/istream/ignore/

Note, getline() consumes the newline character, but formatted input with cin >> leaves it behind.

@Chervil
Wow thanks. I will try it out and get back to you asap.

Also, I've read the article in the link you posted but I'd like to ask what the parameters in the cin.ignore(1000, ’\n') actually mean?

Thanks again.
The reference page for ignore() describes the parameters, but perhaps in too technical a way to begin with.
Quote:
cplusplus_com wrote:
Extracts characters from the input sequence and discards them, until either n characters have been extracted, or one compares equal to delim.


The starting point is that the input stream is buffered. When prompted to enter a number, the user might enter something like "123" and then press enter. All of that, including the newline generated when the enter key is pressed, gets stored in the buffer, "123\n".
After processing the cin >> nNum, the numeric characters which can be interpreted as an integer are extracted from the buffer, but the newline '\n' isn't part of the number, so it remains behind in the buffer.

cin.ignore() with no parameters will just read and discard a single character from the buffer, which might be sufficient.

But what if, when prompted for a number, the user typed
" 123 hello \n"? Any leading spaces will be read and discarded, but any trailing characters whether spaces or anything else, will get left behind.

So we can tell the ignore() function to ignore more than one character. But how many? Well, we don't know what was typed by the user, so I just chose a large number, 1000. cin.ignore(1000) tells the function to read and ignore the next 1000 characters. But hold on, the user may not have typed that many, and the command will sit there waiting for the next 999 characters, that's no good. So we add a delimiter, which tells ignore to stop processing after it has read that particular character. Hence the form I chose, cin.ignore(1000, '\n'); which means ignore up to 1000 characters, or until a newline is found. The number 1000 is entirely arbitrary, I just chose that because it is usually sufficient.
Last edited on
Hmmm, awesome. Now I understand. I'm grateful you took time out to elucidate on these concepts. Thank you @Chervil.
Last edited on
@Chervil:
Thank you. The cin.ignore(1000, '/n') object worked but there's another prevalent issue which I thought would be resolved after making the correction.

At run time, upon the seventh prompt (at this point, the program asks for a number to be entered), the program terminates abruptly with the error:

"Run-Time Check Failure #2 - Stack around the variable 'aNumber' was corrupted"

How do I rectify this?
Thank you.
Last edited on
upon the seventh prompt

It probably is no coincidence that you have two arrays of size six elements. Almost certainly that would suggest an out-of-bounds array access (trying to modify an element of the array which doesn't exist, thereby corrupting some other adjacent memory location).

I don't understand the purpose of either array - they are local to the function and will no longer exist after the function terminates. Only one element is ever used, but only briefly, before it drops out of scope and is lost.
True, what was I thinking? Will modify it and get back to you asap. Or do you have any suggestions? Thank you.
Last edited on
@Chervil
Sorry, but can I communicate with you on a one to one basis? I'd really appreciate if I could send the subsequent revision as a private mail since you have been the only one in correspondence with me.
My email is ayoesquire@yahoo.com.
Thanks
Last edited on
@Ayoesquire thanks for the invitation. I'd prefer to continue openly using the ordinary forum thread - where others may learn, and equally may fill in on some things I might miss or get wrong. (in the past I've let too many people down by missing private messages until well past their sell-by date. At least a forum post can be picked up by others if I should drop the ball).
Last edited on
@Chervil:

Ok. No problem at all. I understand your point and I really appreciate your time and effort.

I should post the revision by tomorrow. I just wanted to make sure you'd be available by then. Kinda selfish of me, right? lol!

Please, whenever you have the time, I'd appreciate it if you keep me in mind and check it out. You have been great. Thanks!
Last edited on
I just wanted to make sure you'd be available by then.

Today being New Year's Eve on this part of the globe, there's still a lot of partying to be done between now and tomorrow :) The next day will have to take care of itself - when it arrives.
That reminds me, Happy New Year in Advance. In about 3hrs time we will be in the new year, and I guess we are AHEAD of you guys in this part of the world. So see u in 2017 :-).
(@Chervil)
Here's the first revision of the corrected version of the original code as promised. Thanks for all the help. Looking forward to responses and corrections. Thanks:

//ayoesquire@cplusplusforum.com
//Stores a number and their corresponding string values.
//First Revision (Abridged).
//Acknowledgement: @Chervil (cplusplus.com). Regards!

#include<iostream>
#include<string>

using std::cout;
using std::endl;
using std::cin;

using std::string;
using std::getline;

//Function prototypes
void getData(double aNum[], string aStr[], int& i);
void showData(const double aNum[], const string aStr[], const int i);

int main()
{
string aString[6]; //Declaration of an array of strings
double aNumber[6]; //Declaration of an array of strings

int index{}; //Keeps tab of current position
int count{}; //Counter

for (int i{}; i < 6; i++)
{
getData(aNumber, aString, index);
if (aString[index] == "") //Exits in the event that there is no string entered
break;
cout << aString[index] << endl; //Just to check that string passed successful
index++;
}

count = index;
//Call of the display function
showData(aNumber, aString, index);

cout << endl;
return 0;
}

void getData(double aNum[], string aStr[], int& index)
{
double number[6];
string str[6];

//Prompts for a number
cout << "Enter a number,or 0 to end: ";
cin >> number[index];
cin.ignore(1000, '\n'); //Discards cin object buffer, courtesy Chervil @ cplusplus.com

if (number[index] != 0)
{
aNum[index] = number[index]; //Store number entered in array

cout << "Type a string (or press only Enter to exit): " << endl;
getline(cin, str[index]);
aStr[index] = str[index];

}

}
At a glance I see two independent sets of arrays.
In main()
1
2
string aString[6]; //Declaration of an array of strings
double aNumber[6]; //Declaration of an array of strings 


in function getData()
1
2
double number[6];  // declaration of some 
string str[6];     // more arrays 


You don't need the second set of arrays. Just operate directly on the original arrays (or on the parameters passed to the function).

Perhaps less important, in main there are three separate integers, count, index and i all serving more or less the same purpose. They could be merged into one.

Anyway, just as food for thought, a slight variation on the above:
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
#include <iostream>
#include <iomanip>
#include <string>

using std::cout;
using std::endl;
using std::cin;

using std::string;
using std::getline;

//Function prototypes
bool getData(double aNum[], string aStr[], int i);
void showData(const double aNum[], const string aStr[], const int size);

int main()
{   
    const int MAXSIZE = 6;
    string aString[MAXSIZE]; 
    double aNumber[MAXSIZE]; 

    int count{}; 

    for ( ; count < MAXSIZE; ++count)
    {
        if (!getData(aNumber, aString, count))
            break;            
    }

    cout << "\nData stored in arrays:\n";
    showData(aNumber, aString, count);
}

bool getData(double aNum[], string aStr[], int index)
{
    cout << "Enter a number,or 0 to end: ";
    cin  >> aNum[index];
    cin.ignore(1000, '\n');     // Discard newline from cin buffer
    
    if (aNum[index] != 0)
    {
        cout << "Type a string (or press only Enter to exit): " << endl;
        getline(cin, aStr[index]);
    }
    
    return ((aNum[index] != 0) && (aStr[index] != ""));
} 

void showData(const double aNum[], const string aStr[], const int size)
{
    for (int i=0; i<size; ++i)
        std::cout << std::setw(8) << aNum[i] << "  " << aStr[i] << '\n';
}


Or another variation - I like trying things different ways, it can at very least make the code look cleaner. For me at least, the less busy-looking the code, the easier it can be to follow what it does.
main():
24
25
26
27
28
    for ( ; count < MAXSIZE; ++count)
    {
        if (!getData(aNumber[count], aString[count]))
            break;            
    }


Function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool getData(double& num, string& str)
{
    cout << "Enter a number,or 0 to end: ";
    cin  >> num;
    cin.ignore(1000, '\n'); 
    
    if (!num)
        return false;
        
    cout << "Type a string (or press only Enter to exit): " << endl;
    getline(cin, str);
    
    return str.size();
} 


or yet another variation, same as above, but for-loop in main() turned into a while-loop:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{   
    const int MAXSIZE = 6;
    string aString[MAXSIZE]; 
    double aNumber[MAXSIZE]; 

    int count = 0;
     
    while ( count < MAXSIZE && getData(aNumber[count], aString[count]) )
        ++count;    

    cout << "\nData stored in arrays:\n";
    showData(aNumber, aString, count);
}
Last edited on
@Chervil:
Hmm... boss!

Thanks for showing me better ways to go about the same thing by utilising elements of the code judiciously and avoid unnecessary repitition. Please, any other suggestions are gladly welcome.

Also, I plan on extending the program such that it gives the user more flexibility and control and I'll submit subsequent revisions for review before I finally approach it from an OOP (class) perspective.

By the way, I wanted to ask how you uploaded the code snippets such that they displayed the line numbers. I tried doing the same earlier but I'm yet to figure it out.

I really appreciate your help. Thanks
Last edited on
how you uploaded the code snippets such that they displayed the line numbers.

Use code tags. There's a formatting menu with a <> button for code and other options for bold text and so on. You can also type the tags yourself:

[code]your code here[/code]
Your mean somethng like this:
 
std::cout << "Goodbye World!" << std::endl;
Hello @Chervil:
Please I need your view on this:

http://www.cplusplus.com/forum/beginner/205757/#msg974138

Is this true?

Cheers!
Pages: 12