I was making a program for Vigenere cipher. I made the program print the cipher text successfully. But, I can't loop the key. so if my key was 'abc' and my plain text was hello, it should print 'hfnlp' not 'hfn'.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("\aError\n");
return 1;
}
else
{
string a = argv[1]; // converts argv[1]
printf("plaintext: ");
string b = get_string(); // takes the plaintext
printf("ciphertext: ");
for(int c = 0, d = strlen(a); c < d; c++)
{
for(int e = 0, f = strlen(b); e < f; e++)
{
if(islower(a[c]))
{
printf("%c\n", b[e] + ( (a[c] - 97) % 26) ); // works for lowercase letters
return 0;
}
else if(isupper(a[i]))
{
printf("%c\n", b[e] + ( (a[c] - 65) % 26) ); // works for uppercase letter
}
else
{
printf("%c", b[e]); // works for non alphabetical inputs
}
if(true)
break;
}
}
printf("\n");
}
}
Your choice of single-letter variable names is odd; it makes it harder to work with your code. I'm not a fan of long names either, but intermediate length variable names (2-8 characters — except for some stylized single-letter names (
c
,i
,j
,k
,p
,s
) — is typically appropriate).You've got trouble because if your key is 6 characters and your string is 24 alphabetic characters, you'll attempt output 144 alphabetic characters because of the loop structure. You only need a single loop that iterates over the characters in the plain text. You have a separate variable that cycles over the length of the key, resetting back to the start when it runs out. In this code, the key length is in
keylen
(you usedd
) and the offset (index) into the key is inkeyoff
(you usedc
) — but the key is still ina
because that's what you used. Left to my own devices, I'd probably usetext
(or maybeplain
) in place ofb
,textlen
in place off
, and I'd usei
instead ofe
for the loop variable. If I wanted to use short indexes, I might usek
instead ofkeyoff
. I might also edit the string in situ and print the whole string at the end.This code also ensures that the alpha characters in the key are in lower case. It doesn't ensure that the key is all alpha; it arguably should and it would be trivial to do so since the key is scanned anyway. As it stands, it is a case of GIGO — garbage in, garbage out.
The code converts the input letter (
a-z
orA-Z
) into an 'offset into the alphabet' by subtractinga
orA
, converts the key letter into an offset into the alphabet, adds the two offsets modulo 26 (number of letters in the alphabet), and converts the offset back into a letter of the appropriate case.When compiled to the program
vc41
and run, it produces, for example:I generated an 8-letter random key (it was
GZlfmTMk
) and ran the code on a number of 'complete alphabet' strings:(I'll note in passing that on a Mac running macOS Sierra 10.12.6 using GCC 7.1.0, this code links without including the (new) CS50 library — there is a system function
get_string()
that has a different interface to the CS50 version that satisfies the reference but crashes the program. However, it isn't documented byman get_string
, so I'm not sure what the system function of that name actually does; I haven't chased it more actively, or found out how extensive the problem is. That caused me a headache that the old CS50 library didn't. Grumble…)fix like this