#include <iostream>
using namespace std;
const int ArrSize = 400;
int main()
{
char arr1[ArrSize];
char arr2[ArrSize];
char arr3[ArrSize];
cout << "enter the first string ";
cin >> arr1;
cout << "enter the second string ";
cin.get(arr2, ArrSize);
cout << "enter the thrid string ";
cin>>arr3;
cout << endl << endl;
cout << "first string is: " << arr1 << "\n";
cout << "second string is: " << arr2 << "\n";
cout << "thrid string is: " << arr3 << "\n";
return 0;
}
execution result is
input :
"abc\n"
output :
first string is: abc
second string is:
thrid string is:(strange characters)
Can you explain why the second cin didn't get input?
I expected that cin would read leading white spaces form the stream buffer and ignore them and read new string.
Let's start by adjusting the program to check for errors.
#include <iostream>
using namespace std;
const int ArrSize = 400;
int main()
{
char arr1[ArrSize];
char arr2[ArrSize];
char arr3[ArrSize];
cout << "enter the first string ";
if (!(cin >> arr1))
{
cout << "Failed cin >> arr1\n";
}
cout << "enter the second string ";
if (!cin.get(arr2, ArrSize))
{
cout << "Failed cin.get(arr2, ArrSize)\n";
}
cout << "enter the third string ";
if (!(cin>>arr3))
{
cout << "Failed cin >> arr3\n";
}
cout << endl << endl;
cout << "first string is: " << arr1 << "\n";
cout << "second string is: " << arr2 << "\n";
cout << "third string is: " << arr3 << "\n";
return 0;
}
The results should be something like
enter the first string abc
enter the second string Failed cin.get(arr2, ArrSize)
enter the third string Failed cin >> arr3
first string is: abc
second string is:
third string is: <garbage here>
We can see that the second and third reads failed. Why is that? To find out, we need to do a little reading. Here's some high-quality documentation for std::istream::get
The relevant overload is number 3, but 3 just calls number 4 with the delimiter set to '\n' and 4 says two important things,
Characters are extracted and stored until any of the following occurs:
count-1 characters have been stored
end of file condition occurs in the input sequence (setstate(eofbit) is called)
the next available input character c equals delim, as determined by Traits::eq(c, delim). This character is not extracted (unlike basic_istream::getline())
If no characters were extracted, calls setstate(failbit). In any case, if count>0, a null character (CharT() is stored in the next successive location of the array.
So if you only get a newline, delim in this case, the output string arr2 is null terminated and the stream is placed into fail state because no characters were extracted from the stream, making the stream unreadable until the failure is acknowledged by clearing it. This is what we are seeing: an empty string and fail bit.
Why is the string empty? Why didn't it prompt for input? Because cin >> arr1 reads one whitespace-delimited token from the stream. It will ignore all whitespace up to the start of the token, but it leaves the whitespace after the token in the stream.
If you type abc and hit enter, "abc\n" goes into the stream. cin >> arr1 reads "abc" into arr1. The "\n" stays in the stream where cin.get(arr2, ArrSize) finds it. The get exit condition is immediately satisfied by the "\n", so get stops and leaves the "\n" in the stream. No characters were extracted. Fail bit is set and arr2 is null terminated.
cin>>arr3 subsequently fails because you can't read from a failed stream. Nothing is placed in arr3, so when arr3 is printed, it is unterminated and << keeps printing until it finds a terminator. This is the garbage characters, though technically anything can happen.
The question does not specify what is to be done with data left over after cin >> arr1. Common solutions are to remove everything up to and including the newline character from the stream with
cin.ignore(numeric_limits<streamsize>::max(), '\n');
but if you want to use any characters left on the line for arr2, you'll have to be trickier. For example, always read lines, build an istringstream out of the line, and then parse the istringstream as is done in option 2 of this answer.
Side note: Reading into character arrays with >> is always risky because it will keep reading until whitespace is found. If the program reads the size of the array from the stream without finding whitepace, sucks to be you. get knows to stop before its overflowed. >> doesn't. On the other hand, get will read until it finds the end of the line, not just a single whitespace delimited token.
>> into a std::string will do the right thing and resize the string to fit the input. Generally prefer std::string to char arrays. And if you are using std::string prefer std::getline to get or istream's getline.
Related
Here is my code:
#include <iostream>
using namespace std;
int main(){
char inp[5], out[4];
cin >> inp >> out;
cout << inp << endl;
cout << out << endl;
system("pause");
return 0;
}
when I type:
12345
6789
It gives me:
6789
Why I failed to save the 5 words char array 'inp' and it showed nothing? The second input looks normal though. However, when I set out[3] or out[5], it seems to work alright? It seem that two char array of [5] then followed by [4] would cause problem...
I see that you enter (type) 1234567890 characters to input data for inp[5] - it is a problem because imp array is able to store 4 characters and null-terminator. When cin >> inp store more than 4 characters to inp array it leads to problem with data (somthing like undefined behaviour). So solution can be in allocation more memory for data, e.g.:
#include <iostream>
using namespace std;
int main(){
char inp[15], out[15]; // more memory
cin >> inp >> out;
cout << inp << endl;
cout << out << endl;
system("pause");
return 0;
}
When you read into a character array the stream keeps reading until it encounters whitespace, the stream is not aware of the size of the array that you pass in so happily writes past the end of the array so if your first string is longer than 4 characters your program will have undefined behaviour (an extra character is used after your input for the null terminator).
Fortunately c++20 has fixed this issue and the stream operators no longer accept raw char pointers and only accept arrays and will only read up to size - 1 characters.
Even with c++20 the better solution is to change your types to std::string which will accept any number of characters end even tell you how many characters it contains:
#include <iostream>
int main(){
std::string inp, out;
std::cin >> inp >> out;
std::cout << inp << "\n";
std::cout << out << "\n";
return 0;
}
Its because, in memory layout of computer out[4] is laid out first and then inp[5]. Something like this:
out[0],out[1],out[2],out[3],inp[0],inp[1],inp[2],inp[3],inp[4]
So, when you write 6789 in out[4], you are overflowing null character to inp[0]. So, inp becomes NULL.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
This program is working without the loop, however when I implement the loop, I get a runtime error. I think it might have something to do with my cin.getline but I really have no idea :/ any help would be great thank you!
#include <iostream>
using namespace std;
#include <string>
#include <iomanip>
int main ()
{int ans, z;
z=1;
cout << "How many times would you like to execute this string program? " << endl;
cin >> ans;
while (z <= ans)
{
int x, i, y, v;
string answer1, str3;
string mystring, fname, lname;
i=0;
y=0;
cout << "Please enter your first and last name: ";
getline(cin, answer1);
cout << endl;
x=answer1.length();
for (int i = 0; i < x; i++)
{
cout << answer1[i] << endl;
if (isspace(answer1[i]))
{
y=i;
}
}
cout << endl << endl;
cout << setw(80) << answer1;
mystring = answer1;
v=answer1.find(" ", 0);
fname=mystring.substr(0, y);
lname=mystring.substr(v, x);
cout << "First name: " << fname << endl;
cout << "Last name: " << lname << endl;
mystring=lname+','+fname;
cout << setw(80) << mystring;
z++;
}
return 0;
}
The error happens in this line:
lname=mystring.substr(v, x);
where v happens to have a very large value. So how does your program get there, and how does v get this value? v has value std::string::npos, which is an error code meaning, in this case, that the space you were looking for wasn't there. That this is the case has to do with the difference between formatted and unformatted input and the fact that you're mixing them.
Formatted input means treating an input stream as a stream of tokens. Leading whitespace -- all whitespace, whether space, tab, or newline -- is skipped, and where the token ends, there does the input. One example of formatted input is
cin >> ans;
For formatted input, everything that doesn't fit its pattern looks the same. Whether std::istream::operator>>(int) encounters a space, a tab, a newline, an 'a' or a 'z', that's just the end of the token, and there it stops reading. For example, if you have
int x;
std::string s;
std::cin >> x >> s;
and feed it the input 123abc, then x will have the value 123, and s will be "abc". Crucially, this means that if the user answers
cin >> ans;
with a number and newline, the encountered character after the number -- a newline -- remains in the stream.
Unformatted input, by contrast, means treating an input stream as a stream of characters. For unformatted input functions, whitespaces are just another character, and unless the unformatted input function defines a special meaning for them, it will treat them the same as any other character. An example of unformatted input is
getline(cin, answer1);
which is shorthand for
getline(cin, answer1, '\n'); // that is to say, the delimiter
// has a default value of '\n'
(just to make it clear that the newline character '\n' has a special meaning in this case). getline, used this way, will read from the stream until it encounters a newline.
And therein lies your problem. After the previous, formatted input function, there is stuff left in the stream that you don't care about. It is probably just a newline (although if the user provided 123abc, it will be abc\n), in which case getline will give you an empty string -- there's an empty line in the stream, so what else can it do?
There are several ways to deal with this condition. One is to say
#include <iostream>
#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
This is essentially saying: ignore everything up to the next newline (the numeric_limits<streamsize>::max() is a very large number that cin.ignore treats as infinity). Another is
cin >> ws;
which says: "ignore everything up to the next non-whitespace character", although this will ignore leading spaces in the next line, and it will not ignore abc if the user provided 123abc. In your case, I believe there is no reason to change gears from formatted input -- you don't want a line but first and last names. I suggest using
string fname, lname;
cin >> fname >> lname;
This will also eliminate the other error (that you're using an error code as string index), because you won't have to search for a space in the string that may not be there.
Do
cin >> ans;
cin >> std::ws;
before the while loop. Also, check
v=answer1.find(" ", 0);
for
std::npos
which is the value returned if find was unsuccessful.
Can somebody please tell me why it won't print my full address? The final output is "Your name is Syd and you live at 2845." Why is it doing this? I clearly state within the cout to print the address string. (by the way, I actually type 2845 SE Taylor Street)
#include <iostream>
using namespace std;
int main()
{
string address;
cout << "Please enter your address." << endl;
cin >> address;
cout << "You live at " << address << "." << endl;
return 0;
}
cin >> address;
This reads a single word, stopping at the first white-space character. To read a whole line:
std::getline(cin, address);
The input operator reads space separated values. So if your address have a space in it then it will read just the first "word.
And worse, if you enter your full name, the first input will read the first name, and the second input will read the second name.
Try to use std::getline to read the whole line, but first do std::cin.ignore(numeric_limits<streamsize>::max(),'\n'); to skip the newline from the last input (or use std::getline for both inputs).
Only the first call to getline() appears to read anything in from std::cin. Is the fact that buffer contains something a problem - why doesn't getline() just overwrite the contents of buffer?
How can I get the second call to getline() to read something in?
My code:
const int recordLen = 20;
// truncate the input to 20 chars
void getText(char line[])
{
std::cout << "Enter something for getText: ";
std::cin.getline(line, recordLen+1);
for(int i = std::strlen(line); i < recordLen; i++)
{
line[i] = ' ';
}
line[recordLen] = '\0';
}
int main()
{
char buffer[340];
getText(buffer);
std::cout << buffer;
std::cout << "Now enter some more text:";
// put more text into buffer
std::cin.getline(buffer, 30);
std::cout << "you entered : " << buffer << std::endl;
return 0;
}
So - example output of program:
Enter something for getText: alskdjfalkjsdfljasldkfjlaksjdf
alskdjfalkjsdfljasldNow enter some more text:you entered :
After the display of "Now enter some more text:", the program immediately displays "you entered:". It does not give me the opportunity to enter more text, neither does it display any characters that were truncated from the previous call to getline().
std::cin.getline(line, recordLen+1);
Here, if the input is longer than recordLen chars, the remaining characters will not be read and will remain in the stream. The next time you read from cin, you'll read those remaining characters. Note that, in this case, cin will raise its failbit, which is probably what you're experiencing.
If your first input is exactly recordLen chars long, only the newline will remain in the stream and the next call to getline will appear to read an empty string.
Other than that, getline does overwrite the buffer.
If you want to ignore anything beyond the first recordLen chars on the same line, you can call istream::clear to clear the failbit and istream::ignore to ignore the rest of the line, after istream::getline:
std::cin.getline(line, recordLen+1);
std::cin.clear();
std::cin.ignore( std::numeric_limits<streamsize>::max(), '\n' );
Why does this program run fine?
#include<iostream>
using namespace std;
int main()
{
cout <<"What year was your house built?\n";
int year;
cin >> year;
cout << "What is its street address?\n";
char address[80];
cin>>address;
cout << "Year built: " << year << endl;
cout << "Address: " << address << endl;
cout << "Done!\n";
return 0;
}
And why does this program not give the chance to enter the address?
#include <iostream>
int main()
{
using namespace std;
cout <<"What year was your house built?\n";
int year;
cin >> year;
cout << "What is its street address?\n";
char address[80];
cin.getline(address, 80);
cout << "Year built: " << year << endl;
cout << "Address: " << address << endl;
cout << "Done!\n";
return 0;
}
cin>> leaves the newline character (\n) in the iostream. If getline is used after cin>>, the getline sees this newline character as leading whitespace, thinks it is finished and stops reading any further.
Two ways to solve the problem:
Avoid putting getline after cin >>
OR
Consume the trailing newline character from the cin>> before calling getline, by "grabbing" it and putting it into a "dummy" variable.
string dummy;
getline(cin, dummy);
Why does the first program work & Second doesn't?
First Program:
The cin statement uses the entered year and leaves the \n in the stream as garbage. The cin statement does NOT read (or "grab") \n. The cin ignores \n when reading data. So cin in program 1 can read the data properly.
Second Program:
The getline, reads and grabs \n. So, when it sees the \n left out from cin, it grabs the \n and thinks it is finished reading, resulting in second program not working as you expected.
Sit down for a second. This is not easy to explain properly.
When your program gets to a point where it reads from std::cin, it does not just automatically wait for you to type something. std::cin is an input stream, the same as you use to read from a file on disk. The only reason it waits is if there is not enough data available yet to satisfy the read request.
Meanwhile, when you run your program from the console, the console window itself is also a program. It is interpreting your key presses and translating them into text, and feeding that text a line at a time to the standard input of your program (so that std::cin can see it). This is important and useful, because it allows the backspace key to work the way you expect it to.
So if your program is supposed to read a number, and you type a number, your program will not see the number until you hit return to complete the line. However, the newline character is still sitting in the input stream, because you didn't read it yet. The operator>> skips whitespace before the value that it's trying to read, but it leaves behind any whitespace after the value.
Now, if the next reading operation is another call to operator>>, then it does the same thing again and it works fine: the newline that we didn't read before is whitespace, so it gets skipped, and then the next thing gets read.
However, the getline() function reads from the current point until the next newline. It never skips any leading or trailing whitespace, and an empty line is considered completely valid. So if you typed a number and hit return, then the getline() call will see the newline and finish reading right away, because it already has an end of the line. The program does not stop because there was already enough data available to finish the operation.
To fix this, the safest, simplest and most robust way of dealing with the input is to always read the entire line first, and then re-interpret the contents of the line. To make this easier, we will use the std::string class to represent strings. We can read into the string instance with std::getline (notice: a global function, not a member function of cin), and create a std::stringstream instance from that string.
The idea is: the program will always wait at an input request, because the previous request always read the newline character (because we read the entire line). So that makes the control flow work the way we expected it to. The std::stringstream instance can be treated like a file or standard input: it's just another stream, except it takes its data from the string. So we can get numbers out of it with operator>>, and so on.
The other benefit of this comes when the user inputs invalid data. It can be quite hard to recover from this properly, if you are just reading directly from std::cin. But if you are using the stringstream as a "buffer", then you can just throw it away and try again with a new line of input.
An example:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
using namespace std;
string line;
int year;
while (true) {
cout << "What year was your house built?" << endl;
getline(cin, line);
stringstream input(line);
if (line >> year) { break; }
}
cout << "What is its street address?\n";
getline(cin, line);
cout << "Year built: " << year << endl;
cout << "Address: " << line << endl;
cout << "Done!\n";
}
Maybe you have a stray terminator in cin?|
Try cin.clear();