Here's a C++ function of mine:
void SetUserName(char username[])
{
cout << "\nPlease enter a username.\n"
<< "Must not be longer than 12 characters.\n>> ";
cin.getline(username, MAX) // MAX is globally defined
while(strlen(username) > MAX)
{
cout << "\nUsername too long, try again.\n>> ";
cin.getline(username, MAX);
}
}
Obviously, the while loop never works because the user input is truncated to 12 characters everytime.
How can I effectively determine if the user input was too long, and continue to loop until the conditions are met?
Edit: Using cstring here is a requirement. I already know how easy it is with strings.
Edit #2: This was definitely a fruitful question for me, as it taught me a lot. Final code: http://pastie.org/3537894
C-style terminated strings are rather tricky to work with, and in almost every case I'd recommend the C++ std::string instead. However, since you say you specifically want to read a terminated string into an array, here is one way to do it.
Remember that the array size must be MAX+1, so there's space for MAX characters followed by the terminator.
istream::getline sets the streams failbit flag if the line is too long; you can test this after reading. If only a partial line was extracted, and you want to move on to the next line, then you'll need to clear the error state, and ignore the rest of the line.
while (!std::cin.getline(buffer, MAX+1)) {
std::cout << "Too long\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Use proper C++ (in particular, strings and the free getline function):
#include <string>
#include <iostream>
std::string line;
while (std::getline(std::cin, line))
{
if (line.length() > 12)
{
// error, line too long
continue;
}
// process line
}
If you want to find out if std::istream::getline() read an array full of characters as demanded but not an end of line character you need to figure out whether the number of stored characters (minus the terminating null) is identical to the extracted characters. That is, the following determines if there are more then 12 characters on the line (the 13th character is needed for the terminating null):
#include <iostream>
#include <string.h>
int main()
{
char array[13];
if (std::cin.getline(array, 13).gcount() == strlen(array)) {
std::cout << "excess characters on the line\n";
}
}
If you next also want to remove the excess characters from the stream you'd use something like std::cin.ignore(std::numeric_limits<std::streamsize>::max());. Since this is tagged as C, too, I don't know off-hand how to do this with C but I'm pretty sure that there is something similar to gcount().
Actually, looking more closely at the spec std::istream:getline() actually sets std::ios_base::failbit if it doesn't encounter a newline while reading the character (it also sets std::ios_base:failbit when no character is read but it doesn't set std::ios_base::failbit if at least one character is read before end of file is reached). This mean, you also want to clear the stream before ignoring excess characters and you can work off std::ios_base::failbit and std::ios_base::eof():
#include <iostream>
#include <limits>
#include <string.h>
int main()
{
char array[13];
std::cout << "enter password: ";
while (!std::cin.getline(array, 13) && !std::cin.eof())
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "password is too long: enter max 12 chars: ";
}
std::cout << "the password is '" << array << "'\n";
}
Since std::ios_base::failbit is set you need to call clear() before you can use the stream for anything.
For the user to enter more characters than you allow, he must go at least one character over the limit. Since it does not matter to you by how many characters the user has "overstepped" your limit, you can pass MAX+1 as your limit, and see if the length is greater than MAX.
Of course you need to make enough space in the buffer to hold the 13-th character and a zero terminator. EDIT You also need to call ignore to skip to the end of the line on each failed attempt.
Related
I am new to c++ and still trying to wrap my head around how input/output streams work.
I am currently trying to write a function to make sure the user enters an int, and tell them if the input is empty or not a valid int.
I am using getline and have tried using cin.clear and cin.ignore but i cannot seem to get this to work and have no idea where i am going wrong.
It works if I input a letter however if i just press enter with nothing input it doesn't say no input detected.
void testStuff()
{
string number;
ws(cin);//skips Whitespaces
if (getline(cin, number) && number.end() !=
find_if_not(number.begin(), number.end(), &isdigit))
{
if (number.empty())
{
cout << "No input detected" << endl;
testStuff();
}
cout << "Please input a Valid number" << endl;
testStuff();
}
}
Assuming your ws works as specified (skips whitespace in the input), by the time you call getline, something other than whitespace has to have been entered. Thus, when getline gets called, that non-whitespace character has to be waiting in the input buffer, and getline must return a non-empty sequence of characters (i.e., everything from that first non-whitespace character up to the next new-line).
For example, let's write our own ws that shows what character(s) it's skipping over:
void ws(std::istream &is) {
while (std::isspace(is.peek())) {
char ch;
is.get(ch);
std::cout << "Read: " << (int)ch << '\n';
}
}
Now, when we call testStuff() and just press enter, we get Read: 10 as our output--i.e., ws has read and skipped the new-line we entered.
So, to get to the call to getline, the user has to enter something other than whitespace, and a new-line is whitespace. So, but the time getline is called at all, we know there's some non-whitespace character waiting in the input buffer, so when getline is called, it must produce a non-empty result.
I have assumed that every of function(s) that i don't know implementation are written correctly. Then, I have such code (simplified):
#include <iostream>
#include <string>
using namespace std;
int main() {
string number;
if (getline(cin, number))
{
if (number.empty())
{
cout << "No input detected" << endl;
main();
}
cout << "Please input a Valid number" << endl;
main();
}
}
I don't know find_if_not(number.begin(), number.end(), &isdigit) implementation so I skipped it. I've put source code on Ideone.com, you can view it HERE. After passing "just enter", program behaves vaildly. This means, one of function implementations that you didn't show us is working incorrectly. To help you we need full source code (if not, just only needed parts). Also, you should skip "using namespace std;". I think, number.end() != find_if_not(number.begin(), number.end(), &isdigit)) is implemented incorrectly. You should think about what someone told you in comments - "If the string is empty the only thing find_if_not can return is number.end(). number.end() == number.end() and body is not entered."
My question is based on this simple code:
#include <string>
using namespace std;
int main() {
string buf;
while (cin >> buf && !buf.empty()) {
cout << "input is " << buf << "\n";
}
return 0;
}
The operator>> of cin (which is an object of type basic_istream) reads and discards any leading whitespace (e.g. spaces, newlines, tabs). Then operator>> reads characters until the next whitespace character is encountered. The operators returns finally the stream itself, cin.
It shouldn't be possible to enter an empty string without also setting at least one of the iostates eof, fail or bad? And therefore the streams converts with the operator bool to false. I think !buf.empty() is here superfluous, but a good habit. Is there a way to leave the iostate of cin in good and leaving the string empty?
Example usage:
1. type in a word of your choice
2. press enter
3. press Ctrl+d (EOF on UNIX) or Ctrl+d (EOF on Windows)
Thank you
No, it is not possible. If no characters could be extracted std::ios::failbit is set. [string.io]/3:
If the function extracts no characters, it calls
is.setstate(ios::failbit), which may throw ios_base::failure.
And if characters could be extracted they are subsequently appended to the string and thereby make its size non-zero.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char name[256];
cout << "Enter your name: ";
cin.getline (name,256);
for(int i = 0; i < 50; i++)
{
cout << name[i];
if (name[i] == '\n')
break;
}
cout << endl;
return(0);
}
Enter your name: My name is Sean
once I do that it outputs "My name is Sean" but then a bunch of nonsense crazy symbols after that.
How come it doesn't stop after 'n' in Sean? Since there's a '\n' character there. Or at least I would think.
All, I want is to output every character in name one symbol at a time, and stop when it gets to the end of the line so that it doesn't have to go to 256 when the array is actually much smaller
What's wrong with my code?
cin.getline reads the newline (or whatever you specify as the delmiter) out of the input buffer, but does NOT include it in the string that's produced, so you're reading past the end of the data that was read until you encounter the next byte that happens to contain the value that corresponds to a new-line (typically 10).
It's a lot easier to just write it all together: cout << name;
From documentation:
Characters are extracted until either
(n - 1) characters have been extracted
or the delimiting character is found
(which is delim if this parameter is
specified, or '\n' otherwise). The
extraction also stops if the end of
file is reached in the input sequence
or if an error occurs during the input
operation.
If the delimiter is found, it is
extracted and discarded, i.e. it is
not stored and the next input
operation will begin after it. If you
don't want this character to be
extracted, you can use member get
instead.
If I have the following C++ code:
#include <iostream>
#include <string>
int main()
{
std::string str;
while (std::cin>>str)
std::cout<<str<<"\n";
std::cout<<str.length(); // UPDATE: str.length
return 0;
}
When I run the program and don't type a string and press Enter, I get an empty output. Does that mean that the while loop ran and considered that there is an input even it was empty?
How can I terminate this loop?
Finally, why don't I get the length of the string in my output?
UPDATE: I want to solve the issue using string functions
Thanks.
Because "enter" produces "carrier return" symbol. It is invisible and just starts the new line.
You can use an istream object and use get() function, which return the number of characters read:
char ch;
while(cin.get(ch))
{
}
Write the code this way and set a breakpoint in line 4:
std::string str;
while (std::cin >> str)
{
std::cout << "you typed: " << str << "\n";
std::cout << "str.length(): " << str.length() << "\n";;
}
In the while loop, std::cin>>str will return true if std::cin successfully read data into str, else it will return false.
Since std::cin can always read data from the input stream, that means, while(std::cin >> str) will be an infinite loop, unless you press some key that generates EOF character. The combination of keys that produces EOF, depends on OS.There is one more thing that can produce EOF, which is if you close the input stream!
The input:
std::cin>>str
Reads one [white] space separated word from the stream.
White space include (space/tab and new line).
This means it ignores all white space until it gets a non-white space character. It then reads characters until it gets a white space character.
Thus if you just hit newline (enter) it will ignore the character. It keeps ignoring until it gets to a word.
If you want to make the loop finish. You have two choices. Look for a special word. Or inject an EOF character into the stream. On Unix/Linux this is done with <ctrl>-D on WIndows <ctrl>-Z
I'm trying to write a program that returns the number of characters in a string. As I was writing my program, I've noticed that there's a bug in the string class.
Say my program is this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string input;
cout << "Input string: ";
cin >> input
cout << "Number of characters: " << input.size() << endl;
return 0;
}
If my input is Test String, I should see the number 11 as the output.
However, the output I get is this:
Number of characters: 4
It seems like the size() method does not work when there is space in the string.
My question is, is there another way to get the number of characters in a string? I tried length() method but the result was the same.
That's because your
cin >> input;
only reads up to the first whitespace character.
If you want to get the a whole line, use the following code:
std::string s;
std::getline(std::cin, s);
This is not a bug, and more particularly, actually has nothing to do with the string class.
It has to do with the istream class (cin). cin's operator>> performs "formatted input," which is to say, input delimited by whitespace. After you hit enter, you read out "Test" into a string, leaving "String" in the input buffer. "Test" is, in fact, four characters long.
Consider using std::getline or istream::getline to read entire lines of input with more control. Be sure to read the documentation for these methods carefully, as they have different behavior with respect to what is left in the input stream which can then cause results you may not expect if mixed together with oeprator>> usage.
This is a result of the meaning of cin >> input, which stops reading when any whitespace is found. If you want to keep reading until the end of a line, try getline.
After taking input correctly, you can get the length of the string or char pointer(char*)(including whitespaces) by using strlen(string_name), this will return the length.