boametaphysica boametaphysica - 3 months ago 11
C Question

Vignere Cipher in C: Space not being ignored

A general explanation of the Vignere Cipher:

The Vignere Cipher is a method of encryption that is similar to the Caesar Cipher. This Cipher takes in a word as an argument and interprets the alphabets of the word as follows- a as 0, b as 1, c as 2 and so on.

So if your input key is 'abc' and you want something like "hi hello" to be encrypted, the output would entail h remaining the same, i shifting by 1 place, h shifting by 2 places, e again remaining the same (as it is being shifted by 0), l shifting by 1 place, the other l by 2 and so on so forth.

The basic idea is that each letter shifts by the corresponding letter in the argument and the spaces and other punctuation marks are ignored. If the argument is shorter than the message (as it is in most cases), the argument simply loops around the message.




My problem:

The only problem which persists is that it just seems to be doing the correct thing for the first word of the sentence. It is not ignoring the spaces.

I have pasted my new code below.

For example, for the program
./vigenere bacon
and message
Meet me at the park at eleven am
, I would expect
Negh zf av huf pcfx bt gzrwep oz
as the output. However, what I get is
Negh ne og tjs qaty bt svfvgb bm
. Or for example, when I run the program
./vignere bc
on
ABCD ABCD
, I would expect
BDDF BDDF
. What I instead get is
BDDF CCEE
(the output when it applies something like
bcbcbcbcb
as opposed to
bcbc bcbc
.

While the first word is changing correctly, it seems to be encrypting the entire sentence whereas it should just encrypt the alphabets-- I have specified this using the isalpha command.

This is why it seems a little puzzling.

CODE:

# include <cs50.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>

int main(int argc, string argv[])

{
string word = argv[1];
int i = 0;
int j = 0;


if (argc != 2 || isalpha(word[j]) == false)
{
printf("Please enter a valid command line argument! \n");
return 1;
}

else if (isalpha(word[j]))
{
printf("Message: ");
string message = GetString();

for (int n = strlen(message); i < n; i++)
{
int plaintext = message[i];
int ciphertext = word[j];
int uppcb = (plaintext - 65 + ciphertext - 65);
int upcipher1 = (uppcb) % 26;
int uplc = (plaintext - 65 + ciphertext - 97);
int upcipher2 = (uplc) % 26;
int lopcb = (plaintext - 97 + ciphertext - 97);
int locipher1 = (lopcb) % 26;
int lolp = (plaintext - 97 + ciphertext - 65);
int locipher2 = (lolp) % 26;

if (isupper(word[j]) && isupper(message[i]))
{
j = (j+1)%strlen(word);
int upcode = (upcipher1 + 65);
printf("%c", upcode);
}

else if (isupper(message[i]) && islower(word[j]))
{
j = (j+1)%strlen(word);
int upcode1 = (upcipher2 + 65);
printf("%c", upcode1);
}

else if (islower(message[i]) && islower(word[j]))
{
j = (j+1)%strlen(word);
int locode = (locipher1 + 97);
printf("%c", locode);
}

else if (islower(message[i]) && isupper(word[j]))
{
j = (j+1)%strlen(word);
int locode1 = (locipher2 +97);
printf("%c", locode1);
}

else
{
printf("%c", message[i]);
}

}
printf("\n");
}


}


NOTE: This is in fact C and not C++ and some of the commands like GetInt() and GetString() are available in the CS50 library I'm using.

Answer

You need another index variable for the variable word such as j since word and message are two different variables which may be of different lengths.

So instead of if (isupper(word[i]) && isupper(message[i])) you would instead have something like if (isupper(word[j]) && isupper(message[i])) in which the index variable j counts up from zero to the strlen(word) - 1 and then start back over at zero.

The reason it works for your special case is because message and word are the same length so there is no need to restart the index of word over at zero again when the end of the string in word is reached.

Comments