How To Stop C++ From Repeating Itself? [duplicate] - c++

This question already has answers here:
std::cin input with spaces?
(8 answers)
How to read a file line by line or a whole text file at once?
(9 answers)
Closed 1 year ago.
Sorry for the poor question but I really do not know what is happening.
while (true) {
string choice;
cout << ">>> ";
cin >> choice;
if (choice == "hi") {
cout << "Whats up?" << endl;
} else {
cout << "error" << endl;
}
}
If I compile this and then input "hi" it will show
>>> hi
Whats up?
>>>
but if I do "hi hi"
>>> hi hi
Whats up?
>>> Whats up?
>>>
It will show that. Why is it showing Whats up? twice instead of the error message?

The problem is that std::cin is used to read either a number that is compatible with the type of the variable, or a single word at a time.
Technically, you're using formatted input operator>> which discards leading whitespace and will also stop reading when it encounters a whitespace/invalid input.
To solve this, replace cin >> choice; with:
std::getline(cin, choice);
This will read until '\n' is encountered, and now we're using unformatted input.
So, the modified code looks like:
while (true) {
string choice;
cout << ">>> ";
std::getline(cin, choice);//i modified this
if (choice == "hi") {
cout << "Whats up?" << endl;
} else {
cout << "error" << endl;
}
}
You can try out the code here.

As soon as std::cin reads a space character (this ' '), it won't consider any more characters that come after that space char as part of the input. So the next time it reads the buffer it will read the second "hi" and insert it to choice. It is like you're entering "hi" and pressing enter key and then doing it again. You will see "Whats up?" being printed twice.
Use std::getline(std::cin, choice); to get the full input even if there are space or tab characters in between the other characters.
If you want something more error-safe then this function might be helpful:
#include <iostream>
#include <limits>
void getCharInput( char arr[], const std::streamsize streamSize )
{
std::cin.putback( '\n' );
std::cin.clear( );
std::cin.ignore( std::numeric_limits<std::streamsize>::max( ), '\n' );
std::cin.getline( arr, streamSize );
}
int main()
{
constexpr std::streamsize streamSize { 11 }; // 11 as an example ( 10 for actual chars plus 1 for '\0' )
char inputBuffer[ streamSize ] { };
getCharInput( inputBuffer, streamSize );
std::cout << "Input is: <" << inputBuffer << ">" << '\n';
}
Only 11 chars (including the null-terminator '\0') will be read and stored in inputBuffer.

Related

How to terminate the '\n' for std::cin.get() [duplicate]

This question already has answers here:
std::cin input with spaces?
(8 answers)
Closed 5 years ago.
I would like to know how to get rid of the '\n' for when I execute cin.get(). For example:
#include <iostream>
int main() {
std::cout << "How many pieces of c: ";
struct c{
std::string name;
int val;
};
int amount;
std::cin >> amount;
c * c1 = new c[amount];
std::cin.get();
for(int i = 0; i < amount; i++){
std::cout << "C Number " << i + 1 << ":" << std::endl;
std::cout << "Please enter the name: ";
c1[i].name = std::cin.get();
std::cout << "Please enter the val: ";
std::cin >> c1[i].val;
std::cin.get();
}
return 0;
}
I've tried using cin.get() to eliminate the '\n' thats last read after my std::cin, but my program only takes in the first name and then executes the rest of the program without letting me continue to type the rest of the name and val values. In short, I want to be able to store the rest of my name and val values. Thanks!
c1[i].name = std::cin.get();
I'm not sure why you used get() instead of operator >>, like you did two lines later. get() reads a single character - meaning, only the first character you type in is saved as name. Everything else is read (most likely unsuccessfully) into val, and then new line character is, just like you intended, digested by the final get().
For reading int, try using getline and stringstream:
std::string input(5, '\0');
int number;
std::getline(std::cin, input);
std::stringstream sstrm(input);
sstrm >> number;
For a name: You can directly use getline
std::string name(30, '\0');
std::getline(std::cin, name);

(C++) How can I use getline() with an integer while reading a file?

I'm trying to create some code to open a file, read the content and check if a couple of integers are equal by using getline(). The problem is that it seems to work only with strings, instead of doing it with integers aswell. Could you help me?
fstream ficheroEntrada;
string frase;
int dni, dnitxt;
int i=0;
int time;
cout << "Introduce tu DNI: ";
cin >> dni;
ficheroEntrada.open ("Datos.txt",ios::in);
if (ficheroEntrada.is_open()) {
while (! ficheroEntrada.eof() ) {
getline (ficheroEntrada, dnitxt);
if (dnitxt == dni){
getline (ficheroEntrada, frase);
cout << dni << " " << frase << endl;
}else{
getline (ficheroEntrada, dnitxt);
}
}
ficheroEntrada.close();
}
getline() member function is used to extract string input. So it would be better if you input data in form of string and then use "stoi" (stands for string to integer) to extract only integer values from the string data.
You can check how to use "stoi" seperately.
getline doesn't read an integer, only a string, a whole line at a time.
If I understand correctly, you are searching for the int dni into the file Datos.txt. What is the format of the file ?
Assuming it looks something like this:
4
the phrase coressponding to 4
15
the phrase coressponding to 15
...
You can use stoi to convert what you've read into an integer:
string dni_buffer;
int found_dni
if (ficheroEntrada.is_open()) {
while (! ficheroEntrada.eof() ) {
getline (ficheroEntrada, dni_buffer);
found_dni = stoi(dni_buffer);
if (found == dni){
getline (ficheroEntrada, frase);
cout << dni << " " << frase << endl;
}else{
// discard the text line with the wrong dni
// we can use frase as it will be overwritten anyways
getline (ficheroEntrada, frase);
}
}
ficheroEntrada.close();
}
This is not tested.
C++ has two type of getline.
One of them is a non-member function in std::string. This version extracts from a stream into a std::string object getline. Like:
std::string line;
std::getline( input_stream, line );
The other one is a member function of an input-stream like std::ifstream and this version extracts from the stream into an array of character getline like:
char array[ 50 ];
input_stream( array, 50 );
NOTE
Both versions extracts characters from a stream NOT a real integer type!
For having an answer to your question, you should know what type of data you have in your file. A file like this: I have only 3 $dollars!; when you try to read that, by using std::getline or input_stream.getline you cannot extract 3 as in integer type!. Instead of getline you can use operator >> to extract a single data one-by-one; like:
input_stream >> word_1 >> word_2 >> word_3 >> int_1 >> word_4;.
Now int_1 has the value: 3
Practical Example
std::ifstream input_stream( "file", std::ifstream::in );
int number_1;
int number_2;
while( input_stream >> number_1 >> number_2 ){
std::cout << number_1 << " == " << number_2 << " : " << ( number_1 == number_2 ) << '\n';
}
input_stream.close();
The output:
10 == 11 : 0
11 == 11 : 1
12 == 11 : 0

C++ User defined string needs to contain spaces (but not allowed by program..?)

I'm working on homework for my c++ class, and it's been quite awhile since I've used it. I was wondering if there was a way to allow spaces in a string (instead of it nulling out and ending the string)
my current code is this:
int chapter10() {
string strinput;
char charstr[1000];
int numwords=1;
cout << "Enter a phrase ";
cin >> strinput;
cout << strinput;
const int size = strinput.size() + 1;
strcpy_s(charstr, strinput.c_str());
cout << strinput << endl;
for (int i = 0; i != size; i++) {
if (*(charstr + i) == ' ')
numwords++;
}
cout << "There are " << numwords << " words in that string." << endl;
return 0;
}
The problem I'm having, is for instance, if I type "Hello World" and press enter, it pops the next line (right after the cin) and says "Hello", and the space made it cut the rest of the phrase off.
How does one fix this issue? I don't want to use the str:: things as I barely know what they are, and have really never had to use them, and that would look a bit suspicious to the teacher :P
Update: If you've suggested using getline(cin, strinput); It doesn't work too well. I can from what I see, only type in the 10 to reach my function, but after I press enter, it thinks that I've presses something else, which makes it completely skip the cin to get the string value. But, there is something weird with this, if I type "10 hello world" it does everything correctly. Well, with the exception that it needs to be in the same line as the number to reach the function.
Solved: The use of getline(cin, strinput) works perfectly fine, if you're not using user input before hand. If you are, you're going to need a cin.ignore before the getline(). As stated in the comment by my best answer.
#include <iostream>
#include <iomanip>
#include <string>
#include <limits>
using namespace std;
//~~~Initialize all functions
int chapter10();
//~~~Initializing complete
int main() {
srand(time(0)); //makes rng thingy work instead of choose same numbers cause it doesn't do it on its own. lol
cout << "Enter the chapter number you need to look at: ";
int chapterNumber;
cin >> chapterNumber;
switch (chapterNumber) {
case 1: testingStuff(); break;
case 9: chapter9(); break;
case 10: chapter10(); break;
default: cout << "You chose an invalid chapter number, reload the program."; break;
}
system("pause");//So console doesn't close instantly cause that's not annoying at all...
}
int chapter10() {
string strinput;
char charstr[10000];
int numwords=1;
cout << "Enter a phrase." << endl;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
getline(cin, strinput);
const int size = strinput.size() + 1;
strcpy_s(charstr, strinput.c_str());
for (int i = 0; i != size; i++) {
if (*(charstr + i) == ' ' & *(charstr + (i+1)) != ' ' )//the & is fail safe so multiple space no ++numwords
numwords++;
}
cout << "There are " << numwords << " words in that string." << endl;
return 0;
}
The way I have my code written was I used a switch/case to reach my function. This required user input, which in turn caused my program to 'think' I was still typing for the second input required in the chapter10 function.
Adding in the line of code: cin.ignore(numeric_limits<streamsize>::max(), '\n'); allowed me to cancel the input, and start a new one.
If you want to get all characters an end-user enters on a single line, use getline: instead of cin >> strinput write this:
getline(cin, strinput);
The fact that it is actually std::getline(std::cin, strinput) makes no difference, because your code uses std namespace anyway. In case you were wondering what std:: prefix is, it's a namespace of the Standard C++ library.
You can use getline() function
It copies into a string till a newline is reached or delimiter is found - so it will accept all the spaces till newline is reached
http://www.cplusplus.com/reference/string/string/getline/
or you can also use cin.getline() as shown here -
std::cin input with spaces?
use:
cin >> noskipws >> strinput;
Use std::getline() function. Example:
#include <iostream>
#include <vector>
#include <sstream>
void WordCounter(
const std::vector<std::string> & lines) {
for (int i = 0; i < lines.size(); ++i) {
std::istringstream iss(lines[i]);
std::string word;
int count = 0;
while (iss >> word) {
++count;
}
std::cout << "Line #" << i << " contains " << count << " words." <<
std::endl;
}
}
int main() {
std::string line;
std::vector<std::string> lines;
while (std::getline(std::cin, line)) {
lines.push_back(line);
}
WordCounter(lines);
return 0;
}

C++ String Input as if/else statement condition

I saw a similar question to mine: C++ string variables with if statements
The only difference between his situation and mine is that I would like the condition to be if a string with a space is matching a certain string.
Here is my code:
#include <iostream>
#include <string>
int main()
{
using namespace std;
string input1;
cout << "Welcome to AgentOS V230.20043." << endl;
cout << "To log in, please type \"log in\"" << endl;
cin >> input1;
if (input1 == "log in")
{
cout << "Please enter your Agent ID." << endl;
}
return 0;
}
For some reason, the if statement is not picking up the string. However, if the conditions is:
if (input1 == "login"
It works. I cannot find a way to use a string with a space in it with a condition. I am wondering if maybe the if statement is okay but that the cin is deleting the space.
Thank you!
You should use standard function std::getline instead of the operator >>
For example
if ( std::getline( std::cin, input1 ) && input1 == "log in" )
{
std::cout << "Please enter your Agent ID." << std::endl;
}
cin >> ignores whitespace, use getline:
getline(cin, input1);
You need to read the entire line with spaces with std::getline, it will stop when finds a newline \n or N-1 characters. So, just do the reading like this:
cin.getline( input1, N );
Where N is the max number of character that will read.

C++ STD Cin error in while loop

Why when I entered the loop below and I type something the first instruction
cmdstd:getline(std::cin,cmdInput); does not read the input entered. For instance if I entered "b 8" it should display "cmd is b 8", but it skips to the next read std::getline(std::cin, input); and displays "it is b" instead
while (editingMode == TRUE) {
std::getline(std::cin, cmdInput);
istringstream cmdiss(cmdInput);
cout << "you entered: " << cmdInput <<endl;
if (cmdInput != "") {
copy(istream_iterator<string>(cmdiss),
istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
std::cout << "cmd is " <<tokens.at(0) << std::endl;
}
//*************************
std::getline(std::cin, input);
istringstream iss(input);
if(input != ""){
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
std::cout << "it is " << tokens.at(0) <<std::endl;
createInstruction(tokens);
}
Perhaps you have a newline character left in the input buffer, from an earlier input? This is a common error.
Lets say that your program first reads an integer with cin >> x, and then a line with getline(cin, cmdline). The user types an integer, followed by the ENTER key. The cin >> x will read the integer, but the ENTER key, interpreted as a newline character, will be left in the input buffer.
When your program then goes on to read a complete line with getline(cin, cmdline), it will read the very short line that consists of just that left-over newline character. This looks like the program "skips to the next read".
There's nothing wrong with the code. It just doesn't do what you think it should :) If you want to print the whole line entered rather than the first word, don't print tokens[0]; print the input line.
Both sections do the same thing:
read a line into a string
create an istream from that line
read the words from that istream into an array of strings called 'tokens'
print the first word
tokens.at(0) is the first word, obviously. check tokens.size() or iterate over tokens if you want to look for arguments like "8".
are you sure editingMode is TRUE?
The problem is mixing >> extractions with getline, leaving a newline (or other input) in the buffer. Blindly using ignore will hide logic errors, such as input of "42 abc" followed by cin >> some_int; cin.ignore(...);. What you really have to do is "extract" the blank line:
int main() {
using namespace std;
int n;
string s;
cout << "Enter a number: "
cin >> n >> blankline; // <---
if (cin) {
cout << "Enter a line of text: ";
getline(cin, s);
}
if (!cin) {
clog << "Sorry, I can't do that.\n";
return 1;
else {
cout << "Input successful, now processing values: " << n << s << '\n';
}
return 0;
}
Thankfully, this is easy:
template<class C, class T>
std::basic_istream<C,T>&
blankline(std::basic_istream<C,T>& s,
typename std::basic_istream<C,T>::char_type delim) {
if (s) {
typename std::basic_istream<C,T>::char_type input;
if (!s.get(input) && s.eof()) {
s.clear(s.eofbit);
}
else if (input != delim) {
s.putback(input);
s.setstate(s.failbit);
}
}
return s;
}
template<class C, class T>
std::basic_istream<C,T>& blankline(std::basic_istream<C,T>& s) {
blankline(s, s.widen('\n'));
return s;
}