I coded the assignment and followed the best that I could. I can pass all of the Check50 arguments except one! Help?? The validation is correct, but when I run the debugger, it begins to give me problems around the ciphering section. Thank you!
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int arg, string argv[])
{
//KEY VALIDATION
if (arg != 2) //checks to make sure that arg is 2 (for # of arguments)
{
printf("Usage: ./caesar key\n");
return 1;
}
else if (arg == 2)
{ // checks key for validity
for(int i = 0, len = strlen(argv[1]); i < len; i++)
{
if (!isdigit(argv[1][i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//int key = atoi(argv[1]);
}
//ciphering
int key = atoi(argv[1]);
string plain = get_string("plaintext: ");
int len_plain = strlen(plain);
string cipher = plain;
for (int x = 0; x < len_plain; x++)
{
if (plain[x] >= 'a' && plain[x] <= 'z')
{
cipher[x] = ((plain[x] + key)%122);
if (cipher[x]<97)
{
cipher[x] = cipher[x] + 96;
}
}
else if (plain[x] >= 'A' && plain[x] <= 'Z')
{
cipher[x] = ((plain[x] + key)%90);
if (cipher[x] < 65)
{
cipher[x] = cipher[x] + 64;
}
}
else
{
cipher[x] = plain[x];
}
}
printf("ciphertext: %s\n", cipher);
}
the check50 results I keep getting are,
:) caesar.c exists.
:) caesar.c compiles.
:) encrypts "a" as "b" using 1 as key
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
***:( encrypts "barfoo" as "onesbb" using 65 as key
output not valid ASCII text
printf("ciphertext: ");
for (int x = 0, y = len_plain; x < y; x++)
{
//Use islower and isupper instead of typing so much words
if islower(code[i])
{
printf("%c", (((code[i] + k) - 97) % 26) + 97);
}
else if isupper(code[i])
{
printf("%c", (((code[i] + k) - 65) % 26) + 65);
}
//If neither then just print it
else
{
printf("%c", code[i]);
}
}
printf("\n")
Related
I've written the below code for the Caesar project in CS50 and I felt like it was hitting the brief, but when I have run the check, both of the checks containing uppercase letters are coming back incorrect There seems to be some extra characters printed between each of the uppercase letters that don't appear when I run the code myself.
Am I missing something in my code that's causing this to happen?
the message from Check50
:( encrypts "BARFOO" as "EDUIRR" using 3 as key
expected "ciphertext: ED...", not "ciphertext: E\..."
:( encrypts "BaRFoo" as "FeVJss" using 4 as key
expected "ciphertext: Fe...", not "ciphertext: F\..."
my code
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
bool only_digits(string s);
char rotate(int, int);
int main(int argc, string argv[])
{
//make sure key is entered correctly
{
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
int cont = only_digits(argv[1]);
if (cont != 1)
{
return 1;
}
else
{
// convert key from string to int
int key = atoi(argv[1]);
string plain = get_string("plain text: \n");
// rotate the letters using the key
printf("ciphertext: ");
{
for (int i = 0, len = strlen(plain); i < len; i++)
{
rotate(plain[i], key);
}
}
printf("\n");
}
}
}
}
//rotate the letters using the key
char rotate(int p, int i)
{
// rotate uppers
if isupper(p)
{
p = p - 65;
char c = (p + i) % 26;
c += 65;
printf("%c", c);
}
// rotate lowers
if islower(p)
{
p = p - 97;
char c = (p + i) % 26;
c += 97;
printf("%c", c);
}
// if its a character keep the same
else
{
printf("%c", p);
}
return 0;
}
//make sure key entered is only digits
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (!isdigit(s[i]))
{
printf("Usage: ./caesar key\n");
return 0;
}
else
{
;
}
}
return 1;
}
While I am unsure if it's your only bug, you forgot an else if in your rotate function such that upper case letters would print in the first case but also the else to the second case after they had been modified.
char rotate(int p, int i)
{
// rotate uppers
if isupper(p)
{
p = p - 65;
char c = (p + i) % 26;
c += 65;
printf("%c", c);
}
// rotate lowers
else if islower(p) // without else if here, upper cases would fall into the else below with p - 65
{
p = p - 97;
char c = (p + i) % 26;
c += 97;
printf("%c", c);
}
// if its a character keep the same
else
{
printf("%c", p);
}
return 0;
}
I completed the caesar assignment on cs50 and tested it on my terminal and it worked perfectly, but on check50 is kept failing some tests.
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
int getkey(string k);
string cipher(string s, int key);
int key;
int p;
int q;
int main(int argc, string argv[])
{
// Allow 2 command line inputs
if (argc == 2)
{
// Assign a local string to allow char scan
string s = argv[1];
// Check if all inputs are numbers
for (int i = 0; s[i] != 0; i++)
{
if (s[i] < 48 || s[i] > 57)
{
printf("Usage: ./caesar key\n");
return 1;
}
}
// Get key from string
int cipherkey = getkey(s);
// Get user text
string text = get_string("plaintext: ");
// Calculate ciphertext and print
string ciphertext = cipher(text, cipherkey);
printf("ciphertext: %s\n", ciphertext);
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
// Change string to int. Turns out theres already a function for this called atoi()
int getkey(string k)
{
key = 0;
for(int i = 0, conv = 0, n = strlen(k); k[i] != 0; i++, n--)
{
// Calcute the placevalue
p = pow(10, n-1);
conv = k[i] - 48; // Convert to int
key = key + (conv * p); // Sum up
}
return key % 26;
}
// Cipher text
string cipher (string s, int key)
{
for(int i = 0; s[i] != 0; i++)
{
if(islower(s[i]))
{
s[i] = s[i] + key;
while(s[i] > 122)
{
s[i] = (s[i] - 123) + 97;
}
}
else if(isupper(s[i]))
{
s[i] = s[i] + key;
while(s[i] > 90)
{
s[i] = (s[i] - 91) + 65;
}
}
}
return s;
}
with error message
:) caesar.c compiles.
:) encrypts "a" as "b" using 1 as key
:( encrypts "barfoo" as "yxocll" using 23 as key
output not valid ASCII text
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
output not valid ASCII text
:) handles lack of argv[1]
:) handles non-numeric key
:) handles too many arguments
I wrote the code without knowing the "atoi" function so i implemented a function called getkey() to return key. when i returned key normally, it failed.
:( encrypts "barfoo" as "onesbb" using 65 as key
Output not a valid ASCII text
Until i returned key % 26;
I dont know why check50 isnt working although the program works well on my terminal. Please help.
Updated code:
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
string cipher(string s, int key);
int main(int argc, string argv[])
{
// Allow 2 command line inputs
if (argc == 2)
{
// Assign a local string to allow char scan
string s = argv[1];
// Check if all inputs are numbers
for (int i = 0; s[i] != 0; i++)
{
if (s[i] < 48 || s[i] > 57)
{
printf("Usage: ./caesar key\n");
return 1;
}
}
// Get key from string
int cipherkey = atoi(s);
// Get user text
string text = get_string("plaintext: ");
// Calculate ciphertext and print
string ciphertext = cipher(text, cipherkey);
printf("ciphertext: %s\n", ciphertext);
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
// Cipher text
string cipher (string s, int key)
{
for(int i = 0; s[i] != 0; i++)
{
if(islower(s[i]))
{
s[i] = (int) s[i] + key;
while(s[i] > 'z')
{
s[i] = (s[i] - 123) + 97;
}
}
else if(isupper(s[i]))
{
s[i] = (int) s[i] + key;
while(s[i] > 'Z')
{
s[i] = (s[i] - 91) + 65;
}
}
}
return s;
}
I've rewritten the function trying to avoid going to far making corrections and improvements. Now, the copy is actually unnecessary, but I hope it helps you understand that a "signed (8 bit) char" is not 'wide' enough to use in calculations that lead to overflow...
Please read the following and try to follow along.
string cipher( string s, int key ) {
for( int i = 0; s[i] != '\0'; i++ ) {
if( !isalpha( s[i] ) )
continue;
int copy = (int)s[i]; // unnecessary casting, but...
// transform ASCII value into 0-25 range
if( islower( s[i] ) )
copy = copy - 'a';
else // must be uppercase
copy = copy - 'A';
copy = (copy + key) % 26;
// transform enciphered MODULO back into ASCII char
if( islower( s[i] ) )
copy = copy + 'a';
else // must be uppercase
copy = copy + 'A';
s[i] = copy;
}
return s;
}
Quiet night, so I thought I'd rewrite the rewrite just to see what it looked like...
string cipher( string s, int key ) {
for( char *cp = s; *cp; cp++ )
if( isalpha( *cp ) ) {
char c = "Aa"[ !!islower(*cp) ];
*cp = (char)(((*cp - c + key) % 26) + c);
}
return s;
}
I am working on Problem Set 2 on CS50 doing the caesar question and having some trouble.
I have tried the below code but it seems to only produce random characters for single character plaintext entries and world, say hello!
Please excuse the lack of comments.
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
//expects function to be declared later
bool validate(string key);
//Command line argument that launches with KEY
int main(int argc, string argv[])
{
//reject all input that is not a single string with the key
string key = argv[1];
if (argc != 2)
{
printf("Usage: ./caesar key");
return 1;
}
else if (validate(key)==true)
{
string plaintext = get_string("plaintext: ");
char ciphertext[strlen(plaintext)];
int intkey = atoi(key);
for(int i = 0; i < strlen(plaintext); i++)
{
if ((plaintext[i] >= 65 && plaintext[i] <=90) || (plaintext[i] >=97 && plaintext[i] <=122))
{
if ((plaintext[i]+(intkey % 26) > 122) || (plaintext[i]+(intkey % 26) >90 && plaintext[i]+(intkey % 26) < 97))
{
ciphertext[i] = plaintext [i] - (26 - intkey % 26);
}
else
{
ciphertext[i] = plaintext[i] + intkey % 26;
}
}
else
{
ciphertext[i] = plaintext[i];
}
}
printf("ciphertext: %s\n", ciphertext);
}
else
{
printf("Usage: ./caesar key");
}
}
bool validate(string key)
{
int count = 0;
for (int i = 0; i < strlen(key); i++)
{
if(isdigit(key[i]))
{
count++;
}
}
if (count == strlen(key))
{
return true;
}
else
{
return 1;
}
}
I am working on Problem Set 2 on CS50 doing the caesar question and having some trouble.
I have tried the below code but it seems to only produce random characters for single character plaintext entries and world, say hello!
Please excuse the lack of comments.
ciphertext[] is not terminated with a null character, it even lacks the room for it, hence printf("ciphertext: %s\n", ciphertext) may well produce random characters after the actual ciphertext. This may be rectified by adding 1 to both occurrences of strlen(plaintext).
I am doing Caesar exercise from CS50 course, but it fail.
Here is the code:
# include <stdio.h>
# include <cs50.h>
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
string key = argv[1];
int l = strlen(key);
for (int i = 0; i < l; i++)
{
// if key[i] is an alphabet character
if (isalpha(key[i]) != 0)
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//change charater to number
int k = atoi(argv[1]);
//print Plaintext
string plaintext = get_string("Plaintext: ");
int n = strlen(plaintext);
char ciphertext[n];
//declare plaintext in ASCII
int nplaintext[n];
//Change plaintext to ASCII
for (int i = 0; i < n; i++)
{
nplaintext[i] = (int)plaintext[i];
}
//Declare ASCII for ciphertext which we name "plusplaintext"
int plusnplaintext[n];
for (int i = 0; i < n; i++)
{
//if Capital
if ((nplaintext[i] < 91) && (nplaintext[i] > 64))
{
plusnplaintext[i] = 65 + ((nplaintext[i] + k) - 65) % 26 ;
}
//if Lowercase
else if ((nplaintext[i] < 123) && (nplaintext[i] > 96))
{
plusnplaintext[i] = 97 + ((nplaintext[i] + k) - 97) % 26 ;
}
//if not character a -> z and A -> Z
else
{
plusnplaintext[i] = nplaintext[i];
}
}
for (int i = 0; i < n; i++)
{
ciphertext[i] = (char)plusnplaintext[i];
}
printf("ciphertext: %s\n", ciphertext);
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
Here is the output from Check50:
:) caesar.c exists.
:) caesar.c compiles.
**:( encrypts "a" as "b" using 1 as key, output not valid ASCII text**
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
**:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key, output not valid ASCII text**
:) handles lack of argv[1]
When I test the code, sometimes it gives right result, sometimes it give the wrong result with some more characters at the end...
How can I correct my code?
The problem is with the logic here
//if Capital
plusnplaintext[i] = 65 + ((nplaintext[i] + k) - 65) % 26 ;
and
//if Lowercase
plusnplaintext[i] = 97 + ((nplaintext[i] + k) - 97) % 26 ;
use this logic instead
//if Capital
((((nplaintext[i] - 90) + 25) + key) % 26) + 65
//if Lowercase
((((nplaintext[i] - 122) + 25) + key) % 26) + 97
and it is also not necessary to assign the letters to a string, instead you can directly print it
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
// Error Checking on the command line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else if (argc == 2)
{
for (int i = 0; i < strlen(argv[1]); i++)
{
if (isdigit(argv[1][i]) == 0)
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
int key = atoi(argv[1]);
string plain_text = get_string("plaintext: ");
printf("ciphertext: ");
for (int i = 0; i < strlen(plain_text); i++)
{
if (isalpha(plain_text[i]) != 0)
{
// printf("%c", plain_text[i] + key);
if (isupper(plain_text[i]))
{
printf("%c", ((((plain_text[i] - 90) + 25) + key) % 26) + 65);
}
else
{
printf("%c", ((((plain_text[i] - 122) + 25) + key) % 26) + 97);
}
}
else
{
printf("%c", plain_text[i]);
}
}
printf("\n");
}
Instead of using the ascii value of a letter in your code, it could be helpful to keep them as characters for the sake of clarity. I took a snippet of your code and changed the values to demonstrate.
//if Capital
if ((nplaintext[i] <= 'Z') && (nplaintext[i] >= 'A'))
{
plusnplaintext[i] = 'A' + ((nplaintext[i] + k) - 'A') % 26 ;
}
This makes it clear what those values represent, and you don't have to reference an ascii chart. More comments would also help a user, or yourself later on, understand what the purpose is for each part of your code.
You could also create some functions outside of your main function. For example, to check for all digits in command line input, or change the letters by the amount given in the key. If you start working on long programs of code, it could be helpful to have functions defined that you can use as many times as you need. It also cleans up your main for clarity.
This function below takes the character of each letter in the original text (char p), then "moves" the character by k spaces (int k, given by the user as the key in the command line). It works when called in a for loop in main that iterates over each letter in the original given string (text[i]), with i being increased for each time the loop executes.
char rotate(char p, int k)
{
// declare variable for the rotated letter to be stored
char c;
// check if it is a letter
if (isalpha(p))
{
// check for lowercase letter
if (islower(p))
{
// subtract ascii value from p to initialize to 0 - 25 for computations
p -= 'a'; // if p is a, it is now initialized to 0, if b to 1, if c to 3, etc
c = (p + k) % 26; // use Caesar's algorithm to rotate letters, 'wrapping' by using % 26
c += 'a'; // add ascii value back to result to get the rotated letter
}
// the only other option is uppercase since we checked for only letters, do the same for uppercase letters as for lowercase
else
{
p -= 'A';
c = (p + k) % 26;
c += 'A';
}
}
// if it is the nul character '\0' return 0, do not print
else if (p == '\0')
{
return 0;
}
// if not a letter or nul character, return the character as is
else
{
c = p;
}
// print the rotated letter which is now stored in c
printf("%c", c);
// return the value of c
return c;
}
I am trying to make Vigenere Cipher in C. https://www.youtube.com/watch?v=9zASwVoshiM this is info about Vigenere Cipher. My code works doesnt work for certain cases like encrypts "world, say hello!" as "xoqmd, rby gflkp!" using "baz" as keyword instead it encrypts it as xomd, szz fl. Another example is:
encrypts "BaRFoo" as "CaQGon" using "BaZ" as keyword but instead it encrypts it as CakGo. My code is given below please help me out:
#include<stdio.h>
#include<cs50.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, string argv[]) {
//string plaintext;
string key;
if (argc != 2) {
printf("Please run the programme again this time using a command line argument!\n");
return 1;
}
key = argv[1];
int keys[strlen(key)];
for (int m = 0; m< strlen(key); m++) {
if (isalpha(key[m]) == false) {
printf("Re-Run The programme without any symbols.\n");
return 1;
}
}
for (int b = 0; b < strlen(key); b++) {
if (isupper(key[b]) == false) {
keys[b] = key[b] - 'a';
}
else {
keys[b] = key[b] - 'A';
}
}
//printf("Enter a string which should be encrypted: \n");
string plaintext = GetString();
int plength = strlen(plaintext);
int klength = strlen(key);
string ciphertext = key;
for (int u = 0; u<plength; u++) {
if (isalpha(plaintext[u]) == false) {
printf("%c", plaintext[u]);
continue;
}
int value = u % klength;
ciphertext[u] = (keys[value] + plaintext[u]);
if ((islower(plaintext[u])) && (ciphertext[u])>'z') {
ciphertext[u] = ciphertext[u] - 'z' + 'a' - 1;
}
if ((isupper(plaintext[u])) && (ciphertext[u])>'z') {
ciphertext[u] = ciphertext[u] - 'Z' + 'A' - 1;
}
printf("%c", ciphertext[u]);
}
printf("\n");
return 0;
}
string ciphertext = key;
ciphertext should start out as blank, it should not be set to key.
ciphertext[u] = ciphertext[u] - 'z' + 'a' - 1;
This is not correct because ciphertext[u] can go out of range. Character should be between 'a' to 'z'. Use the mod % operator to make sure character is within range. For example:
int j = 0;
for (int u = 0; u<plength; u++)
{
int c = plaintext[u];
if (isalpha(plaintext[u]))
{
int k = keys[j % klength];
if (islower(c))
{
c = 'a' + (c - 'a' + k) % 26;
}
else
{
c = 'A' + (c - 'A' + k) % 26;
}
j++;
}
ciphertext[u] = c;
}
printf("%s\n", ciphertext);
Lots of little issues (ciphertext needs to be allocated dynamically and start out as a copy of plaintext, not key; need to mod calculations to the length of the alphabet; incorrect calculations; print errors to stderr) and lots of little optimizations that can be made (combine loops; combine if clauses; save key length to a variable earlier). A rework of your code:
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[]) {
if (argc != 2) {
fprintf(stderr, "Please run the program again with a command line argument!\n");
return 1;
}
string key = argv[1];
int key_length = strlen(key);
int keys[key_length];
for (int i = 0; i < key_length; i++) {
if (!isalpha(key[i])) {
fprintf(stderr, "Re-run The program without any symbols.\n");
return 1;
}
keys[i] = toupper(key[i]) - 'A';
}
// printf("Enter a string which should be encrypted: \n");
string plaintext = GetString();
int text_length = strlen(plaintext);
string ciphertext = strcpy(malloc(text_length + 1), plaintext);
for (int i = 0, j = 0; i < text_length; i++) {
if (!isalpha(plaintext[i])) {
continue;
}
int index = j++ % key_length;
ciphertext[i] = (toupper(plaintext[i]) - 'A' + keys[index]) % (1 + 'Z' - 'A');
ciphertext[i] += isupper(plaintext[i]) ? 'A' : 'a';
}
printf("%s\n", ciphertext);
free(ciphertext);
return 0;
}
Encrypts "world, say hello!" as "xoqmd, rby gflkp!" with key "baz"
Encrypts "BaRFoo" as "CaQGon" with key "BaZ"