I was trying to write Fizz Buzz and I came across an unexpected interaction. If I do std::cout << i, it automatically converts i (int) into a string and prints it? But if assign i to a string variable, it prints a blank instead? I managed to solve it by using std::to_string, but I was just wondering why printing to_print prints a blank instead of either an integer or throwing some sort of error?
#include <iostream>
#include <string>
int main() {
for (int i = 1; i <= 10; i++) {
// prints i
std::cout << i;
}
std::cout << std::endl;
for (int i = 1; i <= 10; i++) {
std::string to_print;
to_print = i;
// prints blank rather than i
std::cout << to_print;
}
}
There is no string::operator=(int), but there is string::operator=(char), which is selected as the best viable candidate.
So you're assigning single characters with codes 1..10 to the string, which apparently get printed by your terminal as blanks.
Try assigning 65, it should print A.
Your variable i gets converted to a character based on its value and the ASCII table. The first few characters are not visible.
Changing your code to start iterating at 49 which is the decimal value for the character "0":
for (int i = 49; i <= 57; i++) {
std::string to_print;
to_print = i;
std::cout << to_print;
}
It prints: 123456789
ASCII table is the most likely culprit. Your "string" contained control characters that aren't printed.
This happened because when you assigned the integer, the compiler treated it like a character. This is because char can be treated like a small integer.
Per asciitable.com, your string contained characters like linefeed, bell, horizontal tab, etc.
for (int i = 1; i <= 10; i++) {
// prints i
std::cout << i;
}
Here std::cout knows that it has to print int so no problem.
for (int i = 1; i <= 10; i++) {
std::string to_print;
to_print = i;
// prints blank rather than i
std::cout << to_print;
}
Here you put an int into a std::string so it takes your number (0, 1, 2, etc.) as a char so as ASCII.
Try to extend your for loop to 255 instead of 10, you will see other characters.
Like #rustyx said:
There is no string::operator=(int), but there is
string::operator=(char), which is selected as the best viable
candidate.
You can translate an int to std::string with to_string.
Data is stored in computer in bits. When you trying to Assign integer variable value to to a char datatype variable or String variable it will read memory contents of that variable as a bits and at printing time it will recognized as string datatype so its Look up for Ascii Value. while in case of integer printing it treat bits as a integer..
Related
I use atoi() to convert argv to int, the problem is when argv = zero is a considered parameter in my problem, it will return zero as well.
I tried to loop about all the arguments except file name for sure, what to do ?
for (int i = 2; i < argc; i++) {
if (!atoi(argv[i]) && atoi(argv[i]) != zero) {
std::cout << "invalid" << std::endl;
return 0;
}
}
I used few cases like == zero, || instead of && and so on, same problem always .. I even used strtol but same problem as well, I dunno if it's a problem with the algorithm, but I thought about it for a long time.
edit : my arguments are like next : a1.exe add 3 2 1 4 .. I started i = 2 to begin with 3, my arguments are all numbers. the atoi returns 0 if an argument is letter or zero so I want zero to be accepted as a parameter since it's a number. Sorry if I sounded vague or something
reason for editing : people misunderstood my question.
If you want to convert a number and know wether the input string was correct, then you can use the std::strtol family of functions.
http://www.cplusplus.com/reference/cstdlib/strtol/
const char *val = "123abc";
char *end = nullptr;
int i = std::strtol(val, &end, 10);
if (end != &val[strlen(val)])
std::cout << "invalid characters in number" << std::endl;
end points to the first character not converted, so if the whole string is a valid number, it points to the end of it.
You can do the following.
SO your Problem is that you can't determine if your argv[i] contains either a numeric 0 or a letter or other sign.
for (int i = 2; i < argc; i++) {
for(int x = 0; x < strlen(argv[i])){
if(!isDigit(argv[i][x])){
std::cout << "invalid" << std::endl;
return 0;
}
}
}
In this example we get the size of the actual char array that's contained inside of argv[i] than we check every single char if it is a digit.
If it's not we write "invalid" onto the console and return 0;
ofc you probably need to make some exceptions but I think this could be a decent start and help you with your problem
I need to program a lotto generator for my education that will randomly roll numbers and check for duplicate entries and replace them otherwise. When I start the program there are no error messages and the program runs but I only see strange characters instead of numbers. A picture of the problem
What is wrong with my code?
#include <iostream>
#include <array>
#include <time.h>
std::array<unsigned char, 6> lottoZahlen = {0, 0, 0, 0, 0, 0};
void arrayFuellen();
unsigned char checkDuplikate(unsigned char);
void arraySortieren();
int main()
{
arrayFuellen();
arraySortieren();
std::cout << "\n---- Ihre Glueckszahlen lauten: ----" << std::endl;
for (unsigned char lottoGlueck : lottoZahlen)
{
std::cout << lottoGlueck << std::endl;
}
std::cout << "---- Glueckszahlen Ende ----" << std::endl;
}
void arrayFuellen()
{
srand(time(NULL));
unsigned char wuerfelZahl = 0;
unsigned char wuerfelZahlChecked = 0;
for (unsigned char i = 0; i < sizeof(lottoZahlen); i++)
{
wuerfelZahl = rand() % 45 + 1;
wuerfelZahlChecked = checkDuplikate(wuerfelZahl);
lottoZahlen[i] = wuerfelZahlChecked;
}
}
unsigned char checkDuplikate(unsigned char checkZahl)
{
srand(time(NULL));
bool dublette = false;
do
{
dublette = false;
for (unsigned char j = 0; j < sizeof(lottoZahlen); j++)
{
if (checkZahl == lottoZahlen[j])
{
checkZahl = rand() % 45 + 1;
dublette = true;
}
}
} while (dublette);
return checkZahl;
}
void arraySortieren()
{
unsigned char merker = 0;
bool vertauscht = false;
do
{
vertauscht = false;
for (unsigned char i = 1; i < sizeof(lottoZahlen); i++)
{
if (lottoZahlen[i - 1] > lottoZahlen[i])
{
merker = lottoZahlen[i];
lottoZahlen[i] = lottoZahlen[i - 1];
lottoZahlen[i - 1] = merker;
vertauscht = true;
}
}
} while (vertauscht);
}
"char" is a type that is used to store characters, and the output stream will interpret it as such in your for-loop. So if you have value 65, it will actually be displayed as a capital A (which has ASCII value 65). To display numbers, you should use a type that the output stream recognizes as a number, such as "int".
There are several ways of doing what you want, printing char as integer/decimal value:
using casging int():
std::cout << int(lottoGlueck) << "\n";
using good old (C style) printf(), some would say do not use this, but there are advantages and disadvantages to using printf().
printf("%d\n", lottoGlueck);
As suggested, you can use std::to_string(), I personally do not recommend this for printing a single character, simply because it converts a character to a string to print out an integer.
In production code I use number 1, in debugging I use 2. There are disadvantages/advantages to using both, but you can read this to better understand those.
When it comes to pinging strings as decimal values, you have std::to_string() and also std::cout << std::dec << string << "\n".
you are printing non printable characters:
https://upload.wikimedia.org/wikipedia/commons/d/dd/ASCII-Table.svg
the ones between [] are not printable characters.
if you write: int i = 5 and then std::cout << i
it will print the corresponding character, with value 5. But the value 5 is not the character '5', so if you expect it to be a printable number, you need to convert it:
std::cout << std::to_string(i)
(not sure if this was your intention though :) )
In addition to the answers to your question, you can check whether your value is printable or not by using isprint().
std::cout << isprint(lottoGlueck) << std::endl;
This will print 0 (false) if your value is non-printable.
Problem:
I was trying to encrypt a std::string password with a single rule:
Add "0" before and after a vowel
So that bAnanASplit becomes b0A0n0a0n0A0Spl0i0t.
However, I got stuck in an infinite loop.
Here is the code:
const std::string VOWELS = "AEIOUaeiou";
std::string pass = "bAnanASplit";
//Add zeroes before and after vowels
for (int i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
std::cout << pass << "\n";
if(i != std::string::npos)
{
std::cout << pass[i] << ": " << i << "\n";
pass.insert(pass.begin() + i++, '0');
pass.insert(pass.begin() + ++i, '0');
}
}
...And the result:
bAnanASplit
A: 1
b0A0nanASplit
a: 5
b0A0n0a0nASplit
A: 9
b0A0n0a0n0A0Split
i: 15
b0A0n0a0n0A0Spl0i0t
b0A0n0a0n0A0Spl0i0t
A: 2
b00A00n0a0n0A0Spl0i0t
a: 8
b00A00n00a00n0A0Spl0i0t
A: 14
b00A00n00a00n00A00Spl0i0t
i: 22
b00A00n00a00n00A00Spl00i00t
b00A00n00a00n00A00Spl00i00t
...
Any help? This sure seems strange.
Edit: All the answers were useful, and therefore I have accepted the one which I think best answers the question. However, the best way to solve the problem is shown in this answer.
Never, ever, modify the collection/container you are iterating upon!
Saves you a lot of trouble that way.
Let's start with your code and generate a new string with vowels surrounded by 0.
const std::string VOWELS = "AEIOUaeiou";
std::string pass = "bAnanASplit", replacement;
//Add zeroes before and after vowels
for (auto ch : pass)
{
if(VOWELS.find(ch) != std::string::npos)
replacement += '0' + ch + '0';
else
replacement += ch;
}
And there you have it!
As the OP seems to look for the exact reason for the misbehavior, I thought to add another answer as the existing answers do not show the exact issue.
The reason for the unexpected behavior is visible in following lines.
for (int i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
...
Problem 1:
The loop counter i is an int (i.e. a signed int). But std::string::find_first_of returns std::string::npos if there's no match. This is usually the maximum number representable by an unsigned long. Assigning a huge unsigned value to a shorter signed variable will store a totally unexpected value (assuming you are not aware of that). In this case, i will becomes -1 in most platforms (try int k = std::string::npos; and print k if you need to be sure). i = -1 is valid state for the loop condition i < pass.length(), so the next iteration will be allowed.
Problem 2:
Closely related to the above problem, same variable i is used to define the start position for the find operation. But, as explained, i will not represent the index of the character as you would expect.
Solution:
Storing a malformed value can be solved by using the proper data type. In the current scenario, best options would be using std::string::size_type as this is always guaranteed to work (most probably this will be equal to size_t everywhere). To make the program work with the given logic, you will also have to use a different variable to store the find result.
However, a better solution would be using a std::stringstream for building the string. This will perform better than modifying a string by inserting characters in the middle.
e.g.
#include <iostream>
#include <sstream>
int main() {
using namespace std;
const string VOWELS = "AEIOUaeiou";
const string pass = "bAnanASplit";
stringstream ss;
for (const char pas : pass) {
if (VOWELS.find(pas) == std::string::npos) {
ss << pas;
} else {
ss << '0' << pas << '0';
}
}
cout << pass << "\n";
cout << ss.str() << endl;
}
You are not exiting the loop in case i becomes std::string::npos. So, the i value is changed to some unexpected value (likely something like -1) when it gets to the position of last i or 0 after i(here I am referring to i of split). This is because i is an signed integer but in this case find_first_of() returns std::string::npos which is largest value that can be held by a size_t. In that case the terminating condition i < pass.length() may hold true and the loop continues. So, I am recommending following changes in your code -
for (size_t i = 0; i < pass.length(); ++i)
{
i = pass.find_first_of(VOWELS, i);
if(i == std::string::npos)
break;
pass.insert(pass.begin() + i++, '0');
pass.insert(pass.begin() + ++i, '0');
}
On the same note if (i != std::String::npos) does not do what you are expecting it to do.
But then again it better not to modify the container while you are iterating over it which #Tanveer mentioned in his answer
I have to convert a decimal value into a string that shows the binary value, e.g. given 8, I need to print a string "1000". I have the conversion from decimal to binary, but when I print the values directly form the char array, I get little question marks instead of numbers. I know it has something to do with the way char arrays read values, but I can't figure out how to correct the issue.
void dec2Bin(int value, char binaryString[]) {
int remainder = 0;
int binDigit = 0;
int i = 0;
while (value != 0) {
binDigit = value % 2;
value /= 2;
binaryString[i] = char(binDigit);
i++;
}
for (int k = i - 1; k > 0; k--) {
cout << binaryString[k];
}
}
int main()
{
cout << "Enter a decimal number: ";
int num;
cin >> num;
char binaryString[20] = "";
dec2Bin(num, binaryString);
return 0;
}
When you do
binaryString[i] = char(binDigit);
you are assigning the decimal value 0 or 1 to binaryString[i]. That's okay, a char is basically nothing more than a small integer.
The problems comes when you want to print the value, as the only overloaded << operator to handle char treats the characters as a character, and in most encodings the values 0 and 1 are not printable.
There are two solutions:
Either you convert the character you want to print into a larger integer which won't be treated as a character:
cout << static_cast<int>(binaryString[k]);
Or you make the array contain actual printable characters instead:
binaryString[i] = binDigit + '0';
So, I am trying to figure out the best/simplest way to do this. For my algorithms class we are supposed read in a string (containing up to 40 characters) from a file and use the first character of the string (data[1]...we are starting the array at 1 and wanting to use data[0] as something else later) as the number of rotations(up to 26) to rotate letters that follow (it's a Caesar cipher, basically).
An example of what we are trying to do is read in from a file something like : 2ABCD and output CDEF.
I've definitely made attempts, but I am just not sure how to compare the first letter in the array char[] to see which number, up to 26, it is. This is how I had it implemented (not the entire code, just the part that I'm having issues with):
int rotation = 0;
char data[41];
for(int i = 0; i < 41; i++)
{
data[i] = 0;
}
int j = 0;
while(!infile.eof())
{
infile >> data[j+1];
j++;
}
for(int i = 1; i < 27; i++)
{
if( i == data[1])
{
rotation = i;
cout << rotation;
}
}
My output is always 0 for rotation.
I'm sure the problem lies in the fact that I am trying to compare a char to a number and will probably have to convert to ascii? But I just wanted to ask and see if there was a better approach and get some pointers in the right direction, as I am pretty new to C++ syntax.
Thanks, as always.
Instead of formatted input, use unformatted input. Use
data[j+1] = infile.get();
instead of
infile >> data[j+1];
Also, the comparison of i to data[1] needs to be different.
for(int i = 1; i < 27; i++)
{
if( i == data[1]-'0')
// ^^^ need this to get the number 2 from the character '2'.
{
rotation = i;
std::cout << "Rotation: " << rotation << std::endl;
}
}
You can do this using modulo math, since characters can be treated as numbers.
Let's assume only uppercase letters (which makes the concept easier to understand).
Given:
static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::string original_text = "MY DOG EATS HOMEWORK";
std::string encrypted_text;
The loop:
for (unsigned int i = 0; i < original_text.size(); ++i)
{
Let's convert the character in the string to a number:
char c = original_text[i];
unsigned int cypher_index = c - 'A';
The cypher_index now contains the alphabetic offset of the letter, e.g. 'A' has index of 0.
Next, we rotate the cypher_index by adding an offset and using modulo arithmetic to "circle around":
cypher_index += (rotation_character - 'A'); // Add in the offset.
cypher_index = cypher_index % sizeof(letters); // Wrap around.
Finally, the new, shifted, letter is created by looking up in the letters array and append to the encrypted string:
encrypted_text += letters[cypher_index];
} // End of for loop.
The modulo operation, using the % operator, is great for when a "wrap around" of indices is needed.
With some more arithmetic and arrays, the process can be expanded to handle all letters and also some symbols.
First of all you have to cast the data chars to int before comparing them, just put (int) before the element of the char array and you will be okay.
Second, keep in mind that the ASCII table doesn't start with letters. There are some funny symbols up until 60-so element. So when you make i to be equal to data[1] you are practically giving it a number way higher than 27 so the loop stops.
The ASCII integer value of uppercase letters ranges from 65 to 90. In C and its descendents, you can just use 'A' through 'Z' in your for loop:
change
for(int i = 1; i < 27; i++)
to
for(int i = 'A'; i <= 'Z'; i++)
and you'll be comparing uppercase values. The statement
cout << rotation;
will print the ASCII values read from infile.
How much of the standard library are you permitted to use? Something like this would likely work better:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
int rotation = 0;
std::string data;
std::stringstream ss( "2ABCD" );
ss >> rotation;
ss >> data;
for ( int i = 0; i < data.length(); i++ ) {
data[i] += rotation;
}
// C++11
// for ( auto& c : data ) {
// c += rotation;
// }
std::cout << data;
}
Live demo
I used a stringstream instead of a file stream for this example, so just replace ss with your infile. Also note that I didn't handle the wrap-around case (i.e., Z += 1 isn't going to give you A; you'll need to do some extra handling here), because I wanted to leave that to you :)
The reason your rotation is always 0 is because i is never == data[1]. ASCII character digits do not have the same underlying numeric value as their integer representations. For example, if data[1] is '5', it's integer value is actually 49. Hint: you'll need to know these values when handle the wrap-around case. Do a quick google for "ANSI character set" and you'll see all the different values.
Your determination of the rotation is also flawed in that you're only checking data[1]. What happens if you have a two-digit number, like 10?