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++;
}`
Related
Stuck on this problem. Codes compiles, and takes input. however when attempting to use key '1' with plaintext 'a', i'm expecting 'b' but returning "\001" (which is not printing) when i check the debugger. Can someone help me explain why this is happening? I suspect error is when im allocating memory for the cypher test.. or when actually doing the cypher in my for / if statements.
int main(int argc,string argv[])
{
check_commands(argc);
//checks if key is alpha
string key = argv[1];
for (int i = 0; i < strlen(key); i++)
{
if (isalpha(key[i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//convert string argv[1] into an int
int k = atoi(key);
//ask user for pplaintect
string plaintext = get_string("Plaintext: ");
//create cyphertext variable
int s = strlen(plaintext);
char *cyphertext = malloc(s + 1);
printf("Cyphertext: ");
for (int i = 0; i < s; i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
// cypher based of k but keep upper
cyphertext[i] = ((plaintext[i] - 65) + k) % 26;
//print uppercase cypher
printf("%s", cyphertext);
}
if (islower(plaintext[i]))
{
//cypher based of k but keep lower
cyphertext[i] = ((plaintext[i] - 97) + k) % 26;
//print lowercase cypher
printf("%s", cyphertext);
}
}
else
{
printf("%c", plaintext[i]);
}
}
free(cyphertext);
printf("\n");
}
int check_commands(int argc)
{ //checks wether we have two command line arguments
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1; //error
}
return 0;
}
You're just putting the modulus into cyphertext. You need to add that to the first character of the alphabet to get the corresponding letter, just as you subtract the character before adding k.
cyphertext[i] = 'A' + ((plaintext[i] - 'A') + k) % 26;
Also, don't hard-code ASCII codes like 65 and 97. Use character literals.
You allocated an uninitialized memory
char *cyphertext = malloc(s + 1);
It does not contain a string. So you may not use the conversion specifier s in calls of printf like this
printf("%s", cyphertext);
Also in these statements
cyphertext[i] = ((plaintext[i] - 65) + k) % 26;
and
cyphertext[i] = ((plaintext[i] - 97) + k) % 26;
you are storing not printable alpha characters.
Also this record
int s = strlen(plaintext);
is redundant.
Use do-while loop instead of the for loop. For example
size_t i = 0;
do
{
if ( isupper( ( unsigned char )plaintext[i] ) )
{
// cypher based of k but keep upper
cyphertext[i] = 'A' + ( plaintext[i] - 'A' + k ) % 26;
}
else if ( islower( ( unsigned char )plaintext[i] ) )
{
//cypher based of k but keep lower
cyphertext[i] = 'a' + ( plaintext[i] - 'a' + k ) % 26;
}
else
{
cyphertext[i] = plaintext[i];
}
} while ( plaintext[i++] != '\0' );
puts( cyphertext );
free( cyphertext );
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;
}
So I need to write a program which ciphers text adding x (argv[1] = x) to a text prompted to the user. i.e:
./program 1 //running the program with argv[1] = 1
plaintext: abcd //prompting the user to write characters he want to cipher
ciphertext: bcde // returning plaintext ciphered with the argv[1] "key" = 1
This is my code
int main (int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./ceasar key\n");
return 1;
}
else if (argc ==2)
{
int k = atoi(argv[1]);
for (int j = 0, len = strlen(argv[1]); j < len; j++)
{
if (!isdigit(argv[1][j]))
{
printf("Usage: ./ceasar key\n");
return 1;
}
}
for (int j = 0, len = strlen(argv[1]); j < len; j++)
{
if (isdigit(argv[1][j]))
{
string s = get_string("plaintext: ");
printf("ciphertext: ");
for (int i = 0, n = strlen(s); i <= n; i++)
{
if ('#' < s[i] && s[i] < '[')
{
printf("%c", (s[i] - 'A' + k) % 26 + 'A');
}
else if('`' < s[i] && s[i] < '{')
{
printf("%c", (s[i] - 'a' + k) % 26 + 'a');
}
else
{
printf("%c", s[i]);
}
printf("\n");
return 0;
}
}
}
}
}```
The first lines checks if argc !=2, and if argv[1][j] has a non numeric character. Once that is done it will get argv[1] and add it to each character given from the user. but it wont work correctly.
**Any sugestions?**
I tested your code. It prints one single character which means your final for loop returns too fast. This loop iterates just once because it returns 0 at the end of its iteration. If you move return 0 out of the for loop together with printf("\n"), your code will work.
Solution;
for (int j = 0, len = strlen(argv[1]); j < len; j++)
{
if (isdigit(argv[1][j]))
{
string s = get_string("plaintext: ");
printf("ciphertext: ");
for (int i = 0, n = strlen(s); i <= n; i++)
{
if ('#' < s[i] && s[i] < '[')
{
printf("%c", (s[i] - 'A' + k) % 26 + 'A');
}
else if('`' < s[i] && s[i] < '{')
{
printf("%c", (s[i] - 'a' + k) % 26 + 'a');
}
else
{
printf("%c", s[i]);
}
}
printf("\n");
return 0;
}
}
I keep making changes to the looping part of this code and my check50 always fails. I don't know what's going on. Below is my code:
#include <stdio.h>
#include <ctype.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv[])
{
// declare variables
int cipherText;
if (argc != 2)
{
printf("Usage: ./vigenere keyword");
printf("\n");
return 1;
}
// keyword is the second command line argument
string key = argv[1];
int keylen = strlen(argv[1]);
// iterate through keyword to check if alphabetical
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if ((key[i] >= '0') && (key[i] <= '9'))
{
printf("Keyword must consist only of letters.");
return 1;
}
}
// get the plaintext
string plainText = GetString();
// encypher - iterate over the characters in string, print each one encrypted
for (int i = 0, j = 0, n = strlen(plainText); i < n; i++, j++)
{
// start the key again if key shorter than plainText
if (j >= strlen(key))
{
j = 0;
}
// skip key[j] if plainText[i] is not an alpha character
if (!isalpha(plainText[i]))
{
j = (j-1);
}
// makes Aa = 0, Zz = 25 for the uppercase letters
if (isupper(key[j]))
{
key[j] = (key[j] - 'A');
}
// makes Aa = 0, Zz = 25 for lowercase letters
else if (islower(key[j]))
{
key[j] = (key[j] - 'a');
}
if (isupper(plainText[i]))
{
cipherText = (plainText[i] - 'A');
cipherText = ((cipherText + key[j%keylen])%26) + 'A';
printf("%c", cipherText);
}
else if (islower(plainText[i]))
{
cipherText = (plainText[i] - 'a');
cipherText = ((cipherText + key[j%keylen])%26 + 'a');
printf("%c", cipherText);
}
else
{
printf("%c", plainText[i]);
}
}
printf("\n");
return 0;
}
Some answered this: "The first for loop has a problem. The condition is checking for i > keylen when it should be checking for i < keylen".
Also when computing the next output value, the steps should be
(p[i]-65) results in a number between 0 and 25
adding (key[i % keylen]) results in a number between 0 and 50
apply modulo 26 so the number is between 0 and 25 (this is the missing step)
then add 65 to get the output"
and it's what I tried to do.
Given this code:
int keylen = strlen(argv[1]);
// iterate through keyword to check if alphabetical
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if ((key[i] >= '0') && (key[i] <= '9'))
{
printf("Keyword must consist only of letters.");
return 1;
}
}
Your test inside the loop identifies digits as 'not a letter' (which is valid), but ignores punctuation, spaces and so on. You should probably be using if (!isalpha(key[i])) for the test (and it is courteous to print the erroneous character in the error message, which should be printed on standard error, not standard output, and should end with a newline:
fprintf(stderr, "Keyword must consist only of letters (%c found at %d)\n",
key[i], i+1);
You could refine that so it doesn't try printing non-printable characters with %c, but this is a huge step in the right direction.
You really don't need to set n in the loop; you just set keylen before the loop, so you could have written:
for (int i = 0; i < keylen; i++)
However, that is mostly cosmetic. Your real problem lies here:
// start the key again if key shorter than plainText
if (j >= strlen(key))
{
j = 0;
}
// makes Aa = 0, Zz = 25 for the uppercase letters
if (isupper(key[j]))
{
key[j] = (key[j] - 'A');
}
// makes Aa = 0, Zz = 25 for lowercase letters
else if (islower(key[j]))
{
key[j] = (key[j] - 'a');
}
You modify the key string on each iteration through the key. Unfortunately, though, if any of the letters in the key is a or A, you've converted that to '\0', which means that strlen(key) returns a different answer from before. So, you should use keylen in place of strlen(). AFAICS, if there isn't an a or A, that part of the code is OK.
Later, you have:
if (isupper(plainText[i]))
{
cipherText = (plainText[i] - 'A');
cipherText = ((cipherText + key[j%keylen])%26) + 'A';
printf("%c", cipherText);
}
The j % keylen is superfluous; j is already limited to 0 .. keylen-1. Similarly with the code for lower-case text.
Putting these changes together, and dummying up a GetString() function using fgets(), I get:
#include <stdio.h>
#include <ctype.h>
// #include <cs50.h>
#include <stdlib.h>
#include <string.h>
typedef char *string;
static char *GetString(void)
{
static char buffer[4096];
if (fgets(buffer, sizeof(buffer), stdin) == 0)
{
fprintf(stderr, "EOF detected in GetString()\n");
exit(EXIT_SUCCESS);
}
buffer[strlen(buffer) - 1] = '\0';
return buffer;
}
int main(int argc, string argv[])
{
// declare variables
int cipherText;
if (argc != 2)
{
printf("Usage: ./vigenere keyword");
printf("\n");
return 1;
}
// keyword is the second command line argument
string key = argv[1];
int keylen = strlen(argv[1]);
// iterate through keyword to check if alphabetical
for (int i = 0; i < keylen; i++)
{
if (!isalpha(key[i]))
{
printf("Keyword must consist only of letters (%c at %d)\n",
key[i], i+1);
return 1;
}
}
// get the plaintext
string plainText = GetString();
// encypher - iterate over the characters in string, print each one encrypted
for (int i = 0, j = 0, n = strlen(plainText); i < n; i++, j++)
{
// start the key again if key shorter than plainText
if (j >= keylen)
{
j = 0;
}
// skip key[j] if plainText[i] is not an alpha character
if (!isalpha(plainText[i]))
{
j = (j - 1);
}
// makes Aa = 0, Zz = 25 for the uppercase letters
if (isupper(key[j]))
{
key[j] = (key[j] - 'A');
}
// makes Aa = 0, Zz = 25 for lowercase letters
else if (islower(key[j]))
{
key[j] = (key[j] - 'a');
}
if (isupper(plainText[i]))
{
cipherText = (plainText[i] - 'A');
cipherText = ((cipherText + key[j]) % 26) + 'A';
printf("%c", cipherText);
}
else if (islower(plainText[i]))
{
cipherText = (plainText[i] - 'a');
cipherText = ((cipherText + key[j]) % 26 + 'a');
printf("%c", cipherText);
}
else
{
printf("%c", plainText[i]);
}
}
printf("\n");
return 0;
}
Sample run:
$ ./vigenere bakedalaska
What a wonderful world! The news is good, and the Vigenere cipher is solved.
Xhkx d wznvorguv arrwd! Lre oegw ls rogn, aod dlh Vtgwxese mmshpr ac splfig.
$
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';
}
}