Can't display the entire string when translating CHAR to INT - c++

In my intro class, I'm tasked with translating a phone number that may have letters in it, back to a pre-determined list of numbers (like 1-800-COLLECT would display as 1-800-2655328) and currently, I can translate the letters to numbers but for whatever reason, the non-letters in the phone numbers arent being translated. This is the main function:
int main()
{
string original;
cout << "Please enter a phone number with letters: ";
getline(cin, original);
cout << "This is your number without letters: ";
for (int i = 0; i < original.length(); i++)
{
if (original[i] < 0 || original[i] > 9)
{
translate(original[i]);
}
else
cout << original[i];
}
}
The translate function simply takes whatever element its fed and, if it falls between Aa - Zz it will display a predetermined number. (Aa - Cc would display the number 2, etc) So far it works for translating, as when I put in "1800GOTJUNK" it returns "4685865" fine, but won't acknowledge the "1800" before it, I think there's something wrong with how I'm structuring the if and for statements to display everything correctly, can someone give me some advice?

This:
if (original[i] < 0 || original[i] > 9)
Is comparing against the ASCII codes 0 and 9, not the actual characters.
It should be:
if (original[i] < '0' || original[i] > '9')

Related

Odd behavior from character array

I am trying to write a helper program for Wordle which will display all of the letters which have not been eliminated and the letters which have been confirmed. I've broken the program into functions, and I'm having an issue with the confirmed_letters() function.
I have this array declared in the global scope:
char* word[NUM_LETTERS];
and it's initialized like this:
for (int i = 0; i < NUM_LETTERS; i++) word[i] = new char(char(42));
Here's the function:
void confirmed_letters() {
int num_let = 0; // the # of confirmed letters
int temp_num; // holds the position of the confirmed letter
char temp_letter;
std::cout << "\n\nHow many letters have you confirmed?\n" <<
"Enter only the letters whose positions are known. ";
std::cin >> num_let;
std::cin.ignore(1000, '\n');
if (num_let == 0) return;
std::cout << "Enter the integer position of the confirmed letter, " <<
"followed by the letter. Press the enter (return) key between each entry.\n";
for (int i = 0; i < num_let; i++) {
//temp_num = -1; // I don't think this is needed
std::cin >> temp_num;
std::cin.ignore(1000, '\n');
if (temp_num > 5 || temp_num < 1) {
std::cout << "Invalid letter position. Enter an integer between 1 and 5.\n";
i--;
goto end;
}
std::cin >> temp_letter;
std::cin.ignore(1000, '\n');
word[temp_num - 1] = &temp_letter;
end:
display_word();
}
return;
}
display_word() is just a function to display the word.
Here's the output I got:
How many letters have you confirmed?
Enter only the letters whose positions are known. 3
Enter the integer position of the confirmed letter, followed by the letter. Press the enter (return) key between each entry.
1
o
o * * * *
2
i
i i * * *
3
e
e e e * *
So, for some reason, each additional letter is modifying the previous letters. I don't understand what is going on here. Each time the value of one of the elements of word[] is modified, it should only modify one element, but it's modifying all of them. Thoughts?
word[temp_num - 1] = &temp_letter; stores the address of a local variable that will be reused on the next loop iteration and hold whatever new value the user inputs. The old value will be lost, so it'll look like all of the used slots store the same letter. Because they do. Worse, the variable goes out of scope at the end of the function and will no longer be valid. This is dangerous as the pointer lives on and might even give what looks to be correct results.
Solution: Don't store pointers to letters in word. Store the letters themselves.
char word[NUM_LETTERS];
Initialize like this:
for (int i = 0; i < NUM_LETTERS; i++) word[i] = '*';
// use the character not the code. It's easier to understand the intent of
// * than the number 42 and not all systems will use 42 for *.
and store
word[temp_num - 1] = temp_letter;

C++ cin.ignore To ignore spaces, numbers, and characters to test a palindrome

I need to process a user input to see if it is a palindrome. Our professor said to use cin.ignore() to ignore spaces, numbers, and other characters so we will just compare the letter inputs.
So far I have just found code that ignores just one of these at a time and the code is more advanced than my learning so I do not know how to modify or apply it to my code.
I have the code to check the palindrome, I just do not know how to make it ignore the unwanted inputs.
Sorry this sort of question has been asked many times over but I cannot seem to figure it out.
Thanks in advance.
do
{
checkInput = false;
cout << "Enter the Palindrome: ";
getline(cin, input);
len = input.length();
if (len == 0)
{
cout << "\nNo data was entered, please enter a palindrome.\n";
checkInput = false;
}
} while (checkInput);
for (int i = 0, j = input.size() - 1; i < input.size(); i++, j--)
{
if (input[i] != input[j] && input[i] + 32 != input[j] && input[i] - 32 != input[j])
{
isPalindrome = false;
break;
}
}
if (isPalindrome)
{
cout << "This is a Palindrome!!" << endl;
}
else
{
cout << "This is not a Palindrome." << endl;
}
im assuming that input is a string. if so then what we want to do before your for loop is have another for loop to run through the string and remove anything unwanted from the string. I am going to assume that all you want to deal with are the upper and lowercase letters, as we are focusing on the ascii values between 65-90 and 97-122. source http://www.ascii-code.com/
to so do we can simply check each index in the string to see if it falls between these two ranges, and if it doesn't, then delete it.
for(unsigned int i = 0; i<input.size();i++)
{
if(input[i]< 65 || (90 <input[i] && input[i] < 97) || input[i] > 122)
{
input.erase(i,1);
i--
}
}
that should work.

String with an interchangeable letter

The directions for my assignment are as follows:
Return the number of times that the string "hope" appears anywhere in the given string, except we'll accept any letter for the 'p', so "hode" and "hooe" count.
I am struggling to figure out how to make the third letter equal anything and still have the program identify that it is correct.
My code so far is quite obviously wrong but ill include it nonetheless.
one big problem is i can't tell the array to check if it matches the string.
int wordsFunction(string words)
{
int num = 0;
for(int i = 0; i < words.length(); i++)
{
if(words[i] == "Hope" || words[i] == "hope")
{
num++;
}
}
return num;
}
main()
{
string words;
cout << "Enter a string: ";
getline(cin, words);
cout << wordsFunction(words);
My code so far is quite obviously wrong
That is true. I wouldn't explain why your code is wrong, and go straight to a description of a fix.
Your main reads the string that allows spaces, which is good: the I/O part of your code does not need to be changed.
Now observe that to detect the word "ho*e", with * denoting any single character, at a position i in a word w, you need to check that w[i] is an 'h', w[i+1] is an 'o', w[i+3] is an 'e', and that the index i+3 is valid. This becomes a simple check:
if (i+3 < w.size() && w[i] == 'h' && w[i+1] == 'o' && w[i+3] == 'e') {
count++;
}

Integer input restricted to four digits only

I'm doing a problem where it asks to input an account number, which consists only of four digits. This has to be accomplished with basic beginner C++.
I need to figure out a way to restrict the input of the integer to four digits. A user should be able to put in 0043 or 9023 or 0001 and it should be an acceptable value....
I think I know how to accomplish it with a string.... getline(cin,input) and then check if input.length()==4?
But I've no idea how I would even do this with an integer input.
Note that if 0043 is intended to be distinct from 43, then the input is not in fact a number, but a digit string, just like a telephone "number".
Read the line as a string input.
Check that the length of input is 4.
Check that each character in the string is <= '9' and >= '0'.
Something like:
std::string read4DigitStringFromConsole()
{
bool ok = false;
std::string result;
while (!ok)
{
std::cin >> result;
if (result.length() == 4)
{
bool allDigits = true;
for(unsigned index = 0; index < 4; ++index)
{
allDigits = allDigits && (
(result[index] >= '0') &&
(result[index] <='9')
);
}
ok = allDigits;
}
}
return result;
}
Something like this should work. Once the user enters something with exactly four characters you can validate it. The rest of the logic is up to you.
#include <iostream>
#include <string>
int main() {
std::cout << "Enter a PIN Number: ";
std::string pinStr;
while(std::getline(std::cin,pinStr) && pinStr.size() != 4) {
std::cout << "Please enter a valid value\n";
}
}
Should you want to store it in an integer form, holding the integers in an std::vector might be beneficial. You can do this easily (loop unrolling was for clarity):
#include <iostream>
#include <string>
#include <vector>
int main() {
std::cout << "Enter a PIN Number: ";
std::string pinStr;
while(std::getline(std::cin,pinStr) && pinStr.size() != 4 ) {
std::cout << "Please enter a valid value\n";
}
std::vector<int> pin;
pin[0] = pinStr[0] - '0';
pin[1] = pinStr[1] - '0';
pin[2] = pinStr[2] - '0';
pin[3] = pinStr[3] - '0';
//pin now holds the integer value.
for(auto& i : pin)
std::cout << i << ' ';
}
You can see it running here
I like your idea to use a string as the input. This makes sense because an account "number" is simply an identifier. You don't use it in calculations. By if (sizeof(input)==4) I think you are trying to check the length of the string. The correct way to do this is if (input.length() == 4). This will check that the user inputs 4 characters. Now you need to make sure that each of the characters is also a digit. You can do this easily by taking advantage of the fact that the ASCII codes for digit characters are ordered as you expect. So if (input[i] >= '0' && input[i] <= '9') will do the trick with an appropriate for loop for the index i. Also, you probably need some kind of loop which continues to ask for input until the user enters something which is deemed to be correct.
Edit:
As an alternative to checking that each character is a digit, you can attempt to convert the string to an int with int value = atoi(input.c_str());. Then you can easily check if the int is a four-or-less-digit number.
// generic solution
int numDigits(int number)
{
int digits = 0;
if (number < 0) digits = 1; // remove this line if '-' counts as a digit
while (number) {
number /= 10;
digits++;
}
return digits;
}
similar to this post.
Then you can call this function to check if the input is 4 digits.
You probably want your code to be responsive to the user input, so I would suggest getting each character at a time instead of reading a string:
std::string fourDigits;
char currentDigit;
std::cout << "Enter 4 digits\n";
for(int i = 0; i < 4; ++i)
{
currentDigit = getch();
if(isdigit(currentDigit))
{
fourDigits += currentDigit;
std::cout << currentDigit; // getch won't display the input, if it was a PIN you could simply std::cout << "*";
}
else
{
// Here we reset the whole thing and let the user know he entered an invalid value
i = 0;
fourDigits = "";
std::cout << "Please enter only numeric values, enter 4 digits\n";
}
}
std::cout << "\nThe four digits: " << fourDigits.c_str();
This way you can handle gracefully invalid character instantly. When using strings, the input will only be validated once the user hits Enter.
So I was going over how I can use an integer type to get the input, and looked at char... since it's technically the smallest integer type, it can be used to get the code... I was able to come up with this, but it's definitely not refined yet (and I'm not sure if it can be):
int main() {
int count=0;
while(!(count==4)){
char digit;
cin.get(digit);
count++;
}
return 0;
}
So, the loop keeps going until 4 characters are collected. Well, in theory it should. But it doesn't work. It'll stop at 2 digits, 5 digits, etc.... I think it could be the nature of cin.get() grabbing white space, not sure.

Caesar cipher input text file

I am trying to create a Caesar cipher using C++. I have the program read in a text file but I need it to encrypt the text and output to the screen.
This is my encryption code but I can't seem to get it to work. I have only just started using C++ and not really sure where to go from here.
cout << "enter a value between 1-26 to encrypt the text: ";
cin >> shift;
while ((shift <1) || (shift >26)) {
cout << "Enter a value between 1 and 26!: ";
cin >> shift;
}
int size = strlen(text);
int i=0;
for(i=0; i<size; i++) {
cipher[i] = (text[i]);
if (islower(text[i])) {
if (text[i] > 122) {
cipher[i] = ( (int)(text[i] - 26) + shift);
}
} else if (isupper(text[i])) {
if (text[i] > 90) {
cipher[i] = ( (int)(text[i] - 26) + shift);
}
}
}
cipher[size] = '\0';
cout << cipher << endl;
First of all, your algorithm is wrong.
If we assume ASCII input then you need to encrypt the values that are between 32 (i.e. space) and 126 (i.e. tilde ~), inclusive. You do this by adding the key (a single number) to the value. If the result is greater than 126 (your highest available character) you need to wrap around and start counting from 32. This means 126 + 1 = 32, 126 + 2 = 33, etc. Look up "modulo".
I recommend you look-up the word "debugging". Generally, when you have an algorithm you write code that matches the algorithm as best you can. If the results are not the expected ones then you step line by line using the debugger until you find the line were your expected results and your code's result no longer match.
reformatted, made compilable ad fixed algorithm (to what i think was tried to achieve)
#include <iostream>
using namespace std;
char text[] = {"This is my encryption code but I can't seem to get it to work. "
"I have only just started using C++ and not really sure where "
"to go from here."};
char cipher[sizeof(text)];
void main()
{
int shift;
do {
cout << "enter a value between 1-26 to encrypt the text: ";
cin >> shift;
} while ((shift <1) || (shift >26));
int size = strlen(text);
int i=0;
for(i=0; i<size; i++)
{
cipher[i] = text[i];
if (islower(cipher[i])) {
cipher[i] = (cipher[i]-'a'+shift)%26+'a';
}
else if (isupper(cipher[i])) {
cipher[i] = (cipher[i]-'A'+shift)%26+'A';
}
}
cipher[size] = '\0';
cout << cipher << endl;
}
A few things:
You are checking if the character islower and then checking if the
ascii value is > 122. This will never be true. In the default
locale (standard ascii), islower() will only be true if the ascii
value is in the range [97, 122] (a-z). The same goes for
isupper(). It only returns true for ascii values between 65 and
90, inclusive.
You are already working with ascii values anyway, so islower() and isupper() may be redundant. Those are equivalent to doing bounds checking on the ranges, i.e. text[i] >= 97 && text[i] <= 122. They are useful shortcuts, but don't base your code around them if you can simplify.
Your code never adds the caesar shift if the value is <= 90/122, so you will never shift anything.