I’m having a bit of a problem in C++. When I wrote this:
int a = ‘:‘;
cout << a;
This printed out 58. It checks out with the ASCII table.
But if I write this:
int a;
cin >> a;
//i type in “:”
cout << a;
This will print out 0. It seems like if I put in any non-numeric input, a will be 0. I expected it to print out the equivalent ASCII number.
Can someone explain this for me? Thank you!
There are two things at work here.
First, ':' is a char, and although a char looks like a piece of text in your source code, it's really just a number (typically, an index into ASCII). This number can be assigned to other numeric types, such as int.
However, to deal with this oddity in a useful way, the IOStreams library treats char specially, for a numeric type. When you insert an int into a stream using formatted insertion (e.g. cout << 42), it automatically generates a string that looks like that number; but, when you insert a char into a stream using formatted extraction (e.g. cout << ';'), it does not do that.
Similarly, when you do formatted extraction, extracting into an int will interpret the user's input string as a number. Forgetting the char oddity, : in a more general sense is not a number, so your cin >> a does not succeed, as there is no string that looks like a number to interpret. (If a were a char, this "decoding" would again be disabled, and the task would succeed by simply copying the character from the user input.)
It can be confusing, but you're working in two separate data domains: user input as interpreted by IOStreams, and C++ data types. What is true for one, is not necessarily true for the other.
You're declaring a as an int, then the operator>> expects digits, but you give a punctuation, which makes extraction fails. As the result, since C++11, a is set to 0; before C++11 a won't be modified.
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set. (until C++11)
If extraction fails, zero is written to value and failbit is set. (since C++11)
And
I expected it to print out the equivalent ASCII number.
No, even for valid digits, e.g. if you input 1, a will be set with value 1, but not its ASCII number, i.e. 49.
This will print out 0. It seems like if I put in any non-numeric input, a will be 0. I expected it to print out the equivalent ASCII number.
Since C++11 when extraction fails 0 will be automatically assigned.
However, there is a way where you can take a char input from std::cin and then print its ASCII value. It is called type-casting.
Here is an example:
#include <iostream>
int main()
{
char c;
std::cin >> c;
std::cout << int(c);
return 0;
}
Output:
:
58
Related
In C++, how can I input a number to unsigned char variable? In C, I can accept the input using %hhu format specifier:
unsigned char var_name;
scanf("%hhu", &var_name);
//lets say I inputted 27
printf("%hhu", var_name);
//the output is 27
How can I do that in C++? The code below is my attempt to do this in C++, but it does a wrong thing. How can I write equivalent code in C++?
unsigned char var_name;
std::cin >> var_name;
//Input 27 again
std::cout << var_name;
//The output is just 2, how can I make the '7' appear?
This happens because when reading an unsigned char from std::istream, a character is read. That's just what happens, that's how std::istream works. It also makes a lot of sense, because it's quite common to want to read a single character.
The trivial solution is to use a temp variable:
unsigned char var_name;
unsigned int tmp;
std::cin >> tmp; // input 27
// optionally add checking that tmp is small enough
var_name = tmp; // truncation of unsigned ints is well defined
std::cout << var_name; // should print 27
You are only getting a 2 when printing the variable because of cin.
The maximum size of an unsigned char in C++ is usually 8 bits, which is fine for any actual character, and any digit up to 255. However this number depends on the compiler and the system. The maximum value that can be stored is in the header, as UCHAR_MAX.
Your issue here is that you are using cin, which only ever reads the first 'character' of an input if it is storing that input as a char. There are several ways around this, including taking the input as an integer and then converting to a char, or making your program work with an integer.
Hope this helps :)
When var_name is of type unsigned char, then the line
std::cin >> var_name;
is similar to
std::scanf("%c", &var_name);
i.e. C++ will assume that you want to read a single character and write the character code into var_name.
If you instead want to read a number and write that number into var_name, then you cannot use the data type char or unsigned char when using operator >>, even if the data type is technically able to represent the desired range of values. Instead, you will first have to use a variable with a larger data type, such as unsigned short, for reading the number. Afterwards, you can assign it to another variable of type unsigned char:
unsigned char var_name;
unsigned short temp;
std::cin >> temp;
if ( std::cin )
{
var_name = static_cast<unsigned char>( temp );
std::cout << var_name << '\n';
}
else
{
//TODO: handle error
}
The static_cast is not necessary, but some compilers may emit a warning due to the truncation, which will probably be suppressed by the cast. Also, using the cast makes the code more readable, because it becomes obvious that the value is being truncated.
However, I generally do not recommend that you use operator >> for user input, because it will do strange things, such as
not always read one line of input at a time, and
accept garbage such as "6sdfj23jlj" as valid input for the number 6, although the input should probably be rejected in this case.
If you want to read a number from the user with proper input validation, I recommend that you take a look at my function get_int_from_user in this answer of mine to another question.
This is the code I wrote to convert integer to string.
#include <iostream>
using namespace std;
int main()
{
string s;
int b=5;
s.push_back((char)b);
cout<<s<<endl;
}
I expected the output to be 5 but it is giving me blank space.
I know there is another way of doing it using stringstream but I want to know what is wrong in this method?
Character code for numbers are not equal to the integer the character represents in typical system.
It is granteed that character codes for decimal digits are consecutive (N3337 2.3 Character sets, Paragraph 3), so you can add '0' to convert one-digit number to character.
#include <iostream>
using namespace std;
int main()
{
string s;
int b=5;
s.push_back((char)(b + '0'));
cout<<s<<endl;
}
You are interpreting the integer 5 as a character. In ASCII encoding, 5 is the Enquiry control character as you lookup here.
The character 5 on the other hand is represented by the decimal number 53.
As others said, you can't convert an integer to a string the way you are doing it.
IMHO, the best way to do it is using the C++11 method std::to_string.
Your example would translate to:
using namespace std;
int main()
{
string s;
int b=5;
s = to_string(b);
cout<<s<<endl;
}
The problem in your code is that you are converting the integer 5 to ASCII (=> ENQ ASCII code, which is not "printable").
To convert it to ASCII properly, you have to add the ASCII code of '0' (48), so:
char ascii = b + '0';
However, to convert an integer to std::string use:
std::stringstream ss; //from <sstream>
ss << 5;
std::string s = ss.str ();
I always use this helper function in my projects:
template <typename T>
std::string toString (T arg)
{
std::stringstream ss;
ss << arg;
return ss.str ();
}
Also, you can use stringstream,
std::to_string doesn't work for me on GCC
If we were writing C++ from scratch in 2016, maybe we would make this work. However as it choose to be (mostly) backward compatible with a fairly low level language like C, 'char' is in fact just a number, that string/printing algorithms interpret as a character -but most of the language doesn't treat special. Including the cast. So by doing (char) you're only converting a 32 bit signed number (int) to a 8 bit signed number (char).
Then you interpret it as a character when you print it, since printing functions do treat it special. But the value it gets printed to is not '5'. The correspondence is conventional and completely arbitrary; the first numbers were reserved to special codes which are probably obsolete by now. As Hoffman pointed out, the bit value 5 is the code for Enquiry (whatever it means), while to print '5' the character has to contain the value 53. To print a proper space you'd need to enter 32. It has no meaning other than someone decided this was as good as anything, sometime decades ago, and the convention stuck.
If you need to know for other characters and values, what you need is an "ASCII table". Just google it, you'll find plenty.
You'll notice that numbers and letters of the same case are next to each other in the order you expect, so there is some logic to it at least. Beware, however, it's often not intuitive anyway: uppercase letters are before lowercase ones for instance, so 'A' < 'a'.
I guess you're starting to see why it's better to rely on dedicated system functions for strings!
I need to read in a value (cin) including a dollar sign and a dollar amount, but I only want to read in the amount.
In other words, I have this input:
"$3458.5,"
but I want to read in and store
"3458.5"
The current approach I thought of was reading the value in as a string, removing the first character, and then converting to a double. But, I feel like this method is inefficient and there's a better method out there. Any tips? Thanks!
I agree with Magnus: this seems minor. But if you really want to do it, just read a character then read a double:
char ch;
double d;
std::cin >> ch >> d;
if(stream.peek() == '$') stream.get();
stream >> amount;
C++98/03 had a money_get facet to do things like this. Unfortunately, using it was fairly painful (to put it nicely).
C++11 added a get_money manipulator to make life quite a bit simpler. It works something like this:
#include <iostream>
#include <iomanip>
int main() {
long double amt;
std::cin.imbue(std::locale(""));
std::cout.imbue(std::locale(""));
std::cin >> std::get_money(amt);
std::cout << std::showbase << std::put_money(amt) << "\n";
}
Now, there are a couple of things to be aware of here. First and foremost, the conversion from the external to internal representation isn't specified, but in the implementations I've seen, $3458.5 will not be read as 3458.5--it'd be read and stored as 345850 -- that is, a count of the number of pennies.
When you use put_money to write the data back out, however, it'll be converted symmetrically with whatever was done during input, so if you entered $3458.5, it'll be written back out the same way.
There is one other caveat: I've seen at least one implementation that was strangely finicky about input format, so it required either 0 or 2 digits after the decimal point during input, so either $3458.50 or $3458 would read fine, but $3458.5 wouldn't be read at all (it'd be treated as a failed conversion).
If you use scanf instead of cin, you can drop the $ if you know it will always be there and write the information directly to a float.
float d;
scanf("$%f", d);
cout << "Enter a positive integer or zero: ";
getline(cin, streamStr);
stringstream(streamStr) >> number;
if (!number) {
cout << "invalid input detected or the input is too big.\n";
return 1;
}
inputs like "%234" or "sdf2334" always fall to 0 , which is false in bool expression, but 0 is still a number.
How to check if the input is really invalid like "%234"??
You need to check the returned value of the operator>>, which is not the same as the value of the variable you're reading into:
if (stringstream(streamStr) >> number) {
...
So what's the returned value, then? If you check the docs, you'll see it's a stream itself. It goes to the operator bool of it (because it's used in an if statement), which in turn returns the validity of the stream, or, IOW, if the last operation succeeded.
If you want to ensure the stream doesn't contain anything besides the number use
if (sstream.rdbuf()->in_avail() > 0) {
// something is still there
And to skip whitespace at the end if you want to allow it:
sstream >> std::ws;
So, all in all...
template<typename T,
// those are optional
enable_if<is_default_constructible<T>::value>::type,
enable_if<is_input_streamable<T>::value>::type
>
optional<T> myRead(string input, bool allowTrailingWs = true) {
stringstream str(input);
T val;
// check parsing
if (!(str >> val))
return none;
// allow whitespace at the end
if (allowTrailingWs)
str >> std::ws;
// check if there's any garbage left
if (str.rdbuf()->in_avail() > 0)
return none;
return val;
}
The code above is just for illustration purposes. Shall you need more advanced parsing, check out Boost.Spirit.
Also, apparently this isn't guaranteed to work every time. Using:
auto inputEnd = ss.tellg();
ss.seekg(0, std::ios::end);
if (inputEnd == ss.tellg()) {
To check if the ss is empty could help fix that.
I don't think you understand how streams work. Allow me to address your misconception:
The stream won't attempt to extract any value into number if the data being evaluated doesn't correspond to formatting requirements of the type. Extraction works by the stream iterating through each character in the character sequence one by one, and testing each character as a viable datum for the type to which the extraction is targeted. If the character is not viable, extraction stops (this is why you are seeing success upon entering something like "2342fdsf"; the stream will keep extracting until it finds an invalid character. "2342" are valid characters for an integer while "f" is not)
If the stream finds an invalid character, nothing further is done to the variable (in this case number). In fact, it is implementation-defined what value an uninitialized variable has if extraction failed to produce any characters. With that in mind, it is potentially dangerous to check the value of the operand to determine if I/O failed. This is where checking the stream state comes in:
std::istringstream iss(streamStr);
if (iss >> number)
{
std::cout << "Extraction produced: " << number << '\n';
}
If the extractions fails, the stream will set the appropriate bits. The stream will then be implicitly converted to a boolean using operator bool() (or operator void*() pre-C++11 where it will subsequently undergo conversion to boolean). The boolean function will check the stream state using !this->fail() (which checks both badbit and failbit) and if the function returns true, the if body will be executed.
If the stream is not in a good state (!this->fail() returns false), that means the extraction failed to produce a value and the if statement body goes unevaluated.
By encasing the extraction in a conditional check, not the value of the thing you tried to extract into.
Assuming number must be a char value, try using the cctype library which is helpful for dealing with strings. It has functions such as
isdigit(Char_Exp) //Returns true if the value is a digit
and
isctrl(Char_Exp) //Returns true if the value is a control character like %(modulus)
Here is a link to a C++ cctype library reference: cctype library reference
To test number I would advise you create a function of type Boolean and so that it tests all possible input errors at once.
I want to get a string of numbers one by one, so I'm using a while loop
with cin.get() as the function that gets my digits one by one.
But cin.get() gets the digits as chars and even though I'm trying to use
casting I can't get my variables to contain the numrical value and not the ascii value
of the numbers I get as an input.
cin.get can’t parse numbers. You could do it manually – but why bother re-implementing this function, since it already exists?*
int number;
std::cin >> number;
In general, the stream operators (<< and >>) take care of formatted output and input, istream::get on the other hand extracts raw characters only.
* Of course, if you have to re-implement this functionality, there’s nothing for it.
To get the numeric value from a digit character, you can exploit that the character codes of the decimal digits 0–9 are consecutive. So the following function can covert them:
int parse_digit(char digit) {
return digit - '0';
}