C Question

Vigenere's Cipher in C (CS50)

I have been stuck on this for a while now, I thought I had it working several times only to find more things I forgot. Basically the problem set was to create the Vigenere Cipher using C, the rules can be found here

I basically have it working it will only allow the correct characters and if the keyword is the same length as the message all is good.

The issue I am having is figuring a way to reset the looping of the keyword while the message is being encrypted, so if I enter a keyword 'A' and the message 'This is a test' the encrypted message should read 'This is a test' since 'A' is worth zero shifts along the ASCII table.

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

int main(int argc, char * keyWord[]) {
int cipher[64], i, j, k, l;
char message[128];

// Validation - using alphaCheck Function
if (argc != 2 || alphaCheck(keyWord) == 2) {
return 1;
}

// For loop to convert to upper and set value ie A = 0 B = 1
for (i = 0, j = strlen(keyWord[1]); i < j; i++) {
cipher[i] = (toupper(keyWord[1][i]) - 65);
printf("%i\n", cipher[i]);
}

// Prompt the user for the message to encrypt
printf("Enter your secret message: ");
fgets(message, 128, stdin);


int keyCount = 0;
int p = strlen(keyWord[1]);

if (keyCount < p) {
keyCount++;
} else {
keyCount = 0;
}

for (i = 0, k = strlen(message); i < k; i++) {
if (isspace(message[i])) {
printf(" ");
} else if (isupper(message[i])) {
char c = (message[i] - 65 + cipher[i]) % 26 + 65;
printf("%c", c);
}
else {
char d = (message[i] - 97 + cipher[i]) % 26 + 97;
printf("%c", d);
}
}
}



// Function to check if alphabet characters.
int alphaCheck(char * argv[]) {
int length = strlen(argv[1]), n;
for (n = 0; n < length; n++) {
if (!isalpha(argv[1][n])) {
printf("Characters 'A-Z' for Keyword.\n");
return 2;
}
}
}


The following section is redundant at the moment I left it in to show how I tried to tackle the problem but failed.

int keyCount = 0;
int p = strlen(keyWord[1]);

if (keyCount < p) {
keyCount++;
} else {
keyCount = 0;
}

Answer

First off, you should enable more compiler warnings. For example, with gcc and my favorite set of flags (-pedantic -Wall -Wextra -Wundef -Wendif-labels -Wshadow -Wbad-function-cast -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wdisabled-optimization -O2) I get:

$ cc prog.c
prog.c: In function ‘main’:
prog.c:12:20: warning: implicit declaration of function ‘alphaCheck’ [-Wimplicit-function-declaration]
   if (argc != 2 || alphaCheck(keyWord) == 2) {
                    ^
prog.c:12:3: warning: nested extern declaration of ‘alphaCheck’ [-Wnested-externs]
   if (argc != 2 || alphaCheck(keyWord) == 2) {
   ^
prog.c:8:28: warning: unused variable ‘l’ [-Wunused-variable]
   int cipher[64], i, j, k, l;
                            ^
prog.c: At top level:
prog.c:53:5: warning: no previous prototype for ‘alphaCheck’ [-Wmissing-prototypes]
 int alphaCheck(char * argv[]) {
     ^
prog.c: In function ‘alphaCheck’:
prog.c:61:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

All of these should be fixed:

  • add return 0 at the end of alphaCheck
  • remove l
  • put int alphaCheck(char *[]); before main (or move the whole function before main and make it static)

Your main loop has three cases. It checks for spaces, uppercase characters, and everything else is assumed to be a lowercase character. You should instead check for uppercase, lowercase, and pass everything else through unchanged (such as punctuation like . or ,):

if (isupper(message[i])) {
    ...
} else if (islower(message[i])) {
    ...
} else {
    printf("%c", message[i]);
}

Your idea with keyCount isn't bad but it needs to be integrated with the main loop. That is, you should use cipher[keyCount] in the loop, not cipher[i], and increment keyCount every time you use it like this.

Then, at the end of each iteration, you can do your check if you've run out of key (and reset keyCount):

for ( ... ) {
    ...

    if (keyCount >= p) {
        keyCount = 0;
    }
}
Comments