I am having a problem, but I cannot figure out what I'm doing wrong. I'm not sure if it's a problem with my loop, or the cin buffer is not being cleaned. I am doing a program that transforms a C-style string to uppercase, however if the user enters more than 11 characters, then the function should only display the first 11, and anything after that should not be displayed.the problem is that if I enter more than 11 characters, then my loop never stops and keeps telling the user that the answer entered is invalid and if he would like to enter a new string.
The issue comes from when you're trying to clear your buffer. When you return from cStringToUpper there are still extra characters in your buffer, but you're immediately looking for y/q.
You give cin.getline a buffer 12 long so it will only take that many characters, the rest are still in the buffer. If you instead use
string str;
cin.getline(str)
Then you will get the whole line, then you can crop it at 11 characters. Not 100% on the cin-syntax but you get the idea.
Or move the ignore-part above
cin >>cont;
to ignore the extra characters that way.
cin >> cont;
cout << "\n" << endl;
cin.ignore(200,'\n');
should be
cin.ignore(200,'\n');
cin >> cont;
cout << "\n" << endl;
You may correct your program by modifying your cStringToUpper fn. something like:
...
int loopCount;
char buffer[256];
cin.getline(buffer,256);
strncpy(letters, buffer, 11);
//letters[11]= '\0';
cout << "\n" << endl;
...
Related
I'm pretty new to coding so I apologize if this is trivial. I'm supposed to create an error message when the user enters more characters than my const int SIZE2 array, which is 20 characters.
My array is called major:
>cout << "Enter your major: " << endl << endl;
>48 cin.width(SIZE2);
>49 cin.get(major,SIZE2, '\n');
>50 majorLength = strlen(major);
>51
>52 if(majorLength > SIZE2)
>53 {
>54 cout << "Too many characters, Enter major again: " << endl;
>55 cin.get(major, SIZE2, '\n');
>56 cin.ignore(100, '\n');
>57
>58 }
It's compiling just fine but skipping over my if-statement.
iostream.get() (here invoked as cin.get()) reads an exact number of bytes and then ends. In your case, it will specifically never read more than SIZE2 bytes into major; as a result, if(majorLength > SIZE2) will always be false. Also, if you enter too many bytes, major will only have the first 20 - the rest are truncated. (FWIW, your code is only matching 19 characters right now.)
Note that you probably shouldn't try to do this - there's not really a good way to check the length of a stream before you read it, and if you decide to just read it all and then check its size, you run the risk of overflowing your buffer - assuming it's fixed size.
You can, however, determine if, after reading, the buffer is empty or not. To determine if there is any more input in the buffer beyond SIZE2, you can capture one character with std::cin.get() and then examine this character. If the character is \n, it means there was no more input in the buffer; if it is not, that means the character buffer had too much input in it. This will also trigger if the input is completely blank.
#include <iostream>
int main () {
int SIZE2 = 20;
char str[SIZE2];
char c;
std::cin.get (str, SIZE2+1); // get c-string of 20 chars
std::cin.get(c); //get last buffer character
if(c != '\n') {
std::cout << "bad input!" << std::endl;
}
std::cout << str << std::endl;
return 0;
}
Demo
I am creating a console version of "Bull Cow Game". In the game, the user has a certain number of tries to guess what the secret word is. Every time they guess, the program returns the number of "Bulls" and "Cows" they guessed correctly. The user gets a "Bull" for every character that they guess in the right place and a "Cow" for every character that they guess correctly but is not in the right place.
My problem is in my getGuess() function. In the do-while loop, the program is supposed to loop if the user inputs anything other than the number of characters in "answer". When I run my program, I get some unexpected and confusing results:
1) No matter what I input for the first "guess", the program tells me that cin's gcount() is 0 or 1 characters after setw(). I could input 50 characters or 2 and the program would output the same result. If the gcount is 1, then this counts as one of the allotted guesses which is an undesirable result. If the cin.gcount() is 0, the program correctly does not count the guess as valid but I am still confused as to why the cin.gcount() is 0 at all.
2) If I change the number of characters in my guess from the previous guess, the program tells me that the cin.gcount() is whatever the cin.gcount() was after the previous guess instead of after the current guess. This is also an undesirable result since if the user decides to input the correct number of characters, the program will not accept the user's guess as valid.
I am confused as to why this is happening since isn't cin.ignore() supposed to dump all of the extraneous characters that setw() doesn't accept? Why would the number of characters in the cin buffer carry over from one guess to the other?
Here is the function in question:
string getGuess()
{
string guess = "";
const int MAX_LENGTH = 4;
/*ensures that "guess" is the same length as answer. This
will make it so that the program avoids comparing "guess"
to "answer" if "guess" has more characters than "answer".
This do-while loop also ensures that a user can't overflow
the cin buffer by theoretically inputting more characters
than the buffer could contain*/
bool endLoop = false;
do {
cout << "Enter a word containing exactly " << MAX_LENGTH << " characters: ";
cin >> setw(MAX_LENGTH) >> guess;
cout << "cin.gcount() after setw(): " << cin.gcount() << " characters" << endl;
/*ensures that the only character in the cin is '\n'. Otherwise
do-while loop continues*/
if (cin.gcount() != 1)
{
cout << "Invalid number of characters. Please input exactly " << MAX_LENGTH
<< " characters" << endl;
}
else
{
endLoop = true;
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "cin.gcount() after cin.ignore(): "
<< cin.gcount() << " characters" << endl;
cout << "guess: " << guess << endl;
cout << endl;
} while ( endLoop == false );
cout << endl;
return guess;
}
Note: This was compiled with Microsoft Visual C++, ISO standard c++17.
A couple of misunderstandings I think
1) gcount only tells you how many characters have been read after an unformatted input operation, cin >> guess is not an unformatted input operation.
2) setw on input does not limit the numbers of characters read. If less than the specified width characters are read then the input is padded to make it equal the given width, but it does not stop more characters being read.
Your code is too tricky, forget about fancy I/O operations, do it the straightforward way. Just read a line of characters into a string using getline and check if the characters entered are what you expect. For instance remove the spaces at the beginning and end of that string, then check for internal spaces and finally check if the string is the length you require.
I am trying out dynamic memory allocation. I want to dynamically allocate memory, enough for a string of 10 characters. If the user inputs more than 10, I only want 10 characters pulled in getline (plus the newline character, I suppose) and subsequently stored in correct size dynamic memory, printed, and deleted. Below is my code:
#include <iostream>
using namespace std;
int main() {
char cont = 'N';
do{
char *input = new char[11];
cout << "This program dynamically allocates memory for a string of
characters up to 10 in length\n";
cout << "Enter a string less than or equal to 10 characters:\n";
cin.getline(input, 11, '\n');
cout << "Your string is:\n";
cout << input << endl << endl;
delete input;
cout << "Would you like to enter another? \"Y\" to continue\n";
cin >> cont;
cin.ignore();
} while (toupper(cont) == 'Y');
Everything works fine if the user inputs up to 10 characters. It can repeat forever.
However if the user inputs more than 10 characters the program does not prompt the user to continue and instead just ends. ABCDEFGHIJ works but ABCDEFGHIJK breaks.
I thought this is because there is still something in cin that is being read in to input, which is not 'Y' and the program therefore ends. However if you go through one loop and set cont to 'Y' first, and then input ABCDEFGHIJK, the program goes infinite without ever inputting anything to overwrite 'Y'.
Another thing I noticed is getline seems to pull the correct amount of characters it stores characters ABCDEFGHIJ in input, even if ABCDEFGHIJK was entered.I thought perhaps 'K' was left in cin, so I tried ABCDEFGHIJY but 'Y' was not saved in to cont.
I also tried various cin.clear() variations before the next prompt for input, and nothing worked.
I think I am misunderstanding how getline works with the overload I am using.
First let me tell you, that doing this with a string is a ton easier, but if you want to do it the hard, allocating way...
Problem:
When you read with std::cin, and some condition isn't met, for example, reading a string as an int, or running out of specified characters, the failbit is set. This makes your istream look crazy
Fix:
Put a check after the getline call, test if the fail bit is set, if it is, reset the flags.
/* ... */
cin.getline(input, 11, '\n'); // Read input
if ( cin.fail() ) { // Check if getline failed
// -- > Remind the user of the limits here < --
// Clear flags
cin.clear();
cin.ignore();
}
/* ... */
Your getline variation has the arguments: char_type * Output, std::streampos MaxLength, char_type Delimeter. Sets failbit if the number of bytes to read is greater than the maximum length (AFAIK).
Sources:
std::basic_istream::fail()
std::basic_istream::getline()
Wish luck with your dynamic allocations, COlda
I'm practicing with c string / pointers and can't solve this simple problem. cin.getline() isn't prompting user input for the first iteration, but does so for the consecutive strings. (I arbitrarily chose 10 as the char limit).
Am I overlooking something extremely simple?
void getStrings() {
int num;
cout << "How many strings? ";
cin >> num;
const int numStrings = num;
char** stringSet = (char**) malloc(numStrings * sizeof(char*));
for (int i = 0; i < numStrings; i++) {
*(stringSet + i) = (char*) malloc(10);
cout << "String " << i << ": ";
cin.getline(stringSet[i], 10);
cout << endl;
}
Setting aside the fact that it's generally inadvisable to use bare pointers in C++ when things like the standard library's std::string are available, you should not use malloc. For example: Instead of (char*) malloc(10), you should write new char[10] and remember to delete[] *(stringSet+i) at the end of your program.
That said, the line:
cin >> num
... extracts only the first number it comes across. It will fail (and cin will set its fail bit, and will need to be reset with cin.reset()) if it encounters any non-whitespace characters before it encounters a number.
But it stops extracting from the input after that. In your input stream is still whatever whitespace or other characters were still present in your input. For example, if you ran this program and typed "2 foobar" before pressing enter, it would immediately print:
String 1: foobar
String 2:
This is because the stream still contains "foobar\n".
In order to get the behavior you're looking for you will probably want to add this before your loop:
cin.ignore();
That will clear the stream of anything that's there.
cin >> num;
This will prompt the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key. The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key. cin will parse the digits to produce an integer, which it stores in the num variable. It stops at the newline character, which remains in the input buffer. Later, you call getline, which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input. So it appears that the first call to getline didn't do anything, but actually it did.
What do you mean by " isn't prompting user input for the first iteration"? I read that to mean "isn't printing the prompt for the input of the first string", but based on your code, I think it means "is printing the prompt for the input of the first two strings before it reads input."
cin >> num reads a number, the whole number, and nothing but the number. It does not read whatever follows the number, like a newline. So the first getline reads the newline character which you've already typed.
By the way, you should use cerr instead of cout for user prompts.
cout should be reserved for actual output. That makes scripting much easier, because you can redirect cout independent of cerr, and because you don't want to capture prompts in the program results anyway.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Need help with getline()
I'm trying to use the getline function in conjunction with cin to get input from the keyboard but my code skips over the getline statement and instead proceeds to cin function below. Here is my code and a screenshot of what is happening.
void addmovie(ofstream& MovieContentsFile) {
string movieTitle;
int movieQuantity;
cout << " \n Add Movie Selected \n " << endl;
cout << "Please type in the movie title and press enter \n" << endl;
getline(cin,movieTitle, '\n');
cout << "Movie: " << movieTitle << "Please type in the amount of copies we have of this movie \n " << endl;
cin >> movieQuantity;
I'd appreciate an explanation of why this is happening and how I can avoid it in the future
cin >> something leaves the trailing newline in the buffer, which would be ignored by the next cin >> something_else (presumably this is how you read the menu option). However, getline gets everything up to and including the next newline in the buffer, not ignoring whitespace. I.e. it gets nothing in this case (well, just the newline character).
Generally it's best not to mix use of both, it can get kinda messy.
Edit: To clarify, getline will remove that last newline from the buffer, but won't store it in your string.
It's because the newline character is still in the buffer so when it gets to the getline it sees it and skips over it. To avoid this you could place something like cin.ignore(25, "\n") on the line before. This will ignore 25 characters until it gets to the newline and then it takes that as well.