Cipher Function Producing Unwanted Results in the Last Character of Output - c

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.

Related

CS50 Week 2 Caesar Practice

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 don't encrypt the way I want (C language). From CS-50 lesson Vegenere

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;
}

Uppercase characters in a string cannot be converted to lowercase and subtracting their ASCII value doesnt make them in alphabetical index

I am a beginner trying to learn to code.
Currently I am doing the CS50 course. I have encountered a problem with the Vigenere cipher problem; please see my code on a github link below.
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ASCII_VALUE_LOWER 97
#define ASCII_VALUE_UPPER 65
#define NR_OF_LETTERS 26
int main(int argc, string argv[])
{
char key[strlen(argv[1]) + 1];
strcpy(key, argv[1]);
int keyLen = strlen(key);
for (int k = 0; k < keyLen; k++)
{
if (!isalpha(key[k]))
{
printf("ERROR: Secret key has to be alphabetical string, program will be terminated now!\n");
return 1; // main should return 1 (signify an error)
}
//converting key letters to respective values
if (isupper(key[k]))
{
key[k] -= ASCII_VALUE_UPPER;
}
key[k] -= ASCII_VALUE_LOWER;
}
//if program is executed without an argument, or with more than one arguments
if (argc != 2)
{
printf("ERROR: You need to give a secret key as an argument, program will be terminated now!\n");
return 1; // main should return 1 (signify an error)
}
else
{
string plaintext = get_string("plaintext: "); //get a plaintext from a user using cs50 custom function from their library
int stringLen = strlen(plaintext);
int keyIndex = 0;
for (int j = 0; j < keyLen; j++)
{
}
//for each character in the plaintext string
for (int i = 0; i < stringLen; i++)
{
//check if is alphabetic (tolower, toupper)
if (isalpha(plaintext[i]))
{
//cypher_character = (plain_character + key_character)% 26
if (islower(plaintext[i]))
{
keyIndex %= keyLen;
plaintext[i] = ((plaintext[i] - ASCII_VALUE_LOWER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_LOWER;
}
else
{
plaintext[i] = ((plaintext[i] - ASCII_VALUE_UPPER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_UPPER;
}
keyIndex++;
}
//else leave as is
}
//print ciphertext in a format "ciphertext: " + ciper
printf("ciphertext: %s\n", plaintext);
return 0;
}
}
The issues are as following:
if you pass an argument in uppercase letters in a key, the values are weird and the conversion doesn't work. The idea is to take each character in a string key and subtracting 65 if uppercase, or 97 if lowercase, so their ASCII value would go to 0 - 25. I then can make a use of them in a Vigenere cipher formula: cipher[i_index] = (plaintext[i_index] + key[j_index]) % 26
doesn't handle lack of argv[1], even though there is an IF condition (!argc == 2), so it shouldn't go through if you don't pass anything.
"failed to execute program due to segmentation fault".
I have tried everything in my capability, I am pretty tired, maybe tomorrow the solution will popout instantly.
I ask you to give me some hints, possibly not revealing everything, but maybe guiding me, so I can learn from it.
if (isupper(key[k]))
{
key[k] -= ASCII_VALUE_UPPER;
}
key[k] -= ASCII_VALUE_LOWER;
If the character is upper case, this subtracts ASCII_VALUE_UPPER. And then, no matter what, it subtracts ASCII_VALUE_LOWER. From the surrounding code, I assume you meant:
if (isupper(key[k])) {
key[k] -= ASCII_VALUE_UPPER;
} else {
key[k] -= ASCII_VALUE_LOWER;
}
As others suggested, everything was fixed, if someone would be curious where exacly was the mistake:
1.] Mistake pinpointed by #Rob Napier
for (int i = 0; i < stringLen; i++)
{
//check if is alphabetic (tolower, toupper)
if (isalpha(plaintext[i]))
{
keyIndex %= keyLen; // makes sure that keyIndex doesnt exceeds actual string length
//cypher_character = (plain_character + key_character)% 26
if (islower(plaintext[i]))
{
plaintext[i] = ((plaintext[i] - ASCII_VALUE_LOWER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_LOWER;
}
else
{
plaintext[i] = ((plaintext[i] - ASCII_VALUE_UPPER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_UPPER;
}
keyIndex++;
}
//else leave as is
}
keyIndex %= keyLen; was placed inside of the if condition below it, so it didnt execute in every iteration of the FOR loop.
2.] answered by #Joe Farrel:
because by the time I checked whether argc != 2, I have already accessed argv[1], and thereby assumed that argc >= 2. If the caller hasn't supplied an argument, then argv[1] is past the end of the array and evaluating that expression results in undefined behavior. - So I moved the if condition as a first thing in main.

C Loop through a small array and add to a large array [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
my first time here, im a very novice student in programming and I have a problem I cant find any solution for.
I’m writing a code to do vigenere cipher but I have problems with it:
First: Key is to be entered, let’s say that the key is; “aaa”
Second: Text to be encrypted, let’s say that the text is:”alligator”
The cipher should be:
alligator
+
aaa|aaa|aaa (key to rerun each extra letter in the text vs key)
a
+
a
ciphered first letter;
b
all the text:
bmmjhbups
My problem is how to loop through alligator with the shorter abc? In all my attempts the abc becomes zero when looping pass it instead of starting from the beginning when the loop for the text is passed the length of the abc.
I have also tried with strcpy and concatenate so that the abc becomes the same strlength at alligator but i meet problems in the strcpy and cat metodes due to strange symbols in the begging of the string.
Do any have a easy solution regarding how a loop can work through a bigger loop ?
Although I probably shouldn't post this (as no code sample was provided), here's a piece of code that does what you want. However, a couple of ideas:
According to Vigenere wiki, each letter has a number associated with it:
a .. 0
b .. 1
...
z .. 25
and when adding 2 letters their values are added and then the % 26 (modulo) is applied to the result. E.g. 'a' + 'a' = (0 + 0) % 26 = 0 which is also a (which is different than b that you are expecting), that's why I had to add the CUSTOM_OFFSET shifting every result from the table (forward) by 1.
The cipher works either with upper or lower case letters, not with both (or any other characters). Probably some text and key validation routines could be added. Anyway in this case, lowercase are used.
Code:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define BASE_CHR 'a' //Change it to 'A' if working with uppercases (can't have both)
#define ALPHABET_LEN ('z' - 'a' + 1)
#define CUSTOM_OFFSET 1 //According to specs should be 0, but it wouldn't match the current requirements
int main() {
char *text = "alligator", *key = "aaa", *new_text = NULL;
size_t text_len = strlen(text), key_len = strlen(key), i = 0;
if ((new_text = (char*)calloc(text_len + 1, sizeof(char))) == NULL) {
printf("Malloc error\n");
return 1;
}
for (i = 0; i < text_len; i++)
new_text[i] = ((text[i] - BASE_CHR + key[i % key_len] - BASE_CHR + CUSTOM_OFFSET) % ALPHABET_LEN) + BASE_CHR;
printf("Text: %s, Key: %s, Crypted: %s\n", text, key, new_text);
free(new_text);
new_text = NULL;
return 0;
}
Output:
Text: alligator, Key: aaa, Crypted: bmmjhbups
Please have a look at this program. I think it does what you want.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NUMLETTERS 26
#define BUFSIZE 4096
char *get_input(void);
int main(int argc, char *argv[])
{
char sign = 1;
char const plainmsg[] = "Plain text: ";
// Convert argument into array of shifts
char const *const restrict key = "bbb";
size_t const keylen = strlen(key);
char shifts[keylen];
char const *restrict plaintext = NULL;
for (size_t i = 0; i < keylen; i++) {
if (!(isalpha(key[i]))) {
fprintf(stderr, "Invalid key\n");
return 2;
}
char const charcase = (char) (isupper(key[i])) ? 'A' : 'a';
// If decrypting, shifts will be negative.
// This line would turn "bacon" into {1, 0, 2, 14, 13}
shifts[i] = (key[i] - charcase) * sign;
}
do {
fflush(stdout);
// Print "Plain text: " if encrypting and "Cipher text: " if
// decrypting
printf("%s", plainmsg);
plaintext = get_input();
if (plaintext == NULL) {
fprintf(stderr, "Error getting input\n");
return 4;
}
} while (strcmp(plaintext, "") == 0); // Reprompt if entry is empty
size_t const plainlen = strlen(plaintext);
char* const restrict ciphertext = calloc(plainlen + 1, sizeof *ciphertext);
if (ciphertext == NULL) {
fprintf(stderr, "Memory error\n");
return 5;
}
for (size_t i = 0, j = 0; i < plainlen; i++) {
// Skip non-alphabetical characters
if (!(isalpha(plaintext[i]))) {
ciphertext[i] = plaintext[i];
continue;
}
// Check case
char const charcase = (isupper(plaintext[i])) ? 'A' : 'a';
// Wrapping conversion algorithm
ciphertext[i] = ((plaintext[i] + shifts[j] - charcase + NUMLETTERS) % NUMLETTERS) + charcase;
j = (j+1) % keylen;
}
ciphertext[plainlen] = '\0';
printf("%s\n", ciphertext);
free(ciphertext);
// Silence warnings about const not being maintained in cast to void*
free((char*) plaintext);
return 0;
}
char *get_input(void) {
char *const restrict buf = malloc(BUFSIZE * sizeof (char));
if (buf == NULL) {
return NULL;
}
fgets(buf, BUFSIZE, stdin);
// Get rid of newline
size_t const len = strlen(buf);
if (buf[len - 1] == '\n') buf[len - 1] = '\0';
return buf;
}
Test
Plain text: alligator
bmmjhbups
However, I think that you might have misunderstood the key, the key aaa will leave the plain text unchanged, if I understood correctly, but the key bbb will shift the positions one step down in the alphabet. Watch for corner cases such as shifting Z down or shifting A up.

Caesar’s cipher encryption program in C

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
}

Resources