C++ character to int - c++

what happens when you cin>> letter to int variable? I tried simple code to add 2 int numbers, first read them, than add them. But when I enter letter, it just fails and prints tons of numbers to screen. But what causes this error? I mean, I expected it to load and use ASCII code of that letter.

I assume you have code like this:
int n;
while (someCondition) {
std::cin >> n;
.....
std::cout << someOutput;
}
When you enter something that cannot be read as an integer, the stream (std::cin) enters a failed state and all following attempts at input fail as long as you don't deal with the input error.
You can test the success of an input operation:
if (!(std::cin >> n)) //failed to read int
and you can restore the stream to a good state and discard unprocessed characters (the input that caused the input failure):
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Another possibility is to accept input into a string variable (which rarely fails) and try to convert the string to int.
This is a very common problem with input and there should be tons of threads about it here and elsewhere.

if you explicitly cast your char to an int, it'll use the ASCII code, else it's not doing the cast by itself to int, so you get the strange results you are getting.

You could use int istream::get();

The issue is that when you read into an integer variable, using C++ streams, the input method expects characters that can make up a number, such as '+', '-', '0' ... '9'. Any character that is not in this set terminates the input and a number is created from these characters.
To get the ASCII value of a character, you need to input the data into a char variable. Internally, it has the ASCII value (provided the program in not reading 16-bit chars or EBCDIC). If you want to see the ASCII value, you will need to output the char variable as an integer (generally requiring a cast before output).
If reading an integer fails, your program needs to inform the User that the input was incorrect. The program may require the User to input the number again before the program can process the input data.

When you are doing something like:
int x;
cin >> x;
You are instructing C++ to expect to read an int from keyboard. Actually, when you enter something not an int, the input stream (standard input, in this case) renders unusable due to its error state.
That's why I personally prefer to always read strings, and convert them to numbers if needed. There are conversion functions in the C part of the C++ standard library that can help with this.
double cnvtToNumber(const std::string &num)
{
char * ptr;
double toret = strtod( num.c_str(), &ptr );
if ( *ptr != 0 ) { // If it got to the end of the string, then it is correct.
throw std::runtime_error( "input was not a number" );
}
return toret;
}
Here you are converting a number, and detecting if the conversion was right. strtod(s) will only stop when finding the end of the string, or a space. In order to avoid trailing spaces fooling the function, you could need a trim function:
std::string &trim(std::string &str)
{
// Remove trailing spaces
unsigned int pos = str.length() -1;
while( str[ pos ] == ' ' ) {
--pos;
}
if ( pos < ( str.length() -1 ) ) {
str.erase( pos + 1 );
}
// Remove spaces at the beginning
pos = 0;
while( str[ pos ] == ' ' ) {
++pos;
}
if ( pos < 1 ) {
str.erase( 0, pos );
}
return str;
}
Now you can safely read from console (or whatever other input stream):
int main()
{
std::string entry;
try {
std::getline( std::cin, entry );
int age = cnvtToNumber( trim( entry ) );
std::cout << age << std::endl;
} catch(const std::exception &e) {
std::cerr << e.what() << std::endl;
}
}
Of course you can lose precision if you always read double's and then convert them. There are specific functions for integers (strtol(s)), in case you want to investigate further.

Related

why does this routine return an array of length 0?

everyone, here is a function I wrote to read a user input which is a vector of double of unknown size, the input must terminate when 'enter' is pressed:
vector<double> read_array()
{
vector<double> array_in;
double el;
while (!cin.get())
{
cin >> el;
array_in.push_back(el);
}
return array_in;
}
To illustrate it consider the following code:
void init() // the function that calls the read_array function
{
cout << "Enter array X: " << endl;
vector<double> X = read_array();
int l = X.size();
cout << l << endl;
}
A typical input when promted is:
1(space)2(space)3(space)4(enter)
When enter is pressed, the input terminates, and the variable 'l' is initialised but is equal to 0
However, when the enter key is pressed, the array size is 0. Debugging it makes it look like it never makes it into the loop like that.
The same routine works well if the input value is not an array.
Thanks to everyone in advance!
I don't know what you hope std::cin.get() does but based on your comment it seems you hope that it somehow deals with end of lines: it doesn't. It simply reads the next character which is unlikely to do you much good. In particular, if the character is anything but '\0' negating it will result in the boolean value false. That said, the loop should in principle work unless you only input a single digit numeric value followed (possibly after space) by a non-digit or the end of the input.
The easiest approach to deal with line-based input is to read the line into a std::string using std::getline() and then to parse the line using std::istringstream:
std::vector<double> read_array() {
std::vector<double> result;
if (std::string line; std::getline(std::cin, line)) {
std::istringstream lin(line);
for (double tmp; std::cin >> tmp; ) {
result.push_back(tmp);
}
}
return result;
}
As std::cin is only involved while reading lines, std::cin.fail() won't be set when parsing doubles fails. That is, you can read multiple lines with arrays of doubles, each of which can also be empty.
If you don't want to read an auxiliary line, you'll need to understand a bit more about how formatted input in C++ works: it starts off skipping whitespace. As newlines are whitespace you need to rather read the whitespace yourself and stop if it happens to be a newline or non-whitespace. I'd use a function doing this skipping which returns false if it reached a newline (which is still extracted):
bool skip_non_nl_ws(std::istream& in) {
for (int c; std::isspace(c = in.peek()); std::cin.ignore()) {
if (c == '\n') {
return false;
}
}
return true;
}
std::vector<double> read_array() {
std::vector<double> result;
for (double tmp; skip_non_nl_ws(std::cin) && std::cin >> result); ) {
result.push_back(tmp);
}
return result;
}
This approach has a similar property that std::ios_base::failbit won't be set. However, if any of the characters on a line can't be parsed as double the bit will set. That way you can detect input errors. The approach using std::getline() will just go on to the next line.

Struggling with a textcounter

I tried to write myself a textcounter which tells me how many characters and words are in a piece of text. Every time I try to paste in a long piece of text for it to count, it will crash or display something random.
Does anyone have any suggestions?
This is what I have written:
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Text counter\nPlease insert text.\n";
string text = "";
getline(cin, text);
double countTotal = text.size();
cout << "Total characters: " << countTotal << "\n";
int wordCount = 1;
for (int chrSearch = 0; chrSearch < (int)text.size(); chrSearch++)
{
char chr = text.at(chrSearch);
if(chr == ' ')
{
wordCount++;
}
}
cout << "Total words: " << wordCount << "\n";
return 0;
}
First of all, the code reads at most one line: std::getline(std::cin, line) stops reading upon receiving the first newline. You can specify a character where to stop, e.g, the character '\0' is unlikely to be present in typical text. For example, you could use:
std::string text;
if (std::getline(std::cin, text, '\0')) {
// do something with the read text
}
You should also always check that input was successful. While the above would work with short texts, when the texts become large it makes more sense to read them one line at a time and eventually reading a line will fail when the end of the stream is reached.
In case you don't like the approach of reading everything up to a null character, you could read the entire stream using code like this:
std::istreambuf_iterator<char> it(std::cin), end;
std::string text(it, end);
if (!text.empty()) {
// do something with the read text
}
A few notes on the other parts of the code:
Don't use double where you mean to use an integer. You may want to use a bigger integer, e.g., unsigned long or unsigned long long but double is for floating point values.
When iterating through a sequence you should either use an unsigned integer type when dealing with indices, e.g., unsigned int or std::size_t. This way there is no need to cast the size(). Preferably you'd use iterators:
for (auto it(text.begin()), end(text.end()); it != end; ++it) {
char chr(*it);
// ...
}
or
for (char chr: text) {
// ...
}
Note that your word count is wrong if there are two consecutive spaces. Also, if you don't break your text using line breaks, you need to use '\n' as an additional whitespace character separating words. If you want to consider all spaces, you should actually use something like this to determine if a character is a space:
if (std::isspace(static_cast<unsigned char>(chr)) { ... }
The static_cast<unsigned char>(chr) is needed because char tends to be signed and using a negative value with std::isspace() results in undefined behavior. Casting the character to unsigned char avoids any problems. Note that negative characters are not entirely uncommon: for example, the second character of my last name (the u-umlaut 'ΓΌ') normally result in a negative char, e.g., when UTF-8 or ISO-Latin-1 encoding is used.

Ways of converting wstring to double with error checking

I need to convert a wide string to double number. Presumably, the string is holding a number and nothing else (maybe some whitespaces). If the string contains anything else, an error should be indicated. So I can't use stringstream - it will extract a number without indicating an error if the string contained something else.
wcstod seems like a perfect solution, but it works wrong on Android (GCC 4.8, NDK r9). What other options can I try?
You can use stringstream, then use std:ws to check that any remaining characters on the stream are only whitespace:
double parseNum (const std::wstring& s)
{
std::wistringstream iss(s);
double parsed;
if ( !(iss >> parsed) )
{
// couldn't parse a double
return 0;
}
if ( !(iss >> std::ws && iss.eof()) )
{
// something after the double that wasn't whitespace
return 0;
}
return parsed;
}
int main()
{
std::cout << parseNum(L" 123 \n ") << '\n';
std::cout << parseNum(L" 123 asd \n ") << '\n';
}
prints
$ ./a.out
123
0
(I've just returned 0 in the error case as something quick and easy for my example. You probably want to throw or something).
There are of course other options too. I just felt your assessment was unfair on stringstream. By the way, this is one of the few cases where you actually do want to check eof().
Edit: Ok, I added the ws and Ls to use wchar_ts.
Edit: Here's what the second if conceptually looks like expanded out. May help to understand why it is correct.
if ( iss >> std::ws )
{ // successfully read some (possibly none) whitespace
if ( iss.eof() )
{ // and hit the end of the stream, so we know there was no garbage
return parsed;
}
else
{ // something after the double that wasn't whitespace
return 0;
}
}
else
{ // something went wrong trying to read whitespace
return 0;
}

Input from a file in C++

I want to read from a file character by character and perform a certain operation on every character I am using the following loop:
ifstream in
while(in)
{
ch=in.get();
//some operation
}
I don't want to read the character in condition for while because then cursor will move to next position and I'll miss that character.
The problem is that the end of the file is not properly signalled and the last character is read two times. Please give a way to avoid this
Eg. if The string in the file is
army
it is read as armyy (when I print)
char ch;
while(in.get(ch)){ } //or in>>std::noskipws>>c
Would be the proper way as the character you want is stored in ch. what is the problem with that?
If you really want it the way you want, then you may use peek() to see the next character and perform appropriate opeartion as:
char c = in.peek(); //this will give you the next character in the stream
//if its an eof, do appropriate
Use the other overload of get:
while (in.get(ch)) {
// do something with ch
}
or
for (char ch; in.get(ch); ) {
// do something with ch
}
You can also use sscanf for reading char.. In that example you can see that 3 input are reading from text . First two are string , last is float .. And also you can use a vector to store values..
Hope this example can be helpfull
std::string str;
char buf_1[50];
char buf_2[50];
while(std::getline(in, str))
{
if(sscanf(str.c_str(), "%s %s %f", buf_1, buf_2, &faceStatistics.statistics) == 3)
{
faceStatistics.faceName_1 = buf_1;
faceStatistics.faceName_2 = buf_2;
faceStat_.push_back(faceStatistics);
}
else
std::cout << "No param in string " << str << std::endl;
}
vector assign
struct Fstat {
std::string faceName_1;
std::string faceName_2;
float statistics;
};

How come the last character is taken in twice before the file resets?

I have a function that takes input from a file, character by character:
#include <iostream>
#include <fstream>
using namespace std;
ifstream input("sequence.txt");
char getChar(){
char nextType;
if (input.eof()) {
input.clear();
input.seekg(0,ios::beg);
}
input >> nextType;
return nextType;
}
int main(){
for(int i = 0; i < 10; i++){
cout << getChar() << endl;
}
return 0;
}
The input inside "sequence.txt" is:
I O
So the output should print alternating I's and O's, but instead outputs:
I O O I O O I O O I
How do I make the file reset after the first time it reads the last character in the file?
eof is only set when you try to read after already reaching the end of the file. Instead, first try to read a char. If that fails, then reset the stream and try again, like this:
char getChar()
{
char nextType;
if (!(input >> nextType))
{
input.clear();
input.seekg(0,ios::beg);
input >> nextType;
}
return nextType;
}
You're returning a value without testing whether the input
succeeded. You're function should be something alont the lines
of:
char
getChar()
{
char results;
input >> results;
if ( !input ) {
input.clear();
input.seekg( 0, std::ios_base:;beg );
input >> results;
if ( !input ) {
// There are no non-blanks in the input, so there's no way we're
// going to read one. Give up, generating some error condition
// (Throw an exception?)
}
}
return results;
}
The important thing is that there is no path of execution
which reads or copies results without having successfully read
it. (Unless you've assigned something to it otherwise. You
might, for example, initialize it with '\0', with the
convention that the function returns '\0' if it is unable to
read anything.)
I might add that the test for input.eof() is only valid
after you've determined that an input has failed. I may
return false even when there's no more valid input.