How to reuse(loop) key in vigenere cipherkey cs50 pset2 - c

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 used d) and the offset (index) into the key is in keyoff (you used c) — but the key is still in a because that's what you used. Left to my own devices, I'd probably use text (or maybe plain) in place of b, textlen in place of f, and I'd use i instead of e for the loop variable. If I wanted to use short indexes, I might use k instead of keyoff. 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 or A-Z) into an 'offset into the alphabet' by subtracting a or A, 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.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2 || strlen(argv[1]) == 0)
{
fprintf(stderr, "Usage: %s key < text\n", argv[0]);
return 1;
}
string a = argv[1];
int keylen = strlen(a);
for (int i = 0; i < keylen; i++)
a[i] = tolower((unsigned char)a[i]);
printf("key: %s\n", a);
printf("plaintext: ");
string b = get_string();
printf("ciphertext: ");
int keyoff = 0;
// Step through each character of the plain text. Encrypt each
// alpha character with the (lower-case) key letter at a[keyoff],
// incrementing keyoff. Don't increment key offset when processing
// non-alpha data.
for (int e = 0, f = strlen(b); e < f; e++)
{
if (islower(b[e]))
printf("%c", ((b[e] - 'a') + (a[keyoff++] - 'a')) % 26 + 'a');
else if (isupper(b[e]))
printf("%c", ((b[e] - 'A') + (a[keyoff++] - 'a')) % 26 + 'A');
else
printf("%c", b[e]);
if (keyoff >= keylen)
keyoff = 0;
}
printf("\n");
return 0;
}
When compiled to the program vc41 and run, it produces, for example:
$ vc41 abcdef
key: abcdef
plaintext: The quick brown Fox jumped over the lazy Dog.
ciphertext: Tig tyncl dusbn Gqa nzmqgg saes vki qaaa Gsl.
$
I generated an 8-letter random key (it was GZlfmTMk) and ran the code on a number of 'complete alphabet' strings:
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: Pack my box with five dozen liquor jugs.
ciphertext: Vznp yr nyd vtyt yufk czeqg xswtzw vnsc.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: The five boxing wizards jump quickly.
ciphertext: Zgp kuoq luwtss pujgqox vnyz wtthwek.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: How vexingly quick daft zebras jump.
ciphertext: Nnh aqquxmkj vgbou jzqy lxnbgr uzyi.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: Bright vixens jump; dozy fowl quack.
ciphertext: Hqtltm hsddyx vnyz; jnkd rhiv wtlhw.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: The quick brown fox jumps over the lazy dog.
ciphertext: Zgp vgbou hqzbz yah ptxue hhox ssj xtli jnr.
$
(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 by man 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
#include <stdio.h>
#include <ctype.h>
#include <cs50.h>
int main(int argc, string argv[]){
if(argc != 2 || !*argv[1]){
printf("\aError:The number of command arguments is incorrect.\n");
printf("Usage: %s key_string\n", argv[0]);
return 1;
}
//Since it is `return 1;` in the if-statement,
//the else clause is unnecessary (unnecessarily deepening the nest)
string key = argv[1];//It does not convert.
size_t i, key_len;
unsigned char curr_char;
for(i = 0; (curr_char = key[i]) != '\0'; ++i){
if(!isalpha(curr_char)){
printf("\aError:Only the alphabet can be specified as the key.\n");
return 1;
}
key[i] -= islower(curr_char) ? 'a' : 'A';//Convert to Deviation
}
key_len = i;
i = 0;
printf("plaintext : ");
string plain = get_string();
printf("ciphertext: ");
for(size_t j = 0; (curr_char = plain[j]) != '\0'; ++j){//Scan of plain text should be the main loop.
if(isalpha(curr_char)){
char base_char = islower(curr_char) ? 'a' : 'A';//Avoid using magic numbers
putchar(base_char + (curr_char - base_char + key[i]) % 26);//Make the same process one
if(++i == key_len)
i = 0;//reset key index
} else {
putchar(curr_char);//non alphabetical inputs
}
}
printf("\n");
free(plain);
}

Related

Why does this program return a "?" symbol in C

I'm following along with cs50x and in problem set 2. This is the idea I had for solving the Caesar problem. I'm yet to implement the key idea due to the fact that it won't print out the word. I'm new to arrays and have searched a bit about why this is occurring. I think that I'm overcomplicating the code and could just use the string given by the user instead of transferring it to a function but now that I've started the idea I want to know why it isn't working and if there is a way to make it work. When ran, the program should accept a command line of a single number, if it has no command line it should fail, if the number is negative it should fail, if it is not a number it should fail and if it has more than 1 argument it should fail. Thanks
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
string cipher(string word, int key);
int main(int argc, string argv[])
{
// Checks whether the user inputted only 1 argument
if (argc == 2)
{
// Convert argv to an int
int key = atoi(argv[1]);
string plainText = get_string("plaintext: ");
// Use function to return the (soon to be encrypted) string
string cipherText = cipher(plainText, key);
// Print for how long the word is
int n = strlen(plainText);
for (int i = 0; i < n; i++)
{
// Print the char of the array based upon the iteration of the loop which runs for however long the word is
printf("%c", cipherText[i]);
}
printf("\n");
// If input is not a positive integer then it will fail
if (key < 1)
{
printf("Usage: ./caesar key\n");
}
}
else
{
// If user inputted too many or no inputs then it will fail
printf("Usage: ./caesar key\n");
}
return 0;
}
string cipher(string word, int key)
{
// Find the length of the word in order to set the size of the array
// This is so that both strings, the word inputted and the word to return are the same to add to
int n = strlen(word);
string cipherText[n];
// Loop through the input word
for (int i = 0; i < n; i++)
{
// If char[i] is a letter then copy that letter into ciphertext
if (isalpha(word[i]))
{
cipherText[i] =& word[i];
}
else
{
cipherText[i] =& word[i];
}
}
// Return the array which, for example the input word is nobody
// Return array[n, o, b, o, d, y]
return cipherText[0-n];
}
The issue is that you are attempting to copy the address of the "word" character array characters into the associated cipher text array element which will print out unknown characters (noted in the above comments).
// Loop through the input word
for (int i = 0; i < n; i++)
{
// If char[i] is a letter then copy that letter into ciphertext
if (isalpha(word[i]))
{
cipherText[i] = &word[i];
}
else
{
cipherText[i] = &word[i];
}
}
When I ran your program with the code like that, I indeed got a series of question marks.
#Una:~/C_Programs/Console/CypherCS50/bin/Release$ ./CypherCS50 12
plaintext: Hello
?????
I then revised it to perform a copy of character elements from "word" to "cipherText".
// Loop through the input word
for (int i = 0; i < n; i++)
{
// If char[i] is a letter then copy that letter into ciphertext
if (isalpha(word[i]))
{
cipherText[i] = word[i];
}
else
{
cipherText[i] = word[i];
}
}
Then, reran the program.
#Una:~/C_Programs/Console/CypherCS50/bin/Release$ ./CypherCS50 12
plaintext: Hello
Hello
Seeing that the same data came out, my guess is that you still need to work on the actual encryption bits. But, the crux of the issue was referencing the memory of the work array elements.
Give that a try.
This does not fix your OP issue, but addresses another issue and responds to our exchange in comments above. Here is a "skeleton" demonstrating how you might approach incrementally developing code for this task. The 'excessive' printf's serve to prove that things are proceeding as you want as the source code becomes more elaborate..
// Functions defined before use do not need to be prototyped
// do-nothing "skeleton" to be completed
string cipher(string word, int key)
{
printf( "In cipher with key %d and str '%s'\n", key, word ); // temp code confirmation
return word; // for now...
}
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return -1; // early termination
}
printf( "argv[1] = %s\n", argv[1] ); // prove functionality
int key = atoi(argv[1]);
printf( "key = %d\n", key ); // prove functionality
if (key <= 0)
{
printf("Key must be positive integer");
return -1; // early termination
}
string plainText = get_string("plaintext: ");
printf( "plain = %s\n", plainText ); // prove functionality
string cipherText = cipher(plainText, key);
printf( "cipher = %s\n", cipherText ); // prove functionality
return 0; // All done!
}

Check whether a list of words make a Pangram

I need to create a 2D string array and input to hi, up to 10 words, than to check if those words are pangram or not.
The program needs to stop receiving words if the words are pangram.
for example:
the
five
boxing
wizards
jump
quickly
It's a pangram?
Yes
but instead of stopping it's just keeps asking for words until it gets to 10. Also says that non-pangram sentences are pangram.
#include<stdio.h>
#include <string.h>
#define ROWS 10
#define COL 50
#define NUM_OF_LETTERS 26
int main()
{
char words[ROWS][COL] = {0};
char used []['z' - 'a' + 1] = {0};
int i = 0;
int j=0;
int count = 0;
printf("Enter up to 10 words try to make a pangram\n");
while(i<ROW&& count < NUM_OF_LETTERS)
{
fgets(words[i], ROW, stdin);
words[i][strcspn(words[i], "\n")] = 0;
int len = strlen(words[i]);
for(j=0;j<COL;j++)
{
if(strcmp(words[j] ,used[j]) == 0)
{
count++;
}
}
i++;
}
printf("It's a pangram?\n");
if (count >= NUM_OF_LETTERS)
{
printf("Yes!\n");
}
else
{
printf("No\n");
}
return 0;
}
And I can't use pointers.
Pangram :
A pangram or holoalphabetic sentence is a sentence using every letter of a given alphabet at least once. Pangram - wiki
2. Count only unique appearance of letters in the input words. Words can have both upper & lower case letters.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_INPUT_WORDS 10
#define MAX_WORD_SIZE 50
#define UNIQUE_LETTERS 26
int main()
{
char* uniq_chars = "abcdefghijklmnopqrstuvwxyz";
//create a look-up table for characters in an alphabet set
char alpha_lt[256] = {0};
for (int ai = 0; '\0' != uniq_chars[ai]; ++ai)
alpha_lt[ (unsigned) uniq_chars[ai]] = 1;
char words [MAX_INPUT_WORDS][MAX_WORD_SIZE];
printf ("\nEnter up to 10 words, try to make a Pangram:\n");
int uniq_count = 0; // tracks count of unique characters so far
int wcount = 0;
for (int wi = 0 ; wi < MAX_INPUT_WORDS; ++wi) {
while (1 != scanf ("%49s", words[wi]));
++wcount;
//count the unique characters from alphabet-set
for (int ci = 0; '\0' != words[wi][ci]; ++ci) {
//Pangram can have letter from different cases.
int ichar = tolower (words[wi][ci]); // to homogenise upper/lower cases
if (alpha_lt[ichar]) { // uniq character not yet counted
++uniq_count;
alpha_lt[ichar] = 0; // remove from LT; to skip
// counting during next occurance
}
}
if (UNIQUE_LETTERS == uniq_count)
break;
}
printf ("\nIs it a Pangram?\n");
printf ((UNIQUE_LETTERS == uniq_count) ? "Yes!\n" : "No\n");
for (int wi = 0; wi < wcount;)
printf ("%s ", words[wi++]);
printf ("\n");
return 0;
}
Sample Pangrams for standard English:
"Waltz, bad nymph, for quick jigs vex." (28 letters)
"Glib jocks quiz nymph to vex dwarf." (28 letters)
"Sphinx of black quartz, judge my vow." (29 letters)
"How vexingly quick daft zebras jump!" (30 letters)
"The five boxing wizards jump quickly." (31 letters)
"Jackdaws love my big sphinx of quartz." (31 letters)
"Pack my box with five dozen liquor jugs." (32 letters)
"The quick brown fox jumps over a lazy dog" (33 letters)
Invalid Pangrams for testing:
ABCD EFGH IJK LMN OPQR STUVWXY Z
abcdef g h i jklmnopqrstuvwxyz

CS50 Caesar - Converting from ASCII number to character

Going through the CS50 exercise Caesar, and I'm still very new to C. My code to validate the key is all working, but as i try to convert from plaintext to the cipher text I keep getting caught up with the conversion form the ASCII number to the char. For example if I run the plaintext with the argv[1] as 27 I get /023/024. I recognize the math is off and if anyone has any pointers about that that would be great, but the main thing I'm curious about is why when I try to assign f into input[i] I get this "/000" type format.
string input = get_string("plaintext: ");
int len = strlen(input);
int i = 0;
while (input[i] != '\0')
{
int mod = atoi(argv[1]);
int t = input[i] + mod;
int f = t % 26;
input[i] = f;
i++;
}
printf("ciphertext: %s\n", input);
Your implementation of doing the %26 is wrong because when you do t % 26 you will get a letter but you have forgotten to add the ASCII value if it is a small of a larger one.
you must change your code to
Here is my code which I had used,
It is correct and hope it helps you...
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2) //checking if there are 2 arguments while calling the main method the first one here will be "./caesar" and the second will be the input given
{
printf("Wrong command\n");
return 1;
}
int k = atoi(argv[1]);//converting string input to integer
string a = argv[1];
for (int i = 0; i < strlen(a); i++)//checking if the input is a number for each character
{
if (a[i] < '0' || a[i] > '9')
{
printf("False\n");
return 1;
}
}
if (k < 0)
{
printf("Wrong command\n");
return 1;
}
else
{
//if everything is successful we ask for the plaintext
string code = get_string("plaintext: ");
//we just print 'ciphertext' and not the 'ciphered text'
printf("ciphertext: ");
for (int i = 0, n = strlen(code); i < n; i++)
{
if (islower(code[i]))
{
printf("%c", (((code[i] + k) - 97) % 26) + 97);
}
else if (isupper(code[i]))
{
printf("%c", (((code[i] + k) - 65) % 26) + 65);
}
else
{
printf("%c", code[i]);
}
}
printf("\n");
return 0;
}
}
Your mistake is that, you are not checking if it is an upper case or lower case and you are not subtracting 97 or 65 before doing the modulus...
If any other doubts, you are free to ask.
Here is the result after running check50 for the 2021 version
:) caesar.c exists.
:) caesar.c compiles.
:) encrypts "a" as "b" using 1 as key
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
:) encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
:) handles lack of argv[1]
All successful

PSET 2: Vigenere Cipher partially working?

I have created the following code as an answer to CS50x PSET2: Vigenere and it works to some extent however when running through check50 I get some errors listed below:
:) vigenere.c exists.
:) vigenere.c compiles.
:) encrypts "a" as "a" using "a" as keyword
:( encrypts "barfoo" as "caqgon" using "baz" as keyword - output not valid ASCII text
:( encrypts "BaRFoo" as "CaQGon" using "BaZ" as keyword - output not valid ASCII text
:) encrypts "BARFOO" as "CAQGON" using "BAZ" as keyword
:( encrypts "world!$?" as "xoqmd!$?" using "baz" as keyword- output not valid ASCII text
:( encrypts "hello, world!" as "iekmo, vprke!" using "baz" as keyword- output not valid ASCII text
:) handles lack of argv[1]
:) handles argc > 2
:( rejects "Hax0r2" as keyword - timed out while waiting for program to exit
What seems to be happening is where the key contains a high value (i.e z/Z) it causes the code to skip to the next line and miss out what appears to be random sequences. eg. in the first word of the string it missed out the 3rd character, then the second word it misses the 3rd and 4th and then the third word the 1st. I just can't understand what is happening.
I have used printf to ensure that all the variables being set and passed into functions are correct at runtime. The functions themselves are returning the correct responses (except validation of Hax0r2). I have tried debugging by comparing results to an online vigenere cipher tool.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int Validate1(int argc);
int Validate2(string argv);
void Cypher(string x);
void KeyCalc(string argv);
string MESSAGE;
int LENGTH;
int *KEY;
int COUNTER = 0;
int main(int argc, string argv[])
{
//Check if right amount of arguments are supplied
int Val1 = Validate1(argc);
if (Val1 == 0)
{
//Check if argument is a string of chars
int Val2 = Validate2(argv[1]);
if (Val2 == 0)
{
//get the string length
LENGTH = strlen(argv[1]);
//Dynamically update KEY array length
KEY = (int *)malloc(LENGTH * sizeof(*KEY));
if (KEY == NULL)
{
fprintf(stderr, "malloc failed\n");
}
//calculate the key
KeyCalc(argv[1]);
//get the message from the user to be encrypted
MESSAGE = get_string("plaintext: ");
printf("ciphertext: ");
//encrypt message from user
Cypher(argv[1]);
free(KEY);
return 0;
}
else
{
//validation failed
printf("Usage: ./vigenere keyword\n");
return 1;
}
}
else
{
//validation failed
printf("Usage: ./vigenere keyword\n");
return 1;
}
}
//Validate the number of arguments supplied
int Validate1(int argc)
{
if (argc != 2)
{
return 1;
}
else
{
return 0;
}
}
//Validate the argument is a string
int Validate2(string argv)
{
int k = 0;
//loop through all characters in argument line string and check if alphabetic
for (int i = 0; i < LENGTH; i++)
{
if isalpha(argv[i])
{
//Do Nothing
}
else
{
k++;
}
}
//k counts the number of non-alphabetic characters, so if > 0 then invalid input
if (k > 0)
{
return 1;
}
else
{
return 0;
}
}
void Cypher(string x)
{
//identify the length of the message to be coded
int Mlength = strlen(MESSAGE);
//identify the length of the key
int Slen = strlen(x);
//cycle through all characters in message supplied by user
for (int i = 0; i < Mlength; i++)
{
// loop through key
if (COUNTER > Slen - 1)
{
COUNTER = 0;
}
//check if the character is alphabetic
if (isalpha(MESSAGE[i]))
{
//convert the character to ASCII int value
char l = MESSAGE[i];
//add key value to message value and wrap around ascii mapping
if (isupper(MESSAGE[i]))
{
l = l + KEY[COUNTER];
if (l > 'Z')
{
l = l - 26;
}
}
else
{
l = l + KEY[COUNTER];
if (l > 'z')
{
l = l - 26;
}
}
//convert value back into character and store in array
MESSAGE[i] = (char) l;
// print character
printf("%c", MESSAGE[i]);
COUNTER++;
}
else
{
//character is 'numeric' or 'symbol' or 'space' just display it
printf("%c", MESSAGE[i]);
}
}
printf("\n");
}
void KeyCalc(string argv)
{
//convert key entry to values A/a = 0 to Z/z = 26
for (int i = 0; i < LENGTH; i++)
{
char k = argv[i];
if (islower(argv[i]))
{
KEY[i] = k - 'a';
}
else
{
KEY[i] = k - 'A';
}
}
}
encrypts "barfoo" as "caqgon" using "baz" as keyword
encrypts "BaRFoo" as "CaQGon" using "BaZ" as keyword
encrypts "world!$?" as "xoqmd!$?" using "baz" as keyword
encrypts "hello, world!" as "iekmo, vprke!" using "baz" as keyword
rejects "Hax0r2" as keyword
From the spec for the caesar pset:
...Caesar’s algorithm (i.e., cipher) encrypts messages by
“rotating” each letter by k positions. More formally, if p is some
plaintext (i.e., an unencrypted message), pi is the ith character in
p, and k is a secret key (i.e., a non-negative integer), then each
letter, ci, in the ciphertext, c, is computed as
ci = (pi + k) % 26
This algorithm (in either "case") does not do that:
l = l + KEY[COUNTER];
if (l > 'Z')
{
l = l - 26;
}
This walkthrough starting at 9:30 is a good primer on how to implement the "shift".
The proximate cause of the problem in this code is that this l = l + KEY[COUNTER]; can yield a result outside the ascii range. In the CS50 implementation, char defaults to a signed char. So, for example, 'r' + 'z' (as in "barfoo" ciphered with "baz") will yield -117.

Shift problem of cipher with Vigenere in C

I am extremely new to programming and I'm having some difficulties with Vigenere in C from the edX course CS50. I have broken the problem down into uppercase letters and lowercase letters and I am only trying to solve the uppercase letter problem right now. I am using the word 'panda' as my key and 'ILIKEYOU' as the plaintext. When I run the program, the first letter corresponds to the letter I'd expect it to be (23=X). After that, the program just seems to spit out random numbers for the remaining 7 letters. I haven't converted back to ASCII since I'm having so many problems with my code. Any ideas what is going on? Thank you all so much for the help :)
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
// Print error message if the user imput is executed without any
command-line arguments or with more than one command-line argument
if (argc != 2)
{
printf("Usage: ./vigenere k\n");
return 1;
}
// Access key
string key = argv[1];
// Convert the array from a string to an int
int letter;
letter = atoi(argv[1]);
// Print error message if the user imput is one command-line argument
and contains *any* non-alphabetical character(s)
for (int c = 0; c < strlen(key); c++)
{
if (!isalpha (key[c]))
{
printf("Usage: ./vigenere k\n");
return 1;
}
}
// Prompt the user for a string of plaintext
string p;
p = get_string("plaintext:");
//Print ciphertext
printf("ciphertext: ");
// Accessing each character in the plaintext
for (int i = 0, n = strlen(p); i < n; i++)
{
// Shift letters only in the plaintext
if (isalpha(p[i]))
{
// Convert plaintext and key to ASCII capital letters to
alphabetical index
// Encipher capital letters in plaintext and print
int c = 0;
if (isupper(p[i]))
{
printf("%i\n", ((p[i] - 65) + (toupper(key[c]) - 65)) % 26);
}
}
}
Needs few modifications -
int index_key = 0;
int shift= 0;
int key_len = strlen(key);
for (int i = 0, n = strlen(p); i < n; i++)
{
// Shift letters only in the plaintext
if (isalpha(p[i]))
{
// Convert plaintext and key to ASCII capital letters to
//alphabetical index
// Encipher capital letters in plaintext and print
if (isupper(p[i]))
{
shift = ((p[i] - 'A') + (toupper(key[index_key % key_len]) - 'A')) % 26;
index_key++;
printf("%c", p[i] + shift);
}
}
}

Resources