Why am I getting a segfault on cin? - c++

I am writing a fairly simple exercise (homework), and most of it works, however it sometimes segfaults on cin. Here is the relevant code.
int main()
{
std::string str = "";
std::cout << "Please select the desired operation:\n";
std::cout << "(A): Generate Decompositions\n";
std::cout << "(B): Generate Acceptable Compositions from S1.txt and S2.txt\n";
std::cout << "cout"; //debug statement
std::cin >> str;
std::cout << "cin"; //debug statement
std::cout << str;
char resp = str.at(0);
std::cout << "resp"; //debug statement
...
}
I get a segfault on std::cin >> str (I know this because of what "debug statements" are output). But the weird thing is, I only get it when I input 'b'. If I input 'a', or any word starting with 'a', it works fine. If I enter any letter other than a or b, or anything starting with any other letter than a or b, it exits (as it's supposed to). But if I type in 'b', or any word starting with 'b', it Segfaults. Every single time. Why?

I know this because of what "debug statements" are output"
The code that you posted looks fine.
Since your output statements do not have << endl at the end, some of the output may still be buffered at the time of segfault. Writing out endl blocks until the output is flushed, so adding << endl is likely to help you get closer to the actual location of the crash.

Related

Why is stringstream mixing up it's content in combination with char array and cout?

in this minimal example there is a weird messing up between the input to a stringstream and the content of a previously used cout:
online gdb:
https://onlinegdb.com/itO69QGAE
code:
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
const char sepa[] = {':', ' '};
const char crlf[] = {'\r', '\n'};
int main()
{
cout<<"Hello World" << endl;
stringstream s;
string test1 = "test_01";
string test2 = "test_02";
s << test1;
cout << s.str() << endl;
// works as expected
// excpecting: "test_01"
// output: "test_01"
s << sepa;
cout << s.str() << endl;
// messing up with previous cout output
// expecting: "test_01: "
// output: "test_01: \nHello World"
s << test2;
cout << s.str() << endl;
// s seems to be polluted
// expecting: "test_01: test_02"
// output: "test_01: \nHello Worldtest_02"
s << crlf;
cout << s.str() << endl;
// once again messing up with the cout content
// expecting: "test_01: test_02\r\n"
// output: "test_01: Hello Worldtest_02\r\nHello World"
return 0;
}
So I am wondering why is this happing?
As it only happens when a char array is pushed into the stringstream it's likely about this... but according to the reference the stringstream's "<<"-operator can/should handle char* (what actually the name of this array stand's for).
Beside that there seems to be a (?hidden, or at least not obvious?) relation between stringstream and cout. So why does the content pollute into the stringstream?
Is there any wrong/foolish usage in this example or where is the dog buried (-> german idiom :P )?
Best regards and thanks
Damian
P.S. My question is not about "fixing" this issue like using a string instead of the char array (this will work)... it's about comprehend the internal mechanics and why this is actually happing, because for me this is just an unexpected behaviour.
The std::stringstream::str() function returns a string containing all characters previously written into the stream, in all previous calls to operator<< (or other output functions). However it seems that you expect that only the last output operation will be returned - this is not the case.
This is analogous to how e.g. std::cout works: each invocation of std::cout << appends the string to standard output; it does not clear the console's screen.
To achieve what you want, you either need to use a separate std::stringstream instance every time:
std::stringstream s1;
s1 << test1;
std::cout << s1.str() << std::endl;
std::stringstream s2;
s2 << sepa;
std::cout << s2.str() << std::endl;
Or better, clear the contents of the std::stringstream using the single argument overload of the str() function:
std::stringstream s;
s << test1;
std::cout << s.str() << std::endl;
// reset the contents of s to an empty string
s.str("");
s << sepa;
std::cout << s.str() << std::endl;
The s.str("") call effectively discards all characters previously written into the stream.
Note, that even though std::stringstream contains a clear() function that would seem a better candidate, it's not analogous to e.g. std::string::clear() or std::vector::clear() and won't yield the effect desired in your case.
Here I am again,
Thanks to "Some programmer dude"'s comment I think I figured it out:
As there is no (null-)termination-symbol related to both char arrays it seems that the stringstream-<<-operator inserts until it stumbles over an null-terminator '\0'.
Either expending both arrays with a \0-symbol (e.g. const char sepa[] = {':', ' ', '\0'}) or terminating the length with e.g. s << string(sepa,2) will do the expected output.
In this specific case above the data seems to lay aligned in memory, so that the next null-terminator will be found inside the cout << "Hello World"-statement. As this alignment is not guaranteed, this will actually result in undefined behaviour, when the termination is missing.
So also two additional "terminating"-arrays like e.g const char sepa[] = {':', ' '}; char[] end_of_sepa = {'\0'}; declared right after the mentioned arrays will result in expected output, eventhough when the rest will be left unchanged... but this is probably not guaranteed and depends on the internal representation in memory.
P.S. As previously written this issue is not about fixing but comprehension. So please feel free to confirm or correct my assumption.
EDIT: Corrected the bold code section.

C++ won't print trailing whitespace

In my simple program to learn C++, I am asking the user their name and then greeting them.
#include <iostream>
int main() {
std::string name;
std::cout << "Enter your name: ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << "!\n";
}
However, here is my result in CLion:
I expected the program to print out a trailing whitespace after the prompt for my name. However, it prints the space after I give the program input. I have only experienced this in CLion, but not in other IDEs. Why is this happening, and how can I fix this?
You need to flush your stream:
std::cout << "Enter your name: " << std::flush;
std::cout is a buffered stream which means that while your write to it isn't immediately written to the underlying device, but it is stored in a buffer. This is done for performance reasons. std::endl has an implicit flush operation, that's why you don't notice this if you always add a std::endl before you request input. Otherwise, like you've seen that can happen.

clearing out extra input from terminal

Here is an example code demonstrating the problem I'm facing.
#include <iostream>
#include <string>
extern "C" {
#include <unistd.h>
}
int main()
{
std::cout << "Making tests ready!" << std::endl;
std::cout << "\nTo start out, Enter an integer: ";
int a = 0;
std::cin >> a;
std::string input;
sleep(3); // what to do if user enters data during this?
std::cout << "\n Now enter a string";
std::getline(std::cin, input);
std::cout << "\nHere are your values - " << a << " & " << input;
return 0;
}
See the sleep call in between the code? This could be replaced with somewhat long delays while computing something when my program isn't accepting any inputs. Now if user presses some keys during this time, that input is captured by std::getline() in next line of code. I know this is the default behavior since it should capture the input being provided.
But what I want is to clear all that captured input and start fresh with 15th line that is std::cout << "\n Now enter a string";, which is immediately after sleep. I don't know exact term to describe this or else I would have used that. Thanking you.
Edit: I've tried using std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); in my code, but it asks for input and then discards it.
Please mind my english, not a native speaker.
Reading the comments causes me to think that you can't really solve this problem (at least by the means suggested there). There's an inherent race condition in any case. Consider the following lines:
sleep(3);
// (*) <- Potential location 1.
std::cout << "\n Now enter a string";
// (**) <- Potential location 2.
std::getline(std::cin, input);
The various comments show some (very technically-competent) ways to flush the standard input. The problem is, you cannot put them in the location marked (*) nor (**).
First location - you clear the standard input some way. Now you decide it's time to move to the next line (std::cout << ...). While you do that, the user types in some more input. Race!
Second location - You print out the message (std::cout << ...), and proceed to clear the standard input. Before you manage to do that, the user typed in something. Race!
It seems to me that any of the techniques described in the comment require locking the standard input, and I don't think there's a (standard) way to do so.

can I Remove "endl" in ( cout<<" "<<endl ) in C++?

I am beginner at C++, my question is can I remove endl the one at the end of cout like :
cout<<" "<<endl;
I don't want return to new line . If I can't remove it, what should I do?
Elephant in the room: remove the endl from the cout.
But in case you don't own that code, you could try "\033[F", which, if your terminal supports it, moves you to the previous line.
Another possibility would be to redirect the cout buffer using rdbuf to an ostream that you control. You could (i) redirect, (ii) call the function that writes the errant cout with the new line and (iii) inspect your ostream and write to the original buffer, this time omitting the endl. Switch everything back once you're done.
Yes of course you do not need to use std::endl every time you use <<. As an example a simple way to print a vector with spaces between the elements would look like:
std::vector<int> foo = {1,2,3,4,5};
for (auto e : foo)
std::cout << e << " ";
Here we never use a endl. You cout also just use \n at the end of a string literal and that will put a newline in the buffer as well.
std::cout << "test\n";
std::cout << "this will be on a new line";
Notice that I don't put a newline in the last cout<< so if there is anymore output it will start off right after the "e" in "line".
Yes you can remove endl. It is an optional parameter to the << stream operator of which there are many. If you don't include it then a new Carriage Return/Line Feed character will not be output and therefore text will appear on the same line in the output (presumably console).
For example
cout << "Hello, World" << endl;
would become:
cout << "Hello, World";
or to make the point another way you could write:
cout << "Hello,";
cout << " World";
There are lots of other examples out there too, here's one for starters: http://www.cplusplus.com/doc/tutorial/basic_io/
cout<<"Your message here.";
It's as simple as that. Were you trying to do something like...
cout<<"Your message here."<<; ....? This is wrong as:
The << operator signifies that something comes after the "" part. You don't have any in this case.

How to break out of this for loop: `for (; cin >> A;);`

for (cout << "\nEnter the Sentence now:";
cin >> Ascii;
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
Probably the best advice is don't be clever. Not only do you make it hard for anyone else* to read, understand, and modify your code, you run a real risk of outsmarting yourself.
Thus, don't try to do weird and clever things to implement your loop. Just do things naturally. If they don't naturally fit into how for or while or do ... while statements are structured, then just write a generic loop and use break statements to deal with leaving the loop. e.g.
while (true) {
// Some stuff
if (i_should_break_out_of_the_loop) {
break;
}
// Some more stuff
}
This is pretty much always better than doing things like torturing the for statement in the way you have.
Once you have a clear, easily comprehensible loop, it should be relatively easy to modify it to suit your needs. (or to ask a clearer and more focused question)
*: "anyone else" also includes you three weeks from now, after you've had time for it leave your short term memory.
I strongly advise you to turn this loop into a while loop. However the following is true whether or not you do:
Just enter an EOF, then the loop will terminate.
How an EOF is input will depend on your OS (and possibly also on your terminal settings). On Linux (under default terminal settings) you get an EOF pressing Ctrl+D at the beginning of the line. On Windows, I think it's Ctrl+Z. On Mac I have no idea.
Of course you could also redirect stdin for your program to come from a file (in which case EOF is — as you would guess — generated at the end of file), or from a pipe (in which case EOF is generated as soon as the writing program closes the pipe).
If the variable Ascii is not of type char or string, you may also enter something that cannot be parsed as that variable's data type (e.g. if reading an int, anything other than a number will cause the stream to report failure and thus the loop to terminate).
You also might want to add another end condition then in the loop body (which in your for loop is currently just an empty statement). For example, you might decide that a percent sign should terminate your loop; then you could write (I'm still assuming the type of Ascii which you didn't provide is char):
cout << "\nEnter the Sentence now:";
while(cin >> Ascii)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
if (Ascii == '%')
break;
}
However note that normally operator<< skips whitespace; I guess you don't want whitespace skipped. Therefore you probably shouldn't use operator<< but get; this will also allow you to use the end of line as end condition:
cout << "\nEnter the Sentence now:";
while(std::cin.get(Ascii) && Ascii != '\n')
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
}
However in that case, it's better to read the line in one step and then iterate through it:
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (std::string::iterator it = line.begin; it != line.end(); ++it)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)*it + RandomNumberSubtract << endl;
}
Note that in C++11, you can simplify this into
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (auto ch: line)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)ch + RandomNumberSubtract << endl;
}