I would like to get rid of everything after the first char of a user input.
Everything is working fine, but I'm handling edge cases and if a user types something for example 'nfff' it would cause two functions to occur, when 'n' is entered as an input and when 'f' is entered as an input. I am aware that this can be solved using if (str[0] == 'n') { function() }, but I'd rather not use more memory with string.
Is there a more efficient way to discard everything after the first character?
You can use scanf or getchar.
For example,
char my_char;
scanf("%c", &my_char);
So, this will ignore everything after the first character.
#include <iostream> // std::cin, std::cout
#include <fstream> // std::ifstream
int main () {
char str[2];
std::cout << "Enter str ";
std::cin.get (str,2); // get c-string
std::cout <<str<<std::endl;
return 0;
}
Use istream::get to do the trick! Size of 2 will make sure that str is null terminated.
Related
#include <iostream>
#include <cstring>
using namespace std;
const int BUFFER_SIZE = 80;
void getstr(char* &str);
int main()
{
char* str;
while(true)
{
getstr(str);
if (!strlen(str))
break;
}
delete [] str;
return 0;
}
void getstr(char* &str)
{
char temp[BUFFER_SIZE];
cout<<"Enter a string(empty line to quit): ";
cin.get(temp, BUFFER_SIZE);
while(cin.get()!='\n')
continue;
str = new char [strlen(temp)+1];
strcpy(str, temp);
}
I have a string reading loop above and entering an empty line to terminate the loop doesn't work(after entering an empty line program stops responding to any input). But when I replace a loop in getstr with single cin.get() all works fine. What's wrong?
istream::get() sets failbit when empty string is read.
This makes cin.get() return EOF and this because you couldn't break the loop while(cin.get()!='\n').
You can use ios::clear() to clear failbit.
cin.get(temp, BUFFER_SIZE);
cin.clear(); // add this
while(cin.get()!='\n')
continue;
cin.get(char* s, size_t n) Extracts characters from the stream and stores them in s as a c-string, until either (n-1) characters have been extracted or the delimiting character is encountered: the delimiting character being either the newline character ('\n') or delim (if this argument is specified).
The delimiting character is not extracted from the input sequence if found and remains there as the next character to be extracted from the stream (see getline for an alternative that does discard the delimiting character).
A null character ('\0') is automatically appended to the written sequence if n is greater than zero, even if an empty string is extracted.
So here is the problem. cin.get() need to read at least 1 character. You can close stdin by pressing Ctrl+D and Enter, after that, your program will be finished.
And BTW, you are using new N times, but you have only 1 delete. You need to delete the previous buffer
If you are going to use C++, you should really use cin/cout in an objectively consistent manner. For example:
string name;
cout << "What is your name: ";
getline (cin, name);
cout << "Your name is: " << name;
What you are doing is kind of a C/C++ hybrid (char arrays in leu of string objects, but using std namespace).
Now, I know this isn't your question, but what you are doing right now is slightly unorthodox which makes answering your question a bit difficult without putting the code in to and editor and debugging it.
Given the c++11 tag, I assume that you really want C++ code. The great thing is that C++ simplifies this a lot.
#include <iostream>
#include <string>
int main()
{
std::string str;
while(std::getline(std::cin, str) && !str.empty())
{
// do stuff
}
return 0;
}
I am a beginner in c++ and I want to enter a string as character by character into an array , so that I can implement a reverse function .. However unlike C when the enter is hit a '\n' is not insterted in the stream.. how can I stop data from being entered ?
my code is :
#include<iostream>
#include<array>
#define SIZE 100
using namespace std;
char *reverse(char *s)
{
array<char, SIZE>b;
int c=0;
for(int i =(SIZE-1);i>=0;i--){
b[i] = s[c];
c++;
}
return s;
}
int main()
{
cout<<"Please insert a string"<<endl;
char a[SIZE];
int i=0;
do{
cin>>a[i];
i++;
}while(a[i-1]!= '\0');
reverse(a);
return 0;
}
When you read character by character, it really reads characters, and newline is considered a white-space character.
Also the array will never be terminated as a C-style string, that's not how reading characters work. That means your loop condition is wrong.
To begin with I suggest you start using std::string for your strings. You can still read character by character. To continue you need to actually check what characters you read, and end reading once you read a newline.
Lastly, your reverse function does not work. First of all the loop itself is wrong, secondly you return the pointer to the original string, not the "reversed" array.
To help you with the reading it could be done something like
std::string str;
while (true)
{
char ch;
std::cin >> ch;
if (ch == '\n')
{
break; // End loop
}
str += ch; // Append character to string
}
Do note that not much of this is really needed as shown in the answer by Stack Danny. Even my code above could be simplified while still reading one character at a time.
Since you tagged your question as C++ (and not C) why not actually solve it with the modern C++ headers (that do exactly what you want, are tested, save and work really fast (rather than own functions))?
#include <string>
#include <algorithm>
#include <iostream>
int main(){
std::string str;
std::cout << "Enter a string: ";
std::getline(std::cin, str);
std::reverse(str.begin(), str.end());
std::cout << str << std::endl;
return 0;
}
output:
Enter a string: Hello Test 4321
1234 tseT olleH
Somehow when I run this code and it comes to inputting strings, the first string where i=0 is being skipped and it starts entering strings from A[1]. So I end up with A[0] filled with random stuff from memory. Can someone please point at the problem?
cin>>s;
char** A;
A = new char *[s];
cout<<"now please fill the strings"<<endl;
for (int i=0;i<s;i++)
{
A[i] = new char[100];
cout<<"string "<<i<<": ";
gets(A[i]);
}
That code is horrible. Here's how it should look like in real C++:
#include <string>
#include <iostream>
#include <vector>
int main()
{
std::cout << "Please start entering lines. A blank line or "
<< "EOF (Ctrl-D) will terminate the input.\n";
std::vector<std::string> lines;
for (std::string line; std::getline(std::cin, line) && !line.empty(); )
{
lines.push_back(line);
}
std::cout << "Thank you, goodbye.\n";
}
Note the absence of any pointers or new expressions.
If you like you can add a little prompt print by adding std::cout << "> " && at the beginning of the conditional check in the for loop.
Probably because you're using gets()... never use gets()
Use fgets() instead.
gets vs fgets
The problem is that cin>>s; just picks up the number you want and leaves a \n (newline from the enter press) on stdin that gets() picks up in the first iteration. This is not the nicest way to fix it, but to prove it write this line after that line:
int a = fgetc(stdin);
Check out a afterwards to confirm it has a newline.
Well, you probably get an empty string: when reading s you use formatted input which stops as soon as a non-digit is encountered, e.g., the newline used to indicate its input is finished. gets(), thus, immediately finds a newline, terminating the first string read.
That said, you shall never use gets(): It is a primary security problem and the root cause of many potential attack! You should, instead, use fgets() or, better, yet, std::getline() together with std::strings and a std::vector<std::string> >. Aslo, you should always verify that the attempt to input was successful:
if ((std::cin >> s).ignore(std::numeric_limits<std::streamsize>::max(), `\n`)) {
std::string line;
for (int i(0); i != s && std::getline(std::cin, line); ) {
A.push_back(line);
}
}
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.
I'm having an unpleasant problem with my c++ example. Everything works fine until I enter something with a whitespace.
#include <iostream>
using namespace std;
int main (int argc, char * const argv[])
{
int iteration = 0;
while (true) {
char * input = new char[256];
scanf("%s", input);
cout << ++iteration << ": " << input << endl;
cin.get();
}
return 0;
}
So with this code, I can enter anything, but everything after whitespace is somehow like stored in buffer and used in the second iteration.
foo
1: foo
bar
2: bar
foobar
3: foobar
foo bar
4: foo
5: bar
Every single input reading function acts like this and it's driving me crazy. cin >> input, freads(), cin.get() etc. all do this.
It this frequent problem with user input, or am I doing something wrong here?
First of all, never use scanf. It's difficult to use that function and avoid buffer overflows. Replace input with a std::string, and read from std::cin.
Both scanf("%s", input) and cin >> input will read one word, delimited by whitespace. If you want to read a whole line, then use getline(cin, input).
About scanf %s format specifier:
This will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab).
About istream::operator>> with str parameter:
Extraction ends when the next character is either a valid whitespace or a null character, or if the End-Of-File is reached.
So yes, this is standard behaviour for these functions.
Maybe try using std::getline instead?
http://www.cplusplus.com/reference/string/getline/