CS50 Caesar - Check50 won't validate my code - arrays

I know that this question have been asked before, but I still can't find the clue to the problem in my code.
My program works apparently fine, but I'm not able to pass the check50 test. From what I understand, the issue may be related to the fact that the null \0 is printed. But I don't know how to modify that. Could you please help me?
This is my code:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
bool only_digits(string s);
char rotate(char c, int n);
int main(int argc, string argv[])
{
string h = argv[1];
if (argc != 2 || !only_digits(h) || h <= 0)
{printf("Usage: ./caesar key\n");
return 1;
}
else
{
int key = atoi(argv[1]);
string plaintext = get_string("plaintext: ");
int f = strlen(plaintext);
printf("ciphertext: ");
for(int q = 0; q < f; q++)
{
printf("%c", rotate(plaintext[q], key));
}
printf("\n");
}
return 0;
}
bool only_digits(string s )
{
for (int i = 0, n = strlen(s); i < n; i++)
{
char digit = s[i];
if (!isdigit(digit))
return false;
}
return true;
}
char rotate(char c, int n)
{
if(isupper(c) && (c != '\0'))
{
printf("%c", (((c - 65) + n) % 26) + 65);
}
else
if(islower(c) && (c != '\0'))
{
printf("%c", (((c - 97) + n) % 26) + 97);
}
else
printf("%c", c);
return 0;
}
This is a caption of check50's check:
check50

rotate always returns 0, so printf("%c", rotate(plaintext[q], key)); is causing the letters you output to be interspaced with NUL characters.
I would keep that printf, but change rotate to return the character instead of printing it.

Related

CS50 Caesar. invisible characters printing after upper case letters

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

How to handle handles lack of argv[1] and handles too many arguments in caesar?

I finished Caesar pset2 for CS50, but when I run it for a check-up, I get 2 errors. One for how handles lack of argv[1] and the other being too many arguments. I've been stuck on this for several hours and haven't made any progress. Any tips on how to move forward?
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int strtoint;
int onlydigits = 0;
if (argc == 2) //Checks the program with one command-line argument
{
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (isdigit(argv[1][i]))
{
onlydigits += 1;
}
}
if (onlydigits == strlen(argv[1])) //Checks if characters are digits
{
strtoint = atoi(argv[1]); //Converts string to int
string plain = get_string("plaintext: "); //Prompt user for input
printf("ciphertext: ");
for (int j = 0, m = strlen(plain); j < m; j++) //Iterate over each character for plaintext
{
if (isalpha(plain[j]) && isupper(plain[j])) //Checks if characters are uppercase
{
printf("%c", (((plain[j] - 65) + strtoint) % 26) + 65);
}
else if (isalpha(plain[j]) && islower(plain[j])) //Checks if characters are lowercase
{
printf("%c", (((plain[j] - 97) + strtoint) % 26) + 97);
}
else
{
printf("%c", plain[j]); //Prints as is if neither of the above
}
}
printf("\n"); //Prints a new line
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
output for code

cs50 - Caesar Cipher - I keep seeing this, error handling non numeric key

I'm working on project work and when I try checking if I've got everything in the code as expected, I see this error,
handles non-numeric key
timed out while waiting for the program to exit.
The code decrypts words or letters being passed into the input with a key. (I just thought I should let you know about that)
here is my actual code. everything seems right except that error code I keep getting each time I check to see all went well.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
//declaration of function prototype
bool only_digits(string s);
char rotate(char c, int n);
int main(int argc, string argv[])
{
// string s = argv[1];
//command line argument
if(argc != 2 || !only_digits(argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}
//convert argv[1] to an int
int key = atoi(argv[1]);
//prompt user for plaintext
string text = get_string("plaintext: ");
//output of plaintext
printf("ciphertext: ");
for(int i = 0; text[i]; i++)
{
text[i] = rotate(text[i], key);
printf("%c", text[i]);
}
printf("\n ");
return 0;
}
bool only_digits(string s)
{
for(int i = 0; i < strlen(s); i++)
{
//check whether the character inputed is a digit 0 - 9
if(isdigit(s[i]))
{
return true;
}
else{
return false;
}
}
return false;
}
char rotate(char c, int n)
{
char cipher_text = c;
if(islower(c))
{
cipher_text = 'a' + ((c - 'a') + n) % 26;
return cipher_text;
}
else if(isupper(c))
{
cipher_text = 'A' + ((c - 'A') + n) % 26;
return cipher_text;
}
return cipher_text;
}
any help will be much appreciated.
Here is a working self-contained solution. It hard-codes the clear text:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool only_digits(const char *s);
char rotate(char c, int n);
int main(int argc, char *argv[]) {
if(argc != 2 || !only_digits(argv[1])) {
printf("Usage: ./caesar key\n");
return 1;
}
int key = atoi(argv[1]);
char *cleartext = "test";
printf("ciphertext: ");
for(; *cleartext; cleartext++) {
printf("%c", rotate(*cleartext, key));
}
printf("\n");
return 0;
}
bool only_digits(const char *s) {
for(; *s && isdigit(*s); s++);
return !*s;
}
char rotate(char c, int n) {
#define ROTATE2(a, c, n) (a) + (((c) - (a)) + (n)) % 26
if(islower(c)) {
return ROTATE2('a', c, n);
}
if(isupper(c)) {
return ROTATE2('A', c, n);
}
return c;
}
It fixes the only_digits() to look at all characters unless s contains a non-digit in which case it would fail early. Simplified the rotate a bit using a macro to avoid the duplicate code. You could write a 2nd function instead of the macro if you so choose.

Struggling with wraparound counting in C

I'm a newbie, so apologies if I don't explain myself well. If it helps, I'm doing this for the Caesar problem set as part of the Harvard CS50x OpenCourseWare.
I'm trying to convert user generated plain text to cipher text using a simple key. To accomplish this I'm attempting to use a wraparound counting formula in my last function. However, sometimes I get blanks that print out instead of the new characters... Help!
EDIT: I'm using a key of 5 and the plaintext "Helloz!" to test. Expect to see Mjqqte!
instead am seeing blank spaces.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
int convert(string n);
string k, text;
char text;
int r, c, t,x;
bool validate(string n);
//int encrypted(string n);
int main(int argc, string argv[])
{
//accept single command-line argument, non negative integer, k with appropriate error
k = argv[1];
if (argc > 1 && argc <= 2)
{
//printf("Success\n%s\n", argv[1]);
// print individual characters of argv[i]
validate(k);
}
else //if wrong input then print error message and main should return 1
{
printf("Usage: ./caesar key\n");
return 1;
}
text = get_string("plaintext:");
t = atoi(k);
printf("%i\n", t);
convert (text);
printf("\n");
}
//output "ciphertext:" without a newline, with the characters roated by k positions
//after output, print a newline and exit by returning 0 from main
bool validate(string n)
{
for (int i = 0; k[i] != '\0'; i++)
{
if (48 <= k[i] && k[i] <= 57)
{
//printf("%c\n", k[i]);
}
else
{
printf("./caesar key\n");
return 1;
// save for later: printf("%s \n", k);
}
}
return r;
}
int convert(string n)
{
//if fits within a range, Reads individual characters
for (int i = 0; i < text[i]; i++)
{
if (isalpha(text[i]))
{
x = text[i];
//printf("%i\n", x);
c = (x+t) % 26;
// printf("%i\n",c);
printf("%c", c);
}
else
{
printf("%i", text[i]);
}
}
return 0;
}
Here's an implementation that could work for you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
void convert(char *text, unsigned char k) {
for (unsigned int i = 0; i < strlen(text); i++) {
if (isalpha(text[i])) {
// Contains the 3 leftmost bits, containing the uppercase/lowercase part.
char c = (text[i] / 32) * 32;
// Perform the shifting with modulo on the alphabetic index of the letter.
text[i] = c + ((text[i] % 32) + k) % 26;
}
}
}
int main(int argc, char *argv[]) {
unsigned char k = strtol(argv[1], NULL, 10);
char text[64];
printf("Using key %d.\n", (int) k);
printf("Plaintext: ");
fgets(text, 64, stdin);
// Remove newline.
text[strlen(text) - 1] = 0;
convert(text, k);
printf("Ciphertext: %s.\n", text);
return 0;
}
Test run:
>>> cipher 4
Using key 4.
Plaintext: Test mE Right Away!!1
Ciphertext: Xiwx qI Vmklx Eaec!!1.

Strange unwanted three digit code printouts from caesar cipher

The cipher code actually works; it's just that I get some odd three digit codes separated with slashes too.
Any help would be greatly appreciated. Here's my code.
The codes look like this but have random numbers /354/233/645/810/236
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cs50.h"
int i, len;
string sentance, encrypted;
int k, argvLen;
int caesar (int k){
printf("Hi I'm Ceaser! What would you like me to cipher?\n");
sentance = GetString();
len = strlen(sentance);
char encrypted[len];
for (i=0; i<len; i++) {
if (sentance[i] >='a' && sentance[i] <='z') {
encrypted[i] = ((sentance[i] - 'a' + k) % 26) + 'a';
}
else if (sentance[i] >='A' && sentance[i] <='Z') {
encrypted[i] = ((sentance[i] - 'A' + k) % 26) + 'A';
}
else if (sentance[i] >=' ' && sentance[i] <= '#'){
encrypted[i] = sentance[i];
}
}
printf("%s", encrypted);
return 0;
};
int main (int argc, const char * argv[]) {
if (argc==2) {
k = atoi(argv[1]);
argvLen = strlen(argv[1]);
for (i=0; i<argvLen; i++){
if (isdigit(argv[1][i])){
caesar(k);
}
else {
printf("please enter a number for the key!");
return 1;
}
}
return 0;
}
};
You are not terminating the encrypted string properly.
You need:
To make sure you have room for the terminating character, by using char encrypted[len + 1];.
encrypted[len] = '\0'; after the loop.

Resources