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.