I'm a little confused with this problem, because I got it to work and submitted and got full credit, but the code only words when I print the initial variables before the loop. This code works:
int main(int argc, string argv[]) {
// c = (p + k) % 26, where c is result text, p is input and k
// is key
//considers if arg count is two
if (argc == 2) {
int n = strlen(argv[1]);
int check = 0;
if (isdigit(argv[1][0])) {
for (int i = 1; i < n; i++) {
if (isdigit(argv[1][i]) || argv[1][i] == '0') {
check++;
} else {
check--;
}
}
}
// verifies all characters are numeric
if (check != n - 1) {
printf("Usage: ./caesar key\n");
return 1;
}
} else {
printf("Usage: ./caesar key\n");
// returning 1 identifies an error and exits the program
return 1;
}
int key = atoi(argv[1]);
string plaintext = get_string("plaintext: ");
printf("%i\n", key);
printf("%s\n", plaintext);
int m = strlen(plaintext);
printf("%i\n", m);
char ciphertext[m];
int usekey = (key % 26);
printf("%i\n", key);
// NEED to figure out how to handle wrap around
// need to understand ASCII
for (int i = 0; i < m; i++) {
int c = plaintext[i];
//encrypts upper case letters
if (c >= 65 && c <= 90) {
//incorporates wrap around for uppercase
if (c + usekey >= 90) {
int val = 90 - c;
int key2 = usekey - val;
char cipher = 64 + key2;
ciphertext[i] = cipher;
}
//considers if key works fine
else {
char cipher = c + usekey;
ciphertext[i] = cipher;
}
}
//encrypts lower case letters
else if (c >= 97 && c <= 122) {
//incorporates wrap around for lowercase
if (c + usekey >= 122) {
int val = 122 - c;
int key2 = usekey - val;
char cipher = 96 + key2;
ciphertext[i] = cipher;
} else {
char cipher = c + usekey;
ciphertext[i] = cipher;
}
} else {
//encrypts punctuation
ciphertext[i] = c;
}
printf("*\n");
}
printf("ciphertext: %s\n", ciphertext);
}
However, this code, does not work (for encrypts a as b using 1 as key, and for world, say hello! as iadxp, emk tqxxa! using 12 as key). It randomly prints different characters after the correct answer, and I cannot figure out why.
int main(int argc, string argv[]) {
// c = (p + k) % 26, where c is result text, p is input and k
// is key
//considers if arg count is two
if (argc == 2) {
int n = strlen(argv[1]);
int check = 0;
if (isdigit(argv[1][0])) {
for (int i = 1; i < n; i++) {
if (isdigit(argv[1][i]) || argv[1][i] == '0') {
check++;
} else {
check--;
}
}
}
// verifies all characters are numeric
if (check != n - 1) {
printf("Usage: ./caesar key\n");
return 1;
}
} else {
printf("Usage: ./caesar key\n");
// returning 1 identifies an error and exits the program
return 1;
}
int key = atoi(argv[1]);
string plaintext = get_string("plaintext: ");
int m = strlen(plaintext);
char ciphertext[m];
int usekey = (key % 26);
// NEED to figure out how to handle wrap around
// need to understand ASCII
for (int i = 0; i < m; i++) {
int c = plaintext[i];
//encrypts upper case letters
if (c >= 65 && c <= 90) {
//incorporates wrap around for uppercase
if (c + usekey >= 90) {
int val = 90 - c;
int key2 = usekey - val;
char cipher = 64 + key2;
ciphertext[i] = cipher;
}
//considers if key works fine
else {
char cipher = c + usekey;
ciphertext[i] = cipher;
}
}
//encrypts lower case letters
else if (c >= 97 && c <= 122) {
//incorporates wrap around for lowercase
if (c + usekey >= 122) {
int val = 122 - c;
int key2 = usekey - val;
char cipher = 96 + key2;
ciphertext[i] = cipher;
} else {
char cipher = c + usekey;
ciphertext[i] = cipher;
}
}
//encrypts punctuation
else {
ciphertext[i] = c;
}
}
printf("ciphertext: %s\n", ciphertext);
}
I think your if conditions is not works as it should be. you can print 'argv[1][i]' and see the problem. here is my code may help you.
bool isNumber(char number[])
{
int i = 0;
for (; number[i] != 0; i++)
{
if (!isdigit(number[i])) //check if there is something that is not digit
{
return false;
}
}
return true;
}
int main(int argc, string argv[])
{
if (argc == 2 && isNumber(argv[1]) == 1)
{
int k = atoi(argv[1]);
string plainText, chipherText;
plainText = get_string("plaintext: ");
printf("ciphertext: ");
for (int i = 0, n = strlen(plainText) ; i < n; i++)
{
// checking if it is lowercase 97 = a to 112 = z and if it + 13 characters along.
if (plainText[i] >= 'a' && plainText[i] <= 'z')
{
printf("%c", (((plainText[i] - 'a') + k) % 26) + 'a'); // print out lowercase with key
} // if it it between uppercase A and Z
else if (plainText[i] >= 'A' && plainText[i] <= 'Z')
{
printf("%c", (((plainText[i] - 'A') + k) % 26) + 'A'); // print out uppercase with key
}
else
{
printf("%c", plainText[i]);
}
}
printf("\n");
return 0;
}
else if (argc != 2 || isNumber(argv[1]) == 0)
{
printf("Error\n");
return 1;
}
}
You allocate m bytes for cyphertext, which is not enough for the null terminator, which you do not set either, causing random characters to appear after the encrypted output. This is actually undefined behavior, so anything can happen including a program crash.
You do not need to store the encrypted text, just output it one byte at a time.
Also do not use ASCII values such as 65 and 90, use character constants 'A' and 'Z' that are much more readable.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("Usage: ./caesar key\n");
// returning 1 identifies an error and exits the program
return 1;
}
char *p;
int key = strtol(argv[1], &p, 10);
if (*p || p == argv[1]) {
printf("caesar: invalid argument: %s\n", argv[1]);
return 1;
}
string plaintext = get_string("plaintext: ");
// assuming ASCII
for (size_t i = 0; plaintext[i]; i++) {
int c = plaintext[i];
if (c >= 'A' && c <= 'Z') {
c = 'A' + (c - 'A' + key) % 26;
} else
if (c >= 'a' && c <= 'z') {
c = 'a' + (c - 'a' + key) % 26;
}
putchar(c);
}
putchar('\n');
free(plaintext);
return 0;
}
Related
I'm trying to figure out why my code is not iterating correctly on z. I would like to iterate every 1 z, but it seems like it's a bit random. Does anyone have any suggestions on how I might do this? If there anything else I'm doing wrong, please let me know. I think I'm really close. I'm also curious how I block spaces/other characters from being encrypted.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int shift(char c);
int main(int argc, string argv[])
{
// Check to see if two arguments are enterted at launch
int cipher = 0;
if (argc != 2)
{
// If not return error & return 0
printf("Usage: ./vigenere keyword \n");
return 1;
}
else
{
int strlength = strlen(argv[1]);
// Iterates through characters in second argument (key), checking to see
if they are digits
for (int k = 0; k < strlength; k++)
{
if (isdigit(argv[1][k]))
{
// If not return error & return 1
printf("Usage: ./vigenere keyword\n");
return 2;
}
}
//char *c =argv[1];
string plaintext = get_string("Plaintext: ");
int len = (int) strlen(plaintext);
//int b = atoi(c);
//char code[len];
//strcpy (code, plaintext);
int z=0;
for (int j = 0; j < len; j++)
{
int key = shift(argv[1][z]);
//printf("%i",z);
if (isupper(argv[1][z]))
{
//printf("theory\n");
cipher = ((((plaintext[j] - 'A') + key) + 'A'));
//cipher = ((((plaintext[j] - 'A') + key) % 26) + 'A');
//printf("%c", (((plaintext[j] - 'A') + key) % 26) + 'A');
//printf("%i",z);
printf("%c",cipher);
}
if (islower(argv[1][z]))
{
//printf("theory\n");
cipher = (((plaintext[j] - 'a') + key) + 'a');
//printf("%i",z);
printf("%c",cipher);
}
//z++;
//else if (!isalpha(plaintext[j]))
//{
//printf("%c", plaintext[j]);
//}
if (z > strlen(argv[1])-1)
{
z=0;
}
/* else
{
z++;
}
else
{
z++;
}
*/
//z++;
}
printf("\n");
}
}
int shift(char c)
{
int i = c;
if (i <= 'Z' && i >= 'A')
{
return ((i - 'A') % 26);
}
else
{
return ((i - 'a') % 26);
}
}
I am trying to implement Vigenere's Cipher in C but the problem is that when I try to repeat the key used in the array it is in, it breaks after the 4th letter. So if the key is ABC and the plaintext is HELLO, it returns HFNLO instead of HFNLP. When I look at my code it logically makes sense but it seems to just not work. Can anybody see the problem?
Here is the code:
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("usage: ./vigenere k\n");
return 1;
}
//asks for plain text
printf("plaintext: ");
string text = get_string();
string k = argv[1];
printf("ciphertext: ");
//checks to see if length of key is shorter than length of plaintext and duplicates it.
int count = 0;
while(strlen(k) <= strlen(text))
{
k[strlen(k + count)] = k[count];
count++;
}
//changes key to be within 0 - 25 and encrypts plaintext
for(int i = 0; i < strlen(text); i++)
{
if(k[i] >= 'A' && k[i] <= 'Z')
{
k[i] = k[i] - 65;
}
else if (k[i] >= 'a' && k[i] <= 'z')
{
k[i] = k[i] - 97;
}
//if statement for plaintext capital letters
if(text[i] >= 'A' && text[i] <= 'Z')
{
text[i] = text[i] - 64;
text[i] = ((text[i] + k[i]) % 26) + 64;
}
//if statement for plaintext lowercase letters
else if(text[i] >= 'a' && text[i] <= 'z')
{
text[i] = text[i] - 96;
text[i] = ((text[i] + k[i]) % 26) + 96;
}
//prints final cipher
printf("%c", text[i]);
}
printf("\n");
return 0;
}
You should use the modulo operator to compute the offset into the key.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <cs50.h>
int main(int argc, string argv[]) {
if (argc != 2) {
printf("usage: ./vigenere k\n");
return 1;
}
string k = argv[1];
size_t klen = strlen(k);
if (klen == 0) {
fprintf(stderr, "vigenere: key must not be empty\n");
return 1;
}
printf("plaintext: ");
string text = get_string();
printf("ciphertext: ");
for (size_t i = 0; text[i] != '\0'; i++) {
int d = (unsigned char)k[i % klen];
if (d >= 'A' && d <= 'Z') {
d -= 'A';
} else
if (d >= 'a' && d <= 'z') {
d -= 'a';
} else {
d = 0;
}
int c = (unsigned char)text[i];
if (c >= 'A' && c <= 'Z') {
c = 'A' + (c - 'A' + d) % 26;
} else
if (c >= 'a' && c <= 'z') {
c = 'a' + (c - 'a' + d) % 26;
}
putchar(c);
}
putchar('\n');
return 0;
}
I would expect that the values in the array would repeat in every 3rd character but I do not understand why to out put are different if they are referencing the same index.
Input:
Command line argument: baz
User input: barfoo
Output: caqmut
Expected output: caqgon
Values of key_number[] after first for loop:
key_number[0] = 1
key_number[1] = 0
key_number[2] = 25
key_number[3] = 32767
key_number[4] = 32
key_number[5] = 57
Code used:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if(argc<=1)
{
printf("Usage: ./vigenere k");
exit(1);
}
// convert command line input from string to int varible keyword
string keyword = argv[1];
//prompt user input and initialized
printf("plaintext: ");
string plaintext = get_string();
printf("ciphertext: ");
//create lower_case_array
char lower_case[26] = "abcdefghijklmnopqrstuvwxyz";
//create upper_case_array
char upper_case[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//convert key from string to int[]
//int array_length =strlen(plaintext);
int key_number[6]; // [array_length]
int key_length = strlen(keyword);
//loop though key_number for the length of plaintext
for (int i = 0; i < (strlen(plaintext)); i++)
{
//if char is uppercase
if (keyword[i] >= 65 && keyword[i] < 91 )
{
key_number[i] = (keyword[i % key_length]) - 65;
}
// if char is lowercase
else if (keyword[i] >= 97 && keyword[i] < 123)
{
key_number[i] = (keyword[i % key_length]) - 97;
}
}
//print out letters accoring to ceasar cryptography
for (int i = 0; i < strlen(plaintext); i++)
{
//branch if letter is upper case
if (plaintext[i] >= 65 && plaintext[i] < 91 )
{
printf("%c", upper_case[((plaintext[i] - 65 + key_number[i]) % 26)]);
}
//branch if letter is lower case
else if (plaintext[i] >= 97 && plaintext[i] < 123)
{
printf("%c", lower_case[((plaintext[i] - 97 + key_number[i]) % 26)]);
}
//branch if any other character
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
what puzzled me when I read your code is that you're using keyword[i % key_length] sometimes and sometimes keyword[i].
So when you're using i, you can go past the keyword table: undefined behaviour because plaintext is probably longer than keyword
You could have avoided that by rewriting your code more cleanly:
for (int i = 0; i < (strlen(plaintext)); i++)
{
char kc = keyword[i % key_length];
//if char is uppercase
if (kc >= 'A' && kc <= 'Z' ) // aka isupper(kc)
{
key_number[i] = kc - 'A';
}
// if char is lowercase
else if (kc >= 'a' && kc <= 'z') // aka islower(kc)
{
key_number[i] = kc - 'a';
}
}
I am stuck in this example. Whenever I put the keyword 'bacon' I get the wrong answer.
Any idea why this is happening? I can't find the bug and I have tried a lot.
Can you please help me?
When I run this: ./vigenere bacon and input the text Meet me at the park at eleven am the answer should be Negh zf av huf pcfx bt gzrwep oz, but instead I get Negh ne og tjs qaty bt syfvgb bm
Update: I made some changes as suggested by the comments but still having the same problem.
#include<cs50.h>
#include<ctype.h>
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
//check if it has only two values
if (argc != 2)
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
// check that every letter of keyword is alphabetic
char *keyword = argv[1];
int keylen = strlen(keyword);
for (int i = 0, n = keylen; i < n; i++)
{
if(!isalpha(keyword[i]))
{
printf("alphabetic keyword only!!!\n");
return 1;
}
if(isalpha(keyword[i]))
{
// if a letter of keyword is uppercase
if (isupper(keyword[i]))
{
keyword[i] = keyword[i] - 'A';
}
// if a letter of keyword is lowercase
if (islower(keyword[i]))
{
keyword[i] = keyword[i] - 'a';
}
}
}
char *text = GetString();
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
// if plaintext letter uppercase then...
if (isupper(text[i]))
{
text[i] = ((text[i] - 'A') + (keyword[i % keylen])) % 26 + 'A';
printf("%c",text[i]);
// ^^^^^^ ----> repeat the pattern
}
// if plaintext letter lowercase then ...
if (islower(text[i]))
{
text[i] = ((text[i] - 'a') + (keyword[i % keylen])) % 26 + 'a';
printf("%c",text[i]);
}
}
// if no letters in plaintext then ...
if (!isalpha(text[i]))
{
text[i] = text[i];
printf("%c",text[i]);
}
}
printf("\n");
}
So as #BLUEPIXY suggested I had to use a different variable in order to get the right answer:
`char *text = GetString();
int k = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
// if plaintext letter uppercase
if (isupper(text[i]))
{
text[i]= ((text[i] - 'A') + (keyword[k % keylen])) % 26 + 'A';
printf("%c",text[i]);
//^^^^^ ----> repeat the keyword pattern
}
// if plaintext letter lowercase
if (islower(text[i]))
{
text[i] = ((text[i] - 'a') + (keyword[k % keylen])) % 26 + 'a';
printf("%c",text[i]);
}
k++;
}`
I'm trying to make a Vigenère encryption code for my problem set of the week and I'm almost done. I have a little problem, I can't make the keyword char shift only on alphabetical chars this is my code and I can't track the problem.
GetString() is implemented by library (it's like scanf) & string typedef also
int main(int argc, string argv[])
{
string keyWord;
if( argc != 2 )
{
printf("Wrong Argument");
return 1;
}
else
{
keyWord = argv[1];
//check if argument is
//only alphabetical characters
for(int i = 0; i < strlen(keyWord); i++)
{
char c = keyWord[i];
if( !isalpha(c) )
{
printf("Your Keyword Must Contain Only alphabetical characters\n");
return 1;
}
}
}
string plainText = GetString();
for(int i = 0,j = 0; i < strlen(plainText); i++,j++)
{
if(j >= strlen(keyWord))
j = 0;
char c = plainText[i];
int keyWordWrapper;
char keyC;
if(isalpha(c))
{
keyWordWrapper = j % strlen(keyWord);
keyC = keyWord[keyWordWrapper];
int key;
tolower(c);
if(islower(keyC))
key = keyC - 'a';
if(isupper(keyC))
key = keyC - 'A';
c = (c - 'a' + key) % 26 + 'a';
}
printf("%c",c);
}
printf("\n");
return 0;
}
you may do the following
//to skip the spaces
if(c==32)
{
j--;
continue;
}
char c = plainText[i];
int keyWordWrapper;
char keyC;
if(isalpha(c))
{
keyWordWrapper = j % strlen(keyWord);
keyC = keyWord[keyWordWrapper];
int key;
tolower(c);
if(islower(keyC))
{
key = keyC - 'a';
c = (c - 'a' + key) % 26 + 'a';
}
if(isupper(keyC))
{
key = keyC - 'A';
c = (c - 'A' + key) % 26 + 'A';
}
}