0

I have been trying to learn C and decided to do an encryption project. I want to use ROT 13 encryption for the project but I have been getting an error. The code is supposed to check the value of a char at index position words[i] and compare its value. If it's in the range of 97-122 ('a' - 'z'), run the code and add the encryption. I learned, however, that when I want to replace a letter like 'z' and move it 6 positions, it doesn't work. Moving it 5 positions does work. Please see the code below:

#include <stdio.h>
#include <string.h>

int main(){
    char words[25]= "ABC MNO XYZ";

    printf("%s \n", words);
    printf("size of 'words' is %d \n", strlen(words));

    int size_t = strlen(words);

    for (int i=0; i < size_t; i++){
        printf("%c \n", words[i]);
    }

    printf("unencrypted ends here... \n\nStarts the cipher\n");

    //converts array to lowercase for ascii purposes
    for (int i=0; i < size_t; i++){
        words[i]= tolower(words[i]);
    }

    for (int i=0; i < size_t; i++)
    {
        char res = 'z';
        if(words[i]>=97 && words[i]<=122)
        {
            words[i] = words[i]+6;
            while(words[i] > 122)
            {
                res = words[i]-res;
                printf("The value of res is: %d\n", res);
                words[i]=96;
                words[i]= words[i]+res;
            }
        }

        //'res' ascii value equals 122
        //if words[i] is more than 122 (z), subtract 122 from it and store it in res
        //restart words[i] at position before 'a', then add res
        //not sure why but after 122 + 6 or more positions, does not reset to a char before 'a'
        //gives those weird chars at 128+ ascii locations

        printf("%c \n", words[i]);
    }

    return 0;
}
Yun
  • 3,056
  • 6
  • 9
  • 28
lilv
  • 1
  • 1
    you shouldn't really use `size_t` as a variable name, it's the name of a variable type in the standard library – John Doe Sep 02 '21 at 15:54
  • 2
    Subtract `'a'` from the letter. Add 13 (for rot13), and then subtract 26 if the result is >= 26. Then add `'a'` to get the final result. – user3386109 Sep 02 '21 at 16:04

2 Answers2

2

@user3386109 has already commented a solution to your problem:

Subtract 'a' from the letter. Add 13 (for rot13), and then subtract 26 if the result is >= 26. Then add 'a' to get the final result.

But here's an explanation of why adding 5 to words[i] works but 6 doesn't:

The main reason adding 5 to words[i] works but adding 6 doesn't is because in your case char is signed (range -128 to 127) so if words[i] (a char) is equal to 122, adding 6 to it (128) overflows the range of signed char.

Since words[i] will never be negative, try using unsigned char instead of char.

Last but not the least, size_t is a datatype in C, try to avoid using it as a variable name.

0

The problem is that a char may have a range of [-128, 127], which is why adding 5 works, but adding 6 causes an out-of-range assignment. One solution is to first convert the char to a larger type, for example an int, but there is something better:

for (int i=0; i < size_t; i++)
{
    if (islower(words[i]))
        words[i] = (words[i] - 'a' + 13) % 26 + 'a';

    printf("%c \n", words[i]);
}

This takes the character, makes it a value between 0 and 25, applies the shift, takes the remainder to handle the wrapping around the alphabet, and finally adds 'a' again to convert the value back to the ASCII 'a' to 'z' range.
This will still implicitly convert the char to an int type, as 'a' and 13 are ints, but now we no longer need an if-statement and it expresses clearly that we are using values modulo 26.

For more information on the range of char and type promotions, see here. Note that assigning an out-of-range value to a signed integer is actually implementation-defined behavior.

Some additional advice:

  • The typical signature for main, using no parameters, is int main(void).
  • To use tolower, include the ctype.h header.
  • Do not use an identifier called size_t. This is a type used in C and is typedef'd in many commonly used headers.
  • Using 'a' and 'z' makes the code easier to understand than using 97 and 122. For checking if a char is lowercase, use islower.
  • The strlen function returns a value of the type size_t. The correct format specifier for this is not %d, but %zu.
Yun
  • 3,056
  • 6
  • 9
  • 28