I am using this code for Caesar’s cipher encryption program. c = (alpha + k) % 26; //c = cipher text ASCII code, "alpha" alphabet ASCII code, "k" key for cipher text; this equation gives me zero(0) on all the 26 alphabets.
Thank You!
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main (int argc, string argv[]) {
// took key from user and converted it to int
int k = atoi (argv[1]);
// get plaintext from user
string p = GetString ();
int c = 0, alpha = 0;
for (int i = 0, n = strlen(p); i < n; i++)
{
// if it is alphabet else if not alphabet
if (isalpha (p[i]) == true) {
// if it is capital case else lower case
if (isupper(p[i]) == true) {
alpha = p[i] - 65;
// add key to plaintext then take modulas
c = (alpha + k) % 26;
alpha = c + 65;
} else {
alpha = p[i] - 97;
// add key to plaintext then take modulas
c = (alpha + k) % 26;
alpha = c + 97;
}
} else {
alpha = p[i];
}
printf("%c \n", alpha);
}
}
From documentation of isalpha
Each of these routines returns nonzero if c is a particular
representation of an alphabetic character
So when you say if (isalpha (p[i]) == true) you are comparing what ever non-zero value returned by isalpha()(which may not be 1) with 1(true) which may not hold true and that if block will not be executed. The same goes for isupper(). So basically i don't think the equation is giving you zero, its just the if block the equation is in is not being executed.
You may want to do:
if (isalpha(p[i])
{
if (isupper(p[i])
{
//your code
}
...//your code
}
Related
My code seems to be working properly except at the point when it should print the final output. The problem is to input a string and output an encrypted version. The encryption works by adding an int defined as the key and then adding that value to each character of the ascii values of the inputed string. My issue is that when the cypher text is outputted there are only spaces and no letters or even numbers.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[]) {
int key = atoi(argv[1]);
printf("%i\n", key);
if (argc != 2) {
printf("Usage: ./ceasar key\n");
} else {
string text = get_string("Plaintext: ");
for (int i = 0, len = strlen(text); i < len; i++) {
int cipher = text[i];
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
printf("%c", ciphermod);
}
printf("\n");
}
}
You've got a few issues going on here. Please make sure to thoroughly read the assignment before turning to others for assistance.
The assignment requires you to:
Only encode alphabetic characters. Look to the function isalpha() for this.
Encode both uppercase and lowercase characters accurately. Note that, in ASCII, uppercase letters and lowercase letters are separate entities.
Meaning, you must have your code be able to handle both, as they are each handled differently.
Perhaps taking some time to sit and take in the ASCII table may be helpful to you, as it will help you understand what is really happening when you add the key.
Use the correct formula for encoding letters. The i'th ciphered letter ci corresponding to the i'th plaintext letter pi is defined as ci = (pi + k) % 26.
Your code is equivalent to this formula, but it does not account for wrapping, uppercase/lowercase letters, etc. The project specification doesn't just ask you to repeat the formula, it asks you to solve a problem using it. To do so, you must understand it. I explain more, subsequently.
I recommend:
Modifying the text in-place. Currently, you calculate the ciphered text and print it. If you add code for modifying the text where it sits, it'll make ignoring non-alphabetic characters easier.
Modify the formula.
Where 𝚨 is the ASCII character code for the beginning of either the uppercase or lowercase characters, the formula might shake out as follows:
ci = (pi - 𝚨 + k) % 26 + 𝚨
What this modified formula does is first take the ASCII code for Pi and turn it into a number that represents which letter in the alphabet it is, ignoring case. Then, you can add the key(shift the cipher). Using % 26 on this result then makes sure that the result is between 1 and 26—always a letter. Finally, we add back 𝚨 so that the character has a case again.
Here's the modified code with the solution broken down, step by step:
// ...
for (int i = 0, n = strlen(text); i < n; i++) {
if (!isalpha(text[i])) continue;
if (isupper(text[i])) {
// the letter's ASCII code on its own.
int charcode = text[i];
// the letter's index in the alphabet. A = 0, B = 1, etc.
// this is no longer a valid ASCII code.
int alphabet_index = charcode - 'A';
// the letter's index in the alphabet, shifted by the key.
// note, this may shift the letter past the end/beginning of the alphabet.
int shifted_alphabet_index = alphabet_index + key;
// the letter's index in the alphabet, shifted by the key, wrapped around.
// the modulo operator (%) returns the remainder of a division.
// in this instance, the result will always be between 0 and 25,
// meaning it will always be a valid index in the alphabet.
int shifted_index_within_alphabet = shifted_alphabet_index % 26;
// this is the final ASCII code of the letter, after it has been shifted.
// we achieve this by adding back the 'A' offset so that the letter is
// within the range of the correct case of letters.
int final_shifted_charcode = shifted_index_within_alphabet + 'A';
text[i] = final_shifted_charcode;
}
else { // islower
int charcode = text[i];
int alphabet_index = charcode - 'a';
int shifted_alphabet_index = alphabet_index + key;
int shifted_index_within_alphabet = shifted_alphabet_index % 26;
int final_shifted_charcode = shifted_index_within_alphabet + 'a';
text[i] = final_shifted_charcode;
}
}
printf("ciphertext: %s\n", text);
// ...
And here is the solution, simplified down:
// ...
for (int i = 0, n = strlen(text); i < n; i++) {
if (!isalpha(text[i])) // if not alphabetic, skip
continue; //
if (isupper(text[i])) // if uppercase
text[i] = (text[i] - 'A' + key) % 26 + 'A'; //
else // if lowercase
text[i] = (text[i] - 'a' + key) % 26 + 'a'; //
}
printf("ciphertext: %s\n", text);
// ...
Just as a side note, the statement if (!isalpha(text[i])) is acting like something called a guard clause. This is a useful concept to know. Using guard clauses allows you to have simpler, more readable code. Imagine if I had nested all of the code inside the for loop under the if (isalpha(text[i])) condition. It would be harder to read and understand, and difficult to match up the different bracket pairs.
Edit: I would also echo what chqrlie said. Do not use argv[n] until you have verified that argc >= (n + 1)
The formula to compute the ciphered characters is incorrect:
you should only encode letters
you should subtract the code for the first letter 'a' or 'A'
you should add the code for the first letter 'a' or 'A' to the encoded index.
Note also that you should not use argv[1] until you have checked that enough arguments have been passed.
Here is a modified version:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("Usage: ./ceasar key\n");
} else {
int key = atoi(argv[1]);
printf("%i\n", key);
string text = get_string("Plaintext: ");
for (int i = 0, len = strlen(text); i < len; i++) {
int c = text[i];
if (c >= 'a' && c <= 'z') {
int cipher = c - 'a';
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
c = 'a' + ciphermod;
} else
if (c >= 'A' && c <= 'Z') {
int cipher = c - 'A';
int ciphertext = cipher + key;
int ciphermod = ciphertext % 26;
c = 'A' + ciphermod;
}
printf("%c", c);
}
printf("\n");
}
return 0;
}
Program must encrypt plaintext by the key from command-line.
If p is some plaintext and k is a keyword (i.e., an alphabetical string, whereby A (or a) represents 0, B (or b) represents 1, C (or c) represents 2, …, and Z (or z) represents 25), then each letter, ci, in the ciphertext, c, is computed as:
ci = (pi + kj) % 26
Note this cipher’s use of kj as opposed to just k. And if k is shorter than p, then the letters in k must be reused cyclically as many times as it takes to encrypt p.
In other words, if Vigenère himself wanted to say HELLO to someone confidentially, using a keyword of, say, ABC, he would encrypt the H with a key of 0 (i.e., A), the E with a key of 1 (i.e., B), and the first L with a key of 2 (i.e., C), at which point he’d be out of letters in the keyword, and so he’d reuse (part of) it to encrypt the second L with a key of 0 (i.e., A) again, and the O with a key of 1 (i.e., B) again. And so he’d write HELLO as HFNLP, per the below:
In that way:
plaintext H E L L O
+key A B C A B
(shift value) 0 1 2 0 1
= ciphertext H F N L P
For example:
$ ./vigenere bacon
plaintext: Meet me at the park at eleven am
ciphertext: Negh zf av huf pcfx bt gzrwep oz
My case:
key: baz
plaintext: barfoo
expected: caqgon
my result: caqfgv
My code:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
// Functions:
bool check_arguments(int argc);
bool is_key_alpha(string key);
int shift(char c);
int main(int argc, string argv[])
{
if (check_arguments(argc) == false)
{
return 1;
}
// Declaring key string variable:
string key = argv[1];
// Check containing any character that is not an alphabetic character
if (is_key_alpha(key) == false)
{
return 1;
}
// Prompting user for plaintext:
string plaintext = get_string("plaintext: ");
// Ecipher:
printf("ciphertext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
if (islower(plaintext[i]))
{
printf("%c", ((plaintext[i]) - 97 + shift(key[i])) % 26 + 97);
}
else if (isupper(plaintext[i]))
{
printf("%c", ((plaintext[i]) - 65 + shift(key[i])) % 26 + 65);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
return 0;
}
// FUNCTIONS :
// Checking if there's more than one command-line argument
// Checking if the command-line argument exists:
bool check_arguments(int argc)
{
// Checking if there's more than one command-line argument
if (argc > 2)
{
printf("Usage: ./vigenere keyword\n\n");
return false;
}
// Checking if the command-line argument exists:
else if (argc < 2)
{
printf("Usage: ./vigenere keyword\n");
return false;
}
// If okey:
else
{
return true;
}
}
// containing any character that is not an alphabetic character
bool is_key_alpha(string key)
{
for (int i = 0; i < strlen(key); i++)
{
if (isalpha(key[i]) == false)
{
printf("Key contains non-alphabetical chars");
return false;
}
}
return true;
}
// convert character into the correct shift value
int shift(char c)
{ // for ex. char = a == 97 ascii
if (isalpha(c))
{
if (isupper(c))
// The ASCII value of A is 65
{
c = c - 65;
}
else if (islower(c))
// The ASCII value of a is 97
{
c = c - 97;
}
}
else
{
return c;
}
return c;
}
Barry is on the right track. It is UB. On my system, I got: caqflr
If i hits the length of key, then key[i] goes beyond the end of key
Change:
shift(key[i])
Into:
shift(key[i % strlen(key)])
That fixes the bug.
But, the code is more complicated than it needs to be. That may be one reason why the issue was difficult to spot.
Also, the code runs slowly.
Using strlen when looping on a string changes the running time from O(n) to O(n^2). That's because strlen rescans the string on every loop iteration.
So, to fix this, change (e.g.):
for (int i = 0; i < strlen(plaintext); ++i)
Into:
for (int i = 0; plaintext[i] != 0; ++i)
Also, in such loops there is a lot of replicated code using plaintext[i].
Although the optimizer will understand this and produce fast code (i.e. cache the value and not refetch plaintext[i]), it can be simplified if we use an extra variable to contain the current value:
for (int i = 0, chr = plaintext[i]; chr != 0; chr = plaintext[++i])
Now, instead of using plaintext[i] in many places within the loop we can use chr
This is usually easier to read. And, ironically, is close/similar to the code the optimizer will generate.
The length of the key is invariant. So, we can precompute the value and just use it rather than recalculating it on every iteration of the plaintext loop.
Avoid using "magic numbers":
When you want 'A' use it instead of 65
When you want 'a' use it instead of 97
Also, shift can be improved / eliminated:
Because is_key_alpha checks with isalpha, key is guaranteed to be only alpha chars. So, no need for shift to use isalpha
We don't need to keep the original key value, only the modified one. That is, we can replace every value in key with the result of shift
In other words, we only need to do the shift operation for each key once, during initialization. We can have is_key_alpha do this.
Here is the refactored code:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
// Functions:
bool check_arguments(int argc);
bool is_key_alpha(string key);
int shift(char c);
int
main(int argc, string argv[])
{
if (check_arguments(argc) == false) {
return 1;
}
// Declaring key string variable:
string key = argv[1];
// get the length of the key
// (1) cache it so we don't need to call strlen(key) in the loop (it's
// invariant)
// (2) because is_key_alpha transforms the key, calling strlen on key
// will no longer be valid
int klen = strlen(key);
// Check containing any character that is not an alphabetic character
if (is_key_alpha(key) == false)
return 1;
// Prompting user for plaintext:
string plaintext = get_string("plaintext: ");
// Ecipher:
printf("ciphertext: ");
for (int i = 0, chr = plaintext[i]; chr != 0; chr = plaintext[++i]) {
int k = key[i % klen];
if (islower(chr)) {
chr = ((chr - 'a') + k) % 26 + 'a';
}
else if (isupper(chr)) {
chr = ((chr - 'A') + k) % 26 + 'A';
}
printf("%c", chr);
}
printf("\n");
return 0;
}
// FUNCTIONS :
// Checking if there's more than one command-line argument
// Checking if the command-line argument exists:
bool
check_arguments(int argc)
{
// Checking if there's more than one command-line argument
if (argc > 2) {
printf("Usage: ./vigenere keyword\n\n");
return false;
}
// Checking if the command-line argument exists:
else if (argc < 2) {
printf("Usage: ./vigenere keyword\n");
return false;
}
// If okey:
else {
return true;
}
}
// containing any character that is not an alphabetic character
bool
is_key_alpha(string key)
{
// do what shift does and convert the key into offsets
for (int i = 0, chr = key[i]; chr != 0; chr = key[++i]) {
if (isupper(chr)) {
key[i] = chr - 'A';
continue;
}
if (islower(chr)) {
key[i] = chr - 'a';
continue;
}
printf("Key contains non-alphabetical chars");
return false;
}
return true;
}
// convert character into the correct shift value
int
shift(char c)
{ // for ex. char = a == 97 ascii
// The ASCII value of A is 65
// The ASCII value of a is 97
// NOTES:
// (1) is_key_alpha guarantees that the key value is an alpha
// (2) now that is_key_alpha computes the offset, this function is obsolete
if (isupper(c))
c -= 'A';
else if (islower(c))
c -= 'a';
return c;
}
We can tighten this up a bit further. shift is no longer needed. And, we can have is_key_alpha return the key length (-1 is error). Now, that it changes the key, we could rename it to be more descriptive of its function
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
// Functions:
bool check_arguments(int argc);
int key_transform(string key);
int
main(int argc, string argv[])
{
if (check_arguments(argc) == false) {
return 1;
}
// Declaring key string variable:
string key = argv[1];
// check and transform the key
int klen = key_transform(key);
if (klen < 0)
return 1;
// Prompting user for plaintext:
string plaintext = get_string("plaintext: ");
// Ecipher:
printf("ciphertext: ");
for (int i = 0, chr = plaintext[i]; chr != 0; chr = plaintext[++i]) {
int k = key[i % klen];
if (islower(chr)) {
chr = ((chr - 'a') + k) % 26 + 'a';
}
else if (isupper(chr)) {
chr = ((chr - 'A') + k) % 26 + 'A';
}
printf("%c", chr);
}
printf("\n");
return 0;
}
// FUNCTIONS :
// Checking if there's more than one command-line argument
// Checking if the command-line argument exists:
bool
check_arguments(int argc)
{
// Checking if there's more than one command-line argument
if (argc > 2) {
printf("Usage: ./vigenere keyword\n\n");
return false;
}
// Checking if the command-line argument exists:
else if (argc < 2) {
printf("Usage: ./vigenere keyword\n");
return false;
}
// If okey:
else {
return true;
}
}
// check and transform the key
// RETURNS: key length (-1=error)
int
key_transform(string key)
{
// do what shift does and convert the key into offsets
int i = 0;
for (int chr = key[i]; chr != 0; chr = key[++i]) {
if (isupper(chr)) {
key[i] = chr - 'A';
continue;
}
if (islower(chr)) {
key[i] = chr - 'a';
continue;
}
printf("Key contains non-alphabetical chars");
return -1;
}
return i;
}
I have been spending all day trying to figure out what I did wrong with this enciphering function I created.
The function works by taking in a keyword which it then converts to an ASCII values and then takes that value and formats it into something that will work with an alphabetical index eg: A= 0, B= 1, C= 2, etc... It then converts all of the plain text using the same method. After that it shifts over the characters of the plain text and then adds the characters value from the keyword iterating over the keyword in a loop until it is done encrypting the plain text.
It works for all my tests except for one which went like this:
Keyword is BaZ
input:
plaintext: BaRFoo
output:
ciphertext: CaQGoh
but the desired output is
ciphertext: CaQGon
I am using the following encipher function:
void encipher(char* plainText, char*key)
{
printf("ciphertext: ");
char alphabeticalIndex[26] = {'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 currentKeyChar = 0;
for(int i = 0, n = strlen(plainText); i < n; i++)
{
// check if the end of they key has been reached, if so then reset it
if(currentKeyChar >= strlen(key)) currentKeyChar = 0;
if(isalpha(plainText[i]) == false) printf("%c", plainText[i]);
if(isupper(plainText[i]))
{
// find the cipher character as an int then add it as the key to captialCharNum
int capitalCipherCharNum = ((int) key[currentKeyChar] - 65);
int capitalCharNum = (((int) plainText[i] - 65) + capitalCipherCharNum) % 26;
printf("%c", toupper(alphabeticalIndex[capitalCharNum]));
}
if(islower(plainText[i]))
{
// same as it was for capitals but in this case its lowercase
int lowerCipherCharNum = ((int) key[currentKeyChar] - 97);
int lowerCharNum = (((int) plainText[i] - 97) + lowerCipherCharNum) % 26;
printf("%c", tolower(alphabeticalIndex[lowerCharNum]));
}
currentKeyChar++;
}
printf("\n");
}
Your error is here:
int lowerCipherCharNum = ((int) key[currentKeyChar] - 97);
When key[currentKeyChar] is uppercase, lowerCipherCharNum is negative, resulting in your cipher value being wrong. To fix the problem you need:
int lowerCipherCharNum;
if (islower (key[currentKeyChar]))
lowerCipherCharNum = key[currentKeyChar] - 'a';
else
lowerCipherCharNum = key[currentKeyChar] - 'A';
This will correct your expected output.
While there is nothing wrong with using array indexing to work your way down each string, using pointer arithmetic can greatly simplify your code. (you also have unnecessary and repeated calls to strlen that should be removed (or at least minimized by computing the length of key once rather than every time you check it.))
An example of how using pointer arithmetic can simplify your logic (and shortening your variable names because I don't like to type), you could do something similar to the following:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void encipher (const char *plaintext, const char *key)
{
const char *aidx = "abcdefghijklmnopqrstuvwxyz",
*p = plaintext,
*k = key;
printf ("ciphertext: ");
while (*p) {
if (isalpha (*p) == 0) printf ("%c", *p);
if (isupper (*p)) {
/* find the cipher character as an int then add it as the key */
int ccicn = (*k - 'A');
int ccnum = (*p - 'A' + ccicn) % 26;
putchar (toupper (aidx[ccnum]));
}
if (islower (*p)) {
/* same as it was for capitals but in this case its lowercase */
int lcicn = islower (*k) ? *k - 'a' : *k - 'A';
int lcnum = (*p - 'a' + lcicn) % 26;
putchar (aidx[lcnum]);
}
p++;
if (*k) k++;
if (!*k) k = key;
}
putchar ('\n'); /* don't use printf for one-character */
}
int main (int argc, char **argv) {
const char *s = argc > 1 ? argv[1] : "BaRFoo",
*key = argc > 2 ? argv[2] : "BaZ";
encipher (s, key);
return 0;
}
Example Use/Output
$ ./bin/encipher
ciphertext: CaQGon
(note: the comment /* don't use printf for one-character */)
While not an error, the standard coding style for C avoids the use of camelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants. It is a matter of style -- so it is completely up to you, but failing to follow it can lead to the wrong first impression in some circles.
Below is an "edited" version of your encipher function with a few additional thoughts in comments and the code spaced a little wider (which you may appreciate more as your eyes get older)
/* if plainText and key are not modified, pass them as 'const char *' */
void encipher (const char *plainText, const char *key)
{
/* place variables before executed code if you have the option...
* (just increases portability to older compilers (like Win7))
*/
char alphabeticalIndex[26] = "abcdefghijklmnopqrstuvwxyz";
int currentKeyChar = 0;
size_t keylen = strlen (key);
printf ("ciphertext: ");
for (int i = 0, n = strlen (plainText); i < n; i++)
{
// check if the end of they key has been reached, if so then reset it
if (currentKeyChar >= (int)keylen) currentKeyChar = 0;
if (isalpha (plainText[i]) == 0) putchar (plainText[i]);
if (isupper (plainText[i]))
{
// find the cipher character as an int then add it as the key
int capitalCipherCharNum = ((int) key[currentKeyChar] - 65);
int capitalCharNum = (plainText[i] - 65 + capitalCipherCharNum) % 26;
putchar (toupper (alphabeticalIndex[capitalCharNum]));
}
if (islower (plainText[i]))
{
// same as it was for capitals but in this case its lowercase
// int lowerCipherCharNum = ((int) key[currentKeyChar] - 97);
int lowerCipherCharNum;
if (islower (key[currentKeyChar]))
lowerCipherCharNum = key[currentKeyChar] - 'a';
else
lowerCipherCharNum = key[currentKeyChar] - 'A';
int lowerCharNum = (plainText[i] - 97 + lowerCipherCharNum) % 26;
putchar (tolower (alphabeticalIndex[lowerCharNum]));
}
currentKeyChar++;
}
putchar ('\n'); /* don't use printf for one-character */
}
Look things over and let me know if you have further questions.
I'm having trouble writing the last part of my code for an assignment which involves writing a Vigenere cipher. The encryption part is working fine, but I'm having trouble figuring out how to repeat the encryption word/keyword. So it works fine if the message that needs to be encrypted is smaller or equal to the keyword and otherwise it puts out another couple of characters, that seem encrypted, but aren't.
This is the code so far:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("YELL!\n");
return 1;
}
//check if the number of command line arguments is correct, if not, YELL!
string keyword = (argv[1]);
//get keyword
for (int j = 0, n = strlen(keyword); j < n; j++)
{
if(!isalpha(keyword[j]))
{
printf("YELL!\n");
return 1;
}
}
//check if the keyword is only alphabetical, if not, YELL!
string message = GetString();
//get plaintext
for (int j = 0, n = strlen(keyword); j < n; j++)
{
if (isupper(keyword[j]))
{
keyword[j] = (keyword[j] - 'A');
}
if (islower(keyword[j]))
{
keyword[j] = (keyword[j] - 'a');
}
}
//this is to get the numerical values from the ascii values of the keyword.
for (int i = 0, j = 0, n = strlen(message); i < n; i++, j++)
//counting through the message & the cypher
{
if (isalpha(message[i]))
{
if (isupper(message[i]))
{
message[i] = (((message[i] - 'A') + keyword[j]) % 26 + 'A');
}
if (islower(message[i]))
{
message[i] = (((message[i] - 'a') + keyword[j]) % 26 + 'a');
}
//adding a keyword value [j] to message [i] and converting back to ascii value,
//individually for upper and lowercase characters.
}
printf("%c", message[i]);
}
}
It's probably an easy solution, but I just can't figure it out. Any help would be vastly appreciated!
It's a miracle encryption is working for you. I think is is not, as your loop is clearly might get j past the keyword length and then keyword[j] will be out of bounds and exhibit undefined behavior. You need only to iterate on i over the message length and index the keyword with keyword[i % strlen(keyword)], such that the index will go cyclically from 0 to the length of the keyword minus one.
My goal is to make a Vigenere cipher. I am attempting to do this by getting the key from argv, getting the string from the user, then passing the message and key though a function I made which combined them and returns the new value before printing it. For some reason it is just printing the key. I think it has something to do with the new function and how I am trying to use the returned value. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
int new_crypt;
int encrypt(string , int );
int main(int argc, string argv[])
{
if( argc != 2)
{
printf("Plese enter only one key");
return 1;
}
string message = GetString();
for(int i=0; i < strlen(message); i++)
{
int klen = strlen(argv[1]);
//repeats the key until the message is over
int key= argv[1][i%klen];
bool kupper = isupper(key);
bool klower = islower(key);
bool kalpha = isalpha(key);
if(kupper == true){
//ASCII value of A is 65. 'A' = 0 shifts
int k = key-65;
int new_crypt = encrypt(message, k);
printf("%c", new_crypt);
}
if(klower == true){
//ASCII value of 'a' is 97. 'a' = 0 shifts
int k = key- 97;
int new_crypt = encrypt(message, k);
printf("%c", new_crypt);
}
if(kalpha == false){
int k = 0;
int i = i-1;
int new_crypt = encrypt(message, k);
printf("%c", new_crypt);
}
}
printf("\n");
return 0;
}
int encrypt(string message, int k)
{
for(int i=0; i < strlen(message); i++)
{
bool upper = isupper(message[i]);
if(upper == true)
{ //Makes sure the message doesnt go past 'Z'.. If it does it mod 90 it / // and adds 65 ('A')
int crypt = (message[i]+ k) % 90;
if(crypt < 65)
{
int new_crypt = (crypt + 65);
return new_crypt;
}
else{
int new_crypt = crypt;
return new_crypt;
}
}
bool lower = islower(message[i]);
if(lower == true)
{
int crypt = (message[i]+ k) % 123;
if(crypt < 97)
{
int new_crypt = crypt + 97;
return new_crypt;
}
else{
int new_crypt = crypt;
return new_crypt;
}
}
bool alpha = isalpha(message[i]);
if(alpha == false)
{
int new_crypt = message[i];
return new_crypt;
}
}
return 0;
}
The loop in the encrypt function is completely useless, because there is no path through the loop-body without a return statement causing the loop to be terminated and control returned to the caller of encrypt. This makes that the program as a whole repeatedly encrypts the first character of the message with successive elements from the key.
The easiest way around this is to make the following changes
Remove the loop from the encrypt function
Pass, as an additional argument, the element from the message that you want to encrypt, making the signature
int encrypt(string message, int k, int i)
Some miscellaneous remarks:
The global variable new_crypt is not used anywhere. You can safely remove it. (You should avoid the use of global variables as much as reasonably possible).
Instead of using the magic number 65, you can also use the character literal 'A'. This has the advantage that you don't need a comment to explain the number 65 and that it is always the correct value for the capital A, even if you end up not using ASCII. (But see also the next bullet)
Your code assumes the letters A to Z (and a to z) have contiguous values (such that Z == A+26). This may happen to be the case for the English alphabet in the ASCII encoding, but it is not guaranteed for other language alphabets or encodings.