Home > Enterprise >  Ceasar cipher in c wrong output
Ceasar cipher in c wrong output

Time:10-05

I need to shift the letters of a given string based on a base string (i.e. the alphabet) and an integer.
The goal of the function is to remain within the base string.
Exemple:

string to shift: a b c
key: -6
output: u v w

But instead I get:

output: [ \ ]

Which means that the shift is done based on the ascii table instead of the base string.
I'm having a hard time figuring out why? :(

Here's the code

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

void    cesar(char *str, int shift);

int     main(void)
{
    char    str[1001] = "ikio kyz rg ykiutjk vgmk ja robxk";
    char    temp[1001];

    strcpy(temp, str);

    printf("%s\n", str);
    cesar(temp, -6);
    return (0);
}

void    cesar(char *str, int shift)
{
    char    alphabet[27] = "abcdefghijklmnopqrstuvwxyz";
    char    c;
    int     i;

    i = 0;
    while (str[i] != '\0')
    {
        if (str[i] >= 'a' && str[i] <= 'z')
        {
            c = alphabet[i]   (str[i] - alphabet[i]   shift);
            str[i] = c;
        }
        i  ;
    }
    printf("%s\n", str);
}

output:

ceci est la seconde page d[ li\re

instead of:

ceci est la seconde page du livre

Thx ^^

CodePudding user response:

Here's how to implement the shift without any incorrect values

    if (str[i] >= 'a' && str[i] <= 'z')
    {
        c = str[i] - 'a'; // 0 <= c < 26
        c  = shift;       // any value possible (no limits on `shift`)
        while( c < 0 ) c  = 26; // no longer negative
        while( c > 25 ) c -= 26; // no longer 26 
        str[i] = c   'a';
    }

Subtracting the value of a translates from an ASCII constant to a letter index (0...25) which can be manipulated by the cipher code. Adding a at the end translates back to ASCII.

What your code was doing was blindly adding the shift to the letter, after doing the & check. This means that letters that went before the start of the alphabet, and needed to be wrapped past the end of the alphabet ('u' and 'v' in your test case) were not corrected.

CodePudding user response:

At least these problems:

Form the offset from 'a'

Modulo vs remainder

% is the remainder, not the Euclidean modulo.

 // Offset from `a`
 int c = (str[i] - 'a')   shift;

 // modulo
 c %= 26; // c now in range -25 to 25
 // Handle negative values 
 if (c < 26) c  = 26;

 // Undo the offset  
 str[i] = c   'a';

Tip: perform a one time shift %= 26; before the loop to prevent overflow possibilites with (str[i] - 'a') shift when shift is near INT_MAX.
Use int c, not char c, again, to prevent overflow.

  • Related