Using while(cin>>x) [duplicate] - c++

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
C++ cin whitespace question
I'm having problem trying to understand this piece of code. I'd like to apologize if this question has already been answered but I didn't find it anywhere. I'm a beginner and its a very basic code. The problem is >> operator stops reading when the first white space
character is encountered but why is it in this case it outputs the complete input string even if we have white spaces in our string. It outputs every word of the string in separate lines. How is it that cin>>x can take input even after the white space? Plz help me out with the functioning of this code. Thanks in advance.
#include<iostream>
#include<string>
using std::cout;
using std::cin;
using std::string;
using std::endl;
int main()
{
string s;
while (cin >> s)
cout << s << endl;
return 0;
}

The problem is >> operator stops reading when the first white space
character is encountered but why is it in this case it outputs the
complete input string even if we have white spaces in our string
Because you're using it in a loop. So each time around cin eats a word which you print and discards whitespace. The fact that you're printing a newline after each word means you don't expect to see whitespace - and in fact s contains none.
A simple way to test this would be to print:
cout << s << "$";
However the most interesting characteristic of the code is how the while tests the istream returned by << which in a boolean context yields exactly what you want: whether the input is done or not.

Using the input operator on a stream by default stops at whitespace, and skip leading whitespace. So since you reading in a loop, it skips whitespace while reading all "words" you input, and then print it inside the loop with a trailing newline.

You probably ignored the fact that whenever you are entering a new string ( after a white space character i.e. a newline, tab or blank-space ) it is being re-assigned to string s in the while loop condition. To verify this you can simply do something like :
int i=1;
while (cin >> s)
cout << i++ << ": " << s << endl;
instead of :
while (cin >> s)
cout << s << endl;
Run this and everything would be crystal clear :)

Related

What does someone mean when they write something to "gobble a newline"? C++ [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 1 year ago.
I am currently learning how to write a code that prompts the user to define how many players and rounds they want in a dice game, with the additional goal to output the results of both into a file. A couple of resources I have seen have suggested when defining the string variable, you want a secondary string for the sole purpose to "gobble newlines."
Here is the snippet of the code I was looking at:
int main()
{
int nPlayers, nRounds, score;
**string name, dummy;**
cout <<"Enter number of players: ";
cin >> nPlayers;
cout << "Enter number of rounds: ";
cin >> nRounds;
**getline (cin, dummy); // gobble up newline**
ofstream ofs ("scores.txt");
ofs << nPlayers << " " << nRounds << endl;
My question is based around the two lines denoted with double asterisks. Why the need to write a string like this?
Many input streams have extra newline characters between inputs.
"Gobble up a newline" is to get rid of those to get the correct output.
For example:
5 //number of inputs
//empty newline character
89 //first input value
...
The dummy variable is used to store it since it is not of much use to store a newline character.

Characters after a space is not being printed out

I was using character arrays to get inputs from the user then display the output afterwards. However, every time I enter values with spaces in between, only the first word before the space is printed.
For instance, this is what I typed:
Customer No.: 7877 323 2332
This will be the output:
Customer No.: 7877
I already searched for possible solutions but I can't seem to find the right solution.
This is my code for reference:
#include<iostream>
using namespace std;
int main()
{
char custNum[10] = " "; // The assignment does not allow std::string
cout << "Please enter values for the following: " << endl;
cout << "Customer No.: ";
cin >> custNum;
cout << "Customer No.: " << custNum << endl;
}
Another option is to use std::basic_istream::getline to read the entire string into the buffer and then remove the spaces with a simple for loop. But when using plain-old character arrays don't skimp on buffer size. It is far better to be 1000-characters too long than one-character too short. With your input, your absolute minimum size of custNum is 14 characters (the 13 shown plus the '\0' (nul-terminating) character. (rough rule-of-thumb, take your longest estimated input and double it -- to allow for user-mistake, cat stepping on keyboard, etc...)
In you case you can simply do:
#include <iostream>
#include <cctype>
int main() {
char custNum[32] = " "; // The assignment does not allow std::string
int wrt = 0;
std::cout << "Please enter values for the following:\nCustomer No.: ";
if (std::cin.getline(custNum, 32)) { /* validate every input */
for (int rd = 0; custNum[rd]; rd++)
if (!isspace((unsigned char)custNum[rd]))
custNum[wrt++] = custNum[rd];
custNum[wrt] = 0;
std::cout << "Customer No.: " << custNum << '\n';
}
}
The two loop counters rd (read position) and wrt (write position) are simply used to loop over the original string and remove any whitespace found, nul-terminating again when the loop is left.
Example Use/Output
$ ./bin/readcustnum
Please enter values for the following:
Customer No.: 7877 323 2332
Customer No.: 78773232332
Also take a look at Why is “using namespace std;” considered bad practice? and C++: “std::endl” vs “\n”. Much easier to build good habits now than it is to break bad ones later... Look things over and let me know if you have questions.
Apart from std::getline, if you are going to use C-style strings, try the following code:
int main() {
char* str = new char[60];
scanf("%[^\n]s", str); //accepts space a a part of the string (does not give UB as it may seem initially
printf("%s", str);
return 0;
}
Also, if you absolutely need it to be a number, then use atoi
int ivar = std::atoi(str);
PS Not to forget gets (!!dangerous!!)
char* str;
gets(str);
puts(str);
cin >> int_variable will stop reading input when it reaches the first character that isn't a valid part of a number. C++ does not consider spaces part of a number, so it stops reading as soon as it encounters one.
You could use std::getline to read into a string instead, then remove the spaces from the string before converting to an integer. Or maybe in this case you don't even need the integer and can leave it as a string.

Cin input with a + causes next input to be a string

so I'm pretty new to C++ and I'm doing an assignment for my class. I ran into a problem when trying to check if an input is a string or a double/int. So I made a basic program to test it
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string hi;
double hello;
cin >> hello;
if (!cin)
{
//Strings go here
cin.clear();
cin >> hi;
cout << hi << endl;
}
else
{
cout << hello << endl;
}
cout << "Done!" << endl;
}
So it works for basically when inputting a letter (such as "j" or "a") or a number but when inputting "+" or "-" it waits for the next input then forces it through the string block, even if it is a number. However "*" or "/" are read as strings and don't cause that issue (I'm assuming since they aren't explicitly operators)
I assume I am probably missing something. Thank you
Edit: I am testing with single types at a time (such as 123, 1 , d, +) without mixing types, so there won't be any inputs that have a double and a string
As per user4581301's suggestion, I'll put in some examples input and outputs
Inputs:Outputs
"Hello":"Hello"
123:123
"/":"/"
"+" (Input after: 2):"2"
The problem
Your programme does not work exactly as intended, because it doesn't take into consideration potentially consumed but lost characters.
Here are different cases that work as expected:
abc: the first char read is not numeric, so it's not consumed and cin fails fast. The second reading reads every chars present as a string.
123abc456: the first 123 is read. When a is encountered, it is not consumed since it's not valid numeric. Further reading is stopped, but a numeric value could be read.
/123: the first char read is not numeric, so it's not consumed and cin fails. the second reading reads every char present as string.
-123 or +123: the first char is considered as a valid numeric char and is read, and then the remainder is read, still as a numeric value. Works as expected if you consider that a double ora an int can be signed. Depending on output formatting, the + might not appear with your output.
Here are the cases that do not work: if the first char is + or - but it is not followed by a valid numeric char. In this case the first char is consumed, but the next char makes the numeric input fail. The remaining chars are then read as string (except the first sign that was already consumed and is lost). Examples:
++123
+ 123 (the space ends the axtraction of the double that fails, the remainder is read as a string).
Online demo
The solution
The easiest solution is to read the input as a string, then try to convert the string.
For example:
size_t processed;
string hi;
double hello;
cin >> hi;
try {
hello = stod(hi,&processed);
cout<<"number:" <<hello;
if (processed<hi.size())
cout << " (followed by something)";
cout <<endl;
}
catch (...) // should be more precise in catching, but it's for the proof of concept
{
cout <<"string: "<< hi << endl;
}
Online demo
If you want to consider + and - as alphanumeric, it'd be easy to check if hi is non empty and hi[0] a digit before trying to do the conversion.
Alternatively, you could also do a regex check of the string to see if it matches a numeric format.

getline function not working with multiple string input [duplicate]

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.

C++, Text to ASCII while-loop error

I've come this far without asking for help, but I've got a problem that I can't seem to fix. I like cryptology, so now that I am learning C++, I want to make programs to encrypt and decrypt strings. I read that the best way is to convert the text to ASCII and go from there, so here is a simple program I made in C++ to try and convert a char variable to ASCII:
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int main()
{
char strString[1000];
cout<<"Enter you message:"<<endl;
cin>>strString[1000];
string strEncrypt;
int a = 0;
while (strString != '\0')
{
int b = (int)strString[a];
strEncrypt.at(a) = b; //This is where I'm getting an error.
a++;
}
cout<<"Encrypted message:"<<endl;
cout<<strEncrypt<<endl;
}
So, I've tried all 3 things I know to do to troubleshoot (Google, check for missing simicolons, and make sure I'm doing == not =, but this is just something I don't know how to do, not something I'm forgetting (I hope). So, any help would great!
You don't have to change the characters to ASCII they already are. Chars are basically the same as integers in memory.
Now to your question; . If you want to set a character in a string you can do that like this
string[index] = b;
Another thing to be careful for in your code. You are using cin to read the string from the user. This will not let you read messages that have spaces in them and will only read the first word. For example, if the user enters "Love Crypto" cin will only read "Love" and "Crypto" will be ignored. To get the entire line, use getline instead.
As for looping over characters in a string, it's better to do it as follows:
for(int i = 0; i < strString.length(); i++)
{
strString[i] = bla;
}
Again, you're code isn't actually doing anything. It is only reading a letter and then storing a "letter" in another string.
string::at() throws exception if the index passed to at() is out of range. So, if you are getting runtime error then it's expected. Because, your string strEncrypt is initialized to "" and thus the size is 0.
You may try
strEncrypt.reserve(strlen(strString));
Easiest way to actually make the code you have work is change this line strEncrypt.at(a) = b; to this strEncrypt += b; Which will add the characters to the empty string strEncrypt.
Your code doesn't make much sense though as char types are already ascii. You'll have to explain more about what kind of encrypting you are trying to do and maybe we can point you in the right direction.
EDIT: After thinking about what you're trying to do a bit more based on the code you have it seems like you want to print the numeric ascii value of characters. You can do that with just a cast like this:
string input;
cout << "Enter you message:" << endl;
// handle spaces in the message
getline(cin, input);
cout << "String chars as ascii values:" << endl;
cout << "Char: " << "ASCII Code:" << endl;
for (int i = 0; i < input.length(); ++i)
{
// casting the char to an int with (int) will print the ascii code
cout << input[i] << " " << (int)input[i] << endl;
}
On top of the fact that your input is already in ASCII, keep in mind that doing cin >> strString[1000] doesn't limit the input captured to the length of your buffer unless you specifically specify the number of characters to capture for the stream object using setw() or setting it's ios_base::width data member. So your method right now risks buffer overflows.
Secondly, the form of cin >> that you're using will not capture the entire line of input. Instead it will stop at the first white-space or any other delimiting character (or end-of-file if that is reached first). In your case, if you are entering a line like "Hello World", then the syntax you're using will only capture "Hello" and drop "World".
A much better idea would be to use the getline() function with a std::string object if you are wanting to capture a line of input to a string and remove the delimiting newline character without risking buffer overflows ... for instance:
string strString;
getline(cin, strString);
Apart from advises given, when receiving this kind of run-time errors use Cppcheck utility.
It will give you the answer: "Message: Array 'strString[1000]' index 1000 out of bounds".