Cannot stop array from overflowing in Caesar algorithm - c

I have almost finished my code, but ran into the following problem. The code, luckily, works, but when I write as input ZQ, with a key of 1, it gives me the next character of the ASCII chart. Is there a way to stop it from overflowing? If it reaches Z, I'd like to go back to the first index character, which would be the A. Additionally, it seems to work better when I get rid of the % 26 in line 39, even though I need to use the formula ci = (pi + k) % 26. It gives me no characters as an output otherwise. Thanks!
If a character is uppercase, it should remain uppercase, vice versa with lowercase.
#include <stdio.h>
#include <cs50.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int k = 0;
string key = argv[1];
if (argc == 2)
{
for (k = 0; k < strlen(key); k++)
{
if (!isdigit(key[k]))
{
printf("\nUsage: %s key\n", argv[0]);
return 1;
}
}
}
else
{
printf("\nUsage: %s key\n", argv[0]);
return 1;
}
string plaintext = get_string("\nplaintext: ");
printf("ciphertext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
char c = plaintext[i];
int keycode = atoi(key);
if (isalpha(c))
{
printf("%c", (c + keycode) % 26);
}
else if (isspace(c) || isdigit(c) || ispunct(c))
{
printf("%c", c);
}
}
}

The number values for letters are offset from the values for the Cæsar cipher, depending on what case it is. You must transform them into numbers in the range of (0, 25), do the operation, and inverse transform the result back into the case selected. These transformations are fairly simple, eg for lower-case letters, F(c) = c - 'a'.

The formula is correct to handle wrapping from Z to A, but you must first convert letters to their index value in the alphabet. For the ASCII character set, this conversion is a simple subtraction but must be performed separately for uppercase (c = 'A') and lowercase letters (c - 'a').
Here is a modified version:
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(int argc, string argv[])
{
int k = 0;
string key = argv[1];
if (argc == 2)
{
for (k = 0; key[k] != '\0'; k++)
{
if (!isdigit((unsigned char)key[k]))
{
printf("\nUsage: %s key\n", argv[0]);
return 1;
}
}
}
else
{
printf("\nUsage: %s key\n", argv[0]);
return 1;
}
string plaintext = get_string("\nplaintext: ");
int keycode = atoi(key);
printf("ciphertext: ");
for (int i = 0; plaintext[i] != '\0'; i++)
{
char c = plaintext[i];
if (isupper((unsigned char)c))
{
printf("%c", 'A' + (c - 'A' + keycode) % 26);
}
else if (islower((unsigned char)c))
{
printf("%c", 'a' + (c - 'a' + keycode) % 26);
}
else // leave other characters unchanged
{
printf("%c", c);
}
}
return 0;
}

Related

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 - Check50 won't validate my code

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.

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.

How to Preserve Case of Inputted Chars in C?

The user inputs chars that can be uppercase or lowercase. I need to spit an answer back that preserves the case of the inputted char after that char is processed by my code. How do I preserve case when the char was converted to its ASCII value and then to its alphabetical index equivalent.
Here is my code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int counter = 0;
if (argc == 2) {
for (int k = 0; k < strlen(argv[1]); k++) {
if (isdigit(argv[1][k])) {
counter++;
}
}
if (strlen(argv[1]) == counter)
{
string s = get_string("plaintext: ");
printf("ciphertext: ");
for (int i = 0; i < strlen(s); i++) {
int c = (int) s[i];
if (c >= 97 && c <= 122)
{
printf("%i\n", (((c % 32) - 1 + atoi(argv[1]))) % 26);
}
printf("\n");
if (c >= 65 && c <= 90)
{
printf("%i", (((c % 32)) - 1 + atoi(argv[1])) % 26);
}
printf("\n");
}
} else {
printf("Usage: ./caesar key\n");
}
}
}
Expected behavior would print Zoo as "App" if Key entered in command line were 1.

The output isn't what i am expecting, the code isn't printing any error and i dont know whats going wrong

Vigenere cipher
Takes in a text and output a cipher version of that text
the user inputs a keyword in the command line and a text for which the user wishes to encrypt. If you're familiar with the Ceasar cipher it's pretty much the same thing except a small minor change, instead of inputting the actual shift value we instead input a keyword and the letters in the keyword would represent the shift value instead.
#include <cs50.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int shift(char c);
int main(int argc, string argv[])
{
//checks for alphabetic characters
if (argc == 2)
{
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (isalpha(argv[1][i]) == false)
{
printf("Usage: ./vigenere keyword. \n");
return 1;
}
}
//promting the user for text
string text = get_string("plaintext: ");
printf("ciphertext: ");
//Intializing variables
string key = argv[1];
int l = strlen(key);
for (int j = 0, k = 0, m = strlen(text); j < m; j++)
{
if (islower(text[j]))
{
//lower cap letter enter here
printf("%c", 'a' + ( text[j] - 'a' + shift(key[k % l]) ) % 26);
k++;
}
else if (isupper(text[j]))
{
//Upper caps letter enter here
printf("%c", 'A' + ( text[j] - 'A' + shift(key[k % l]) ) % 26);
k++;
}
else
{
//The rest whatever left enter here
printf("%c", text[j]);
}
}
printf("\n");
return 0;
}
else
{
printf("Usage: ./vigenere keyword. \n");
return 1;
}
}
//This function calculates the shift value per character
int shift(char c)
{
return ( islower(c) - 'a' );
}
the problem is that the output isn't what I expect it to be. For instance, if the keyword is 'b' and the text is 'hello' the output must be 'ifmmp' but it's not. I don't know what goes wrong.

Resources