I have a given exercise that wants me to find the uppercase letter that is K places from the letter in this case char variable that is named C. The range is uppercase letters from A to Z.
For example if the input is B 3 the output should be E. For this specific input its simple you just sum the values and you get your answer but for example what if we go out of the range. Here is one example F 100 the program should output B because if the value is > than Z the program starts from A.
If there are some confusions I will try to explain it more here are some test cases and my code that only work if we don't cross the range.
Input Output
B 3 E
X 12345 S
F 100 B
T 0 T
#include <stdio.h>
int main(){
int K;
char C,rez;
scanf("%c %d",&C,&K);
int ch;
for(ch = 'A';ch <= 'Z';ch++){
if(C>='A' && C<='Z'){
rez = C+K;
}
}
printf("%c",rez);
return 0;
}
Think of the letters [A-Z] as base 26 where zero is A, one is B and 25 is Z.
As we sum of the letter (in base 26) and the offset, it is only the least significant base 26 digit we have interest, so use % to find the least significant base 26 digit much like one uses % 10 to find the least significant decimal digit.
scanf(" %c %d",&C,&K);
// ^ space added to consume any white-space
if (C >= 'A' && C <= 'Z') {
int base26 = C - 'A';
base26 = base26 + K;
base26 %= 26;
int output = base26 + 'A';
printf("%c %-8d %c\n", C, K, output);
}
For negative offsets we need to do a little more work as % in not the mod operator, but the remainder. This differs with some negative operands.
base26 %= 26;
if (base < 0) base26 += 26; // add
int output = base26 + 'A';
Pedantically, C + K may overflow with extreme K values. To account for that, reduce K before adding.
// base26 = C + K;
base26 = C + K%26;
We could be a little sneaky and add 26 to insure the sum is not negative.
if (C >= 'A' && C <= 'Z') {
int base26 = C - 'A';
base26 = base26 + K%26 + 26; // base26 >= 0, even when K < 0
base26 %= 26; // base26 >= 0 and < 26
int output = base26 + 'A';
printf("%c %-8d %c\n", C, K, output);
}
... or make a complex one-line
printf("%c %-8d %c\n", C, K, (C - 'A' + K%26 + 26)%26 + 'A');
This can be accomplished by using 2 concepts.
ASCII value
Modulus operator (%)
In C every character has an ASCII value. Basically it goes from 0-127.
The character 'A' has the value of 65
The character 'B' has the value of 66 (65 + 1)
and so on...
Until Z which is 65 + 25 = 90
And the 2nd concept I want to highlight in math is modulo arithmetic where if you always want to map a number to certain range, you can use a modulus operator.
Modulus is the reminder that you get after dividing a number by another number.
In our case, we have 26 alphabets so we can always get a number between 0 to 25
For the example you took
100 % 26 = 22
But you have to consider the starting point too.
So, we always subtract the initial alphabet by the value of 'A', i.e. 65 so that 'A' maps to 0 and 'Z' maps to 25
So, if we start with 'F' and need to go 100 places..
Subtract 'A' value from 'F' value. Characters behave like numbers so you can actually store 'F' - 'A' in an integer
In this case 'F' - 'A' = 5
Next we add the offset to this.
5 + 100 = 105
Then we perform modulus with 26
105 % 26 = 1
Finally add the value of 'A' back to the result
'A' + 1 = 'B'
And you are done
Get the remainder of input number with 26 using modulo operator. If sum of input character and remainder is less than or equal to Z then its the answer otherwise again find the remainder of sum with 26 and that will be answer (take care of offset because the ASCII decimal value of letter A is 65).
Roughly the implementation will be:
#include <stdio.h>
int main(){
int K;
char C, rez;
scanf("%c %d",&C,&K);
// Validate the user input
int ch;
int rem = K % 26;
if ((rem + C) - 'A' < 26) {
rez = rem + C;
} else {
rez = ((rem + C - 'A') % 26) + 'A';
}
printf("%c\n",rez);
return 0;
}
Note that, I know there is scope of improvement in the implementation. But this is just to give an idea to OP about how it can be done.
Output:
# ./a.out
B 3
E
# ./a.out
X 12345
S
# ./a.out
F 100
B
# ./a.out
T 0
T
Related
I first did this:
// Convert ASCII range down to a value from 0 to 25
char uppercase[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char lowercase[27] = "abcdefghijklmnopqrstuvwxyz";
char convertedUppercase[27];
char convertedLowercase[27];
for (int i = 0; i <= 26; i++)
{
convertedUppercase[i] = uppercase[i] - 'A';
convertedLowercase[i] = lowercase[i] - 'a';
}
// For each character in the plaintext: (DOESN'T WORK)
for (int i = 0, n = strlen(p); i <= n; i++)
{
// Rotate the character if it's a letter // ci = (pi + k) % 26
if (isalpha(p[i]))
{
if (isupper(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
else if (islower(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
}
}
printf("ciphertext: %s\n", c);
but then I realized that the value of convertedUppercase will just be like 0 = NUL instead of 0 = A. Can anyone give me a hint what to do?
edit:
From the CS50 Discord:
"The caesar cipher formula (p + k) % 26 works on the premise that p (the plain text character) has a value of 0 - 25 (representing a - z or A - Z)
So if your plain char is 'x', that would have a value of 23, and if your key was 2, then the ciphered char would be:
(23 + 2) % 26
( 25 ) % 26
= 25 'z'
I'm kinda lost on how to do it.
This would be so much easier if you would provide a MRE.
I guess what you are observing is that you see a truncated cipertext if you attempt to output it via printf() with "%s".
This is however only because any "A" (that is a ciper A, i.e. after shifting by key) results in a 0 (which terminates string output, being the '\0' terminator) and most other letters result in unprintable characters.
This is because you only shift by key and map to 0-25 what needs to be the number representation (i.e. numeric instead of textual ciper) here:
c[i] = ((p[i]) + k) % 26;
In order to turn into textual cipher instead of numeric ciper, you need to do
convert textual to numeric, with -'A'
shift by key, with +k
map to 0-25, with %26
convert numeric to textual, with +'A'
I.e.
c[i] = ((p[i]-'A') + k) % 26 + 'A';
E.g. "H" from "Hello World".
textual to numeric, 'H' - 'A' -> 7
shift by key, 7 + 4 -> 11
map to 0-25, 11%26 -> 11
numeric to textual, 11 + 'A' -> 'L' is cipher
E.g. "W" from "Hello World".
textual to numeric, 'W' - 'A' -> 22
shift by key, 22 + 4 -> 26
map to 0-25, 26%26 -> 0
numeric to textual, 0 + 'A' -> 'A' is cipher
I have an input data of 4 character string (alphanumeric) or 3 character string and I need to convert these ASCII character string to unique float in 2 digits each, separated by decimal.
Ex:
Input string = 5405, output data = 54.05
Input string = 53BC, output data = 53.199 ( B ascii value is ~ 0x42 in hex and C is 0x43 )
Issue is I am seeing the same output when input strings are 560B and 5618, as both results in same output as 56.18.
Is there a way to uniquely generate a float number in these cases?
Max value of float allowed is 99.999.
Simple math tells us that this is not possible. The number of unique alphanumeric strings of length 4 (case-insensitive) is 36^4 = 1,679,616 while the number of non-negative unique floating point numbers with at most 3 fractional digits and less than 100 is 10^5 = 100,000.
If the string were restricted to hexadecimal digits, there would only be 16^4 = 65,536 possibilities in which case a unique encoding would be possible.
Slightly off-topic: when a mapping is needed into a domain which is too small to accommodate the result of a unique mapping, a hash function is the "standard tool", but collisions must be handled.
Your encoding is somewhat confusing, but here is a simple solution:
use 2 digits for the integral part
use 2 digits for fractional parts 00 to 99
use a combination of 1 letter and 1 letter or digit for fractional parts 100 to 999. There are 26*36 = 936 such combinations, enough to cover the 900 possibilities.
all values from 00.00 to 99.999 can be encoded.
some 4 letter and digit combinations are not used.
the encoding is not unique. eg: 53A0 is 53.100, the same number as 53.10 encoded as 5310.
Here is an implementation:
#include <stdib.h>
double fdecode(const char *s) {
char a[7];
a[0] = s[0];
a[1] = s[1];
a[2] = '.';
if (s[2] >= '0' && s[2] <= '9') {
a[3] = s[3];
a[4] = s[4];
a[5] = '\0';
} else {
// assuming uppercase letters
int n = 100 + (s[3] - 'A') * 36;
if (s[4] >= '0' && s[4] <= '9') {
n += s[4] - '0';
} else {
n += 10 + (s[4] - 'A') % 26;
}
snprintf(&a[3], 4, "%d", n);
}
return strtod(a, NULL);
}
int fencode(char *s, double d) {
char a[7];
if (d >= 0 && snprintf(a, 7, "%06.3f", d) == 6) {
s[0] = a[0];
s[1] = a[1];
if (a[5] == '0') {
s[2] = a[3];
s[3] = a[4];
} else {
int n = atoi(a + 3);
s[2] = 'A' + (n / 36);
n %= 36;
if (n < 10) {
s[3] = '0' + n;
} else {
s[3] = 'A' + n - 10;
}
}
s[4] = '\0';
return 4;
} else {
s[0] = '\0';
return -1;
}
}
I found this problem interesting, as it is given that you need to use the alphabet as an array in C. Task is to brute force every possible K value, in basic Caesar's cipher manner.
However, code I come up with compile non-true values after K = 1. For example, a letter C is turned to Z instead of A etc. Can anyone spot what I did wrong?
#include <stdio.h>
#include <string.h>
void bruteforce (char*);
int main() {
char cyphertext[] = "kyvtrmrcipnzccrkkrtbwifdkyvefikynvjkrkeffe";
bruteforce(cyphertext);
return 0;
}
void bruteforce (char *cyphertext) {
char alphabet[26] = "abcdefghijklmnopqrstuvwxyz";
long int size = strlen(cyphertext);
for (int k = 0; k < 26; k++){
for (long int i = 0; i < size; i++){
for (int j = 0; j < 26; j++){
if (alphabet[j] == cyphertext[i]){
cyphertext[i] = alphabet[j - k];
if (k > j){
cyphertext[i] = alphabet[26 + j - k];
}
break;
}
}
}
printf("%s\n ", cyphertext);
}
}
For Caesar Cypher shifting, you don't need to use the alphabet string. You can just shift the character in ASCII code. ASCII codes of 'a' - 'z' are 97 - 122. Thus if decode with + 1. If the characters are a - z, you can just add one to each character. If after adding the shift value to the character value and the character value become larger than 122 then take the character value and subtract it to 122 then add 96 to that.
For shifting negative, if character value become smaller than 97. Take 97 subtract to character's value. Then subtract 123 to the previous equation value. Nonetheless, I built the code so that negative shift will be convert to positive shift. If the shift is negative we take 26 and add to that. Example is, shifting -1 will make a become z. So that is similar to shifting 26 + -1 = 25.
Shift value can be larger than +25 or smaller than -25. Nonetheless, if it is, it will be modulus to 26.
If you want to bruteforce all the possible combinations for a string. Just use the function below and run it in a loop from 1 to 25. But your function modify the original string. Thus, when doing bruteforce, you would have to copy the string of your function to a temporary string and let the function work on that. The examples are below.
#include <stdio.h>
#include <string.h>
void bruteforce (char *cyphertext, int shiftBy);
int main() {
char cyphertext[] = "kyvtrmrcipnzccrkkrtbwifdkyvefikynvjkrkeffe";
char cyphertext2[] = "yvccf wifd bvmze";
bruteforce(cyphertext, -17);
puts("");
bruteforce(cyphertext2, 9);
/* Bruteforce example */
puts("");
puts("Bruteforce section:");
// +9
char cyphertext3[] = "kyzjkvokzjkfsvtirtb nyrk tre kyzj sv zj zk yvccf nficu";
char temp[50];
for (int i = 1; i < 26; i++){
printf("Trying to crack by shifting %d \n", i );
strcpy(temp, cyphertext3);
bruteforce(temp, i);
puts("");
}
/* End Bruteforce example */
return 0;
}
// If there is no shift i.e 0, 26, 52, -26
// It won't print
void bruteforce (char *cyphertext, int shiftBy){
size_t size = strlen(cyphertext);
if ( shiftBy > 25){
shiftBy = shiftBy % 26;
} else if ( shiftBy < 0 ) {
shiftBy = 26 + (shiftBy % 26);
// If shiftBy is 26
// there is no need to shift.
if ( shiftBy == 26 ) return;
}
// If there is no shift return.
if ( shiftBy == 0 ) return;
for ( size_t i = 0; i < size; i++){
// 97 - 122 is a - z
// if char is a - z
if ( cyphertext[i] > 96 && cyphertext[i] < 123 ){
// add shift by
cyphertext[i] += shiftBy;
// if char > z
// then take char - z then add to the ascii code that just before 'a'.
// Since shiftBy is converted fomr negative to positive.,
// There will not be a negative shiftBy.
if ( (unsigned char)cyphertext[i] > 122 )
cyphertext[i] = ((unsigned char) cyphertext[i]) - 122 + 96;
}
// If want to do A - Z
// ASCII code are 65 - 90.
}
printf("%s\n", cyphertext);
}
I am trying to get the output of this equation :
44 - 10 + 11 / 5
it work properly as follow :
char str[] = "44 - 10 + 11 / 5";
int sum = 0 ;
sum += atoi(str); // 0 + 44
sum += atoi(str+3); // 44 + 10
sum += atoi(str+5); // 54 + 11
sum += atoi(str+7); // 65 / 5 = 13
printf("%d/n",sum); // output = 13
but it doesn't work if I put the atoi() function in the for loop:
char str[] = "44 - 10 + 11 / 5";
int sum = 0;
int i;
sum += atoi(str);
for (i = 0; i < 100; i++) {
if (!(str[i] >= 0 && str[i] <= 9)) { //if str[i] is not a number
sum += atoi(str + i);
}
}
printf("%d/n", sum); // output = 0
You are comparing a char value that contains the ASCII representation of a number, to an actual number. Change
if(!(str[i]>=0 && str[i]<=9)){
to
if(!(str[i]>='0' && str[i]<='9')){
I did not check if the rest of the code is correct, but certainly, this is one issue.
if(!(str[i]>=0 && str[i]<=9)){ //if str[i] is not a number
This is incorrect. '0' and 0 are not same. Neither is 9 and '9'. The value of '9' will be integer that represents '9' in ASCII chart.
Rest of the logic seems suspicious too, for example what happens if you have "55", code will enter if twice, once for 55 and second time for 5, isn't it?
Because your code does not do the same calculations as your previous one. In the first one you are shifting the pointer to the next number and you are adding it to the number, so your code does the following 44 + 10 + 11 + 5.
In the second case you are checking whether the character code is between 0 and 9, but the numbers are between 48 and 57 - the characters '0' and '9'. So the if statement would be always wrong. Your intention was probably this, but it won't work.
for(i = 0; i < 100 ; i++){
if(!(str[i]>='0' && str[i]<='9')){ //if str[i] is not a number
sum += atoi(str+i);
}
}
This also does not work, because here you are doing the wrong shifts of the pointer by one, resulting in the reading of the following numbers: 44, 4, 10, 0, 11, 1, 5. Because of the atoi properties. To perform the exact same code you did before you`d have to write the following code:
int skip_non_diggits(int i, char *str) {
while (str[i] < '0' || str[i] > '9') {
if (str[i] == 0)
return -1; //end of string case
i++;
}
return i;
}
int skip_diggits(int i, char *str) {
while (str[i] >= '0' && str[i] <= '9') {
if (str[i] == 0)
return -1; //end of string case
i++;
}
return i;
}
These functions could be used as follows:
int i = 0, sum = 0;
while (i != -1) {
sum += atoi(str+i);
i = skip_diggits(i, str); // positions i after the current number
i = skip_non_diggits(i, str); // positions i at the begin of the next number
}
BTW
Don't use for (i = 0; i < 100; i++) to iterate through the strings you don't know the size of. If the string is shorter in length than 100 you're derefferencing memory which probably isn't yours creating undefined behavior. Instead check the strlen method or check whether the character is not equal to \0 which in C indicates the end of the string.
This seems a bit odd. What's the goal?
Agree with previous comment.
Why are you doing atoi() on what is NOT a number?
You will go past the end of the string.
Your spaces COUNT in the example
and so on.
you don't update i when you find a number, so you will count "44" as 44 first and 4 second.
If you're trying to learn, hook up a debugger, step through the code, and see how the data changes.
I am trying to understand how the putchar('0' + r); works. Below, the function takes an integer and transform it to binary.
void to_binary(unsigned long n)
{
int r;
r = n % 2;
if (n >= 2)
to_binary(n / 2);
putchar('0' + r);
}
I google the definition of putchar but I didn't find this. To test it, I added a printf to see the value of the r:
void to_binary(unsigned long n)
{
int r;
r = n % 2;
if (n >= 2)
to_binary(n / 2);
printf("r = %d and putchar printed ", r);
putchar('0' + r);
printf("\n");
}
and I run it (typed 5) and got this output:
r = 1 and putchar printed 1
r = 0 and putchar printed 0
r = 1 and putchar printed 1
So I suppose that the putchar('0' + r); prints 0 if r=0, else prints 1 if r=1, or something else happens?
In C '0' + digit is a cheap way of converting a single-digit integer into its character representation, like ASCII or EBCDIC. For example if you use ASCII think of it as adding 0x30 ('0') to a digit.
The one assumption is that the character encoding has a contiguous area for digits - which holds for both ASCII and EBCDIC.
As pointed out in the comments this property is required by both the C++ and C standards. The C standard says:
5.2.1 - 3
In both the source and execution basic character sets, the value of
each character after 0 in the above list of decimal digits shall be
one greater than the value of the previous.
'0' represents an integer equal to 48 in decimal and is the ASCII code for the character 0 (zero). The ASCII code for the character for 1 is 49 in decimal.
'0' + r is the same as 48 + r. When r = 0, the expression evaluates to 48 so a 0 is outputted. On the other hand, when r = 1, the expression evaluates to 49 so a 1 is outputted. In other words, '0' + 1 == '1'
Basically, it's a nice way to convert decimal digits to their ASCII character representations easily. It also works with the alphabet (i.e. 'A' + 2 is the same as C)
It's a common technique used for char handing.
char a = '0' + r (r in [0,9]) will convert an integer to its char format based on given char base (i.e. '0' in this case), you will get '0'...'9'
Similarly, char a = 'a' + r or char a = 'A' + r (r in [0,25]) will convert an integer to its char format, you will get 'a'...'z' or 'A'...'Z' (except for EBCDIC systems which has discontinuous area for alphabets).
Edit:
You can also do the other way around, for example:
char myChar = 'c';
int b = myChar - 'a'; // b will be 2
Similar idea is used to convert a lowercase char to uppercase:
char myChar = 'c';
char newChar = myChar - 'a' + 'A'; // newChar will be 'C'
U are adding the ASCII value of the number's
say '0' ASCII value is 48
'1' -> 49,and so on CHECK HERE FOR COMPLETE TABLE
so when u add one to 48 it will 49 and putchar functuion prints the character sent to it. when u do
putchar('0' + r )
if r = 1 putchar(48 + 1) (converting into ASCII value)
putchar(49) which is 1