I’m a novice in C and I’m practicing with some code in order to improve my knoowledge.
With the following code I’m trying to encrypt a given text returning, for every text character, a character that is the result of moving in the alphabet n positions forward.
So, for example, for the given text “hello” and the key 6 (so for every char of ‘hello‘ shifting of 6 positions in the alphabet chars array) the encrypted text will be “nkrru“.
My code use:
- empty char array strResult where to store the resulting encrypted text;
- temporary char array tmp where to store the shifted chars.
I also used two nested loop: in the first one I iterate, char by char, into the given text string and in the inner one I iterate into the alphabet chars in order to find the equivalent character. Then I populate the tmp array with the alphabet chars shifted by key times.
Meanwhile I manage the case if the shifting forward goes over the 26 letters of the alphabet and if one of the char is a white space.
At the end, using strcat() I concatenate tmp to strResult and print it.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char ALPHABET[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
int key = 9;
string word = "Hello World";//text to encrypt
char resultStr[strlen(word)];//string where to store the resulting encrypted text
char tmp[strlen(word)];//temporary string
int counter;//for the shifted index
for (int i = 0, n = strlen(word); i < n; i )
{
char wordcurrChar = tolower(word[i]);//convert every wordcurrChar to lowercase
int checkSpace = isspace(wordcurrChar);//check if the character is a white space
//inner loop to iterate trough alphabet array
for (int j = 0, m = strlen(ALPHABET); j < m; j )
{
counter = j key;//counter has now the value of the shifted index
char ALPHcurrChar = ALPHABET[j];
if ((wordcurrChar == ALPHcurrChar) && (counter <= 26)) {//if counter is whitin the 26 characters of the alphabet
tmp[i] = ALPHABET[counter];//then shift at index counter
} else if ((wordcurrChar == ALPHcurrChar) && (counter > 26)) {//if counter is over the 26 characters of the alphabet
int newCounter = counter - 26;//then, once over Z, start from the beginning of the alphabet
tmp[i] = ALPHABET[newCounter];
} else if (checkSpace != 0) {//if the character is a white space
tmp[i] = ' ';//then return a white space also for the encrypted text
}
}
}
strcat(resultStr, tmp);//concat resultStr and temporary string
printf("%s\n", resultStr);//print the encrypted text
}
Everithing looks to work fine, except from the fact that when the shifting goes over the 26 alphabet chars and has to return as encrypted char the specific letter 'A' it stops.
So, for example, if I give as string to encrypt hello world with key=9, result is qnuux fx_ _ _. The last 3 letters are missing. Basically, the shifting of char r in hello world (that shifted of 9 position in the alphabet array goes over the 26th position and end in in char a position) stops everything.
Again, this happen only if the shifting goes over the 26 letters of the alphabet and end on the specific position of char a (with all other cases works fine). So with hello world and key = 15, the result will be wt_ _ _ _ _ _ _ _ stopping at the shifting of the first l of hello world. This because the shifting goes over the 26 alphabet letters and reach char a position.
I spent hours and hours to understand why is happening but with no success.
Hope someone can help.
Thanks a lot in advance.
P.s: I tried many different changing of the if statment that manage the condition of going over the 26 alphabet array positions but nothing really helped.
CodePudding user response:
Code seems to have missed the idea that with the C library, a string has a '\0'
A string is a contiguous sequence of characters terminated by and including the first null character. C17dr 7.1.1 1
At least these problems:
strlen()
on a non-string
strlen(ALPHABET)
leads to undefined behavior (UB) as strlen()
expects a string and ALPHABET
is not a string as it lacks a terminating null character.
// Bad
char ALPHABET[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
for (int j = 0, m = strlen(ALPHABET); j < m; j )
// Add null character
char ALPHABET[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0'};
// or simply
char ALPHABET[] = "abcde...wxyz";;
strcat()
with a non-string
Similarly, strcat()
below fails as strcat()
expects resultStr
and tmp
to be strings. Neither are strings as they lack a terminating null character.
char resultStr[strlen(word)];
char tmp[strlen(word)];
....
// Bad
strcat(resultStr, tmp);
Alternate code would increase array size by 1 and add the final '\0'
.
Not-productive to repeated walk the word
to find its length.
size_t word_length = strlen(word);
char resultStr[word_length 1u];
char resultStr[0] = '\0';
char tmp[word_length 1u];
....
char tmp[word_length] = '\0';
strcat(resultStr, tmp);
CodePudding user response:
- You can simply initialise a char array with a string.
char ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
- It's better to
#define
magic numbers
#define CIPHER_ROTATIONS 9
- Every cipher should be recoverable, for data consistency. So, ignoring letter-case is loss of info.
char wordcurrChar = tolower(word[i]);
Simplified code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define CIPHER_ROTATIONS 27
// shift can be positive(encoding) or negative(decoding)
void caeser_cipher (const char* input, const int tlen, int shift, char* output)
{
shift %= 26; // more than 26 make cycle[s]
if (shift < 0) shift = 26; // moving x steps backward = moving (26-x) forward
for (int ti=0; ti < tlen; ti) {
if (islower (input[ti]))
output[ti] = 'a' (input[ti] - 'a' shift) % 26;
else if (isupper (input[ti]))
output[ti] = 'A' (input[ti] - 'A' shift) % 26;
else
output[ti] = input[ti];
}
}
int main() {
char text[] = "Caesar cipher, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift";
int tlen = strlen(text);
char cipher[tlen 1]; cipher[tlen] ='\0';
int shift = CIPHER_ROTATIONS; // also called rotations
printf ("Text :\t\t[%s]\n", text);
caeser_cipher (text, tlen, shift, cipher);
printf ("Cipher:\t\t[%s]\n", cipher);
text[0] = '\0';
caeser_cipher(cipher, tlen, -shift, text);
printf ("DecipheredText: [%s]\n", text);
return 0;
}
CodePudding user response:
So thank'you very much, to everyone, for helping. As I wrote, I'm a novice in C and probably I have to go deep in strings behavior.
What was inexplicable for me was the fact that the script stopped with such a specific case and not with all other cases.
I'll take all your suggestions as starting points for delve more in c string matter. Thanks again for helping.