Matt Matt - 19 days ago 6
C Question

Caesar cipher in C, upper and lower case

I have to produce Caesar cipher decoder -- for both lower and upper case, but I am not able to think of an easy solution to do this (or at the moment even working one).

At the moment I have this loop to decipher the code by given shift

i
:

char* s1 = "qrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop";
int s1s = strlen(s1);
int i = 16;
char tmp[s1s+1];
for (int j = 0; j < s1s; ++j) {
char tmp_s = (char) ((int) s1[j]-i);
if(tmp_s<65){
tmp_s+=58;
}
tmp[j]=tmp_s;
}
tmp[s1s]='\0';


Output should be
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
, at the moment it is
abcdefghijklmnopqrstuvwxyzABCDEFGHIJQRSTUVWXYZ[\]^_
.

I have tried some conditions, but can't really figure out the right one.

Answer

Your tests are not complete. Consider the "ASCII space":

\0 ... 'A' ... 'Z' ... 'a' ... 'z' ...

You have here 5 areas:

  1. characters before 'A'.
  2. characters between 'A' and 'Z'.
  3. characters between 'Z' and 'a'.
  4. characters between 'a' and 'z'.
  5. characters after 'z'.

What you need is to handle characters in areas 1 and 3 once shifted (since you're only performing subtractions, area 5 will never be reached).

You should also use characters in your conditions instead of numerical values for readability. Try:

char* s1 = "qrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop";
int s1s = strlen(s1);
int i = 16;
char tmp[s1s+1];
for (int j = 0; j < s1s; ++j) {
    char tmp_s = (char) ((int) s1[j]-i);
    if(tmp_s < 'A'){ /* "area 1" */
        tmp_s += 'z'-'A' + 1; /* shift between 'a' and 'z' */
    }
    else if(tmp_s < 'a' && s1[j] >= 'a'){ /* "area 3" */
        tmp_s += 'Z'-'a' + 1; /* shift between 'A' and 'Z' */
    }
    tmp[j]=tmp_s;
}
tmp[s1s]='\0';

The code may need further adaptations if you allow i to be high enough to "jump" more than one area.