segmentation fault on CS50 Caesar and debugging - c

Hey all I asked a question related to this code earlier and got a lot of helpful answers (I'm very green at coding). While I overcame my initial problem and corrected a few more mistakes I've run into another error that I can't seem to fix. I keep getting the Segmentation fault but I want it to prompt the user to give a second argument. Along with that when I do give the number, the code doesn't seem to actually encrypt the text Any suggestions or blaring issues I missed?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
int num;
int k = atoi(argv[1]);
string output;
if(argc != 2)
{
printf("K not included in command");
return 1;
}
string s = get_string("Insert Lowercase Message:");
for (int i = 0, n = strlen(s); i < n; i++)
{
char c = s[i];
if (c >= 'A' && c <= 'Z')
{
num = 'A';
if (c >= 'a' && c <= 'z')
num = 'a';
printf("%c", (c - num + k) % 26 + num);
}
else
printf("%c", c);
}
}

You have your braces misaligned where you are testing the case of the letters. The way it is written, if a lowercase case letter is encountered, the uppercase test will fail and you will drop through to the else case. What you want is something like this:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
int num;
int k;
string output;
char c;
if(argc != 2)
{
printf("K not included in command");
return 1;
}
k = atoi(argv[1]);
string s = get_string("Insert Lowercase Message:");
for (int i = 0; c = s[i]; i++)
{
if (isalpha(c))
{
if (isupper(c))
num = 'A';
else // islower
num = 'a';
printf("%c", (c - num + k) % 26 + num);
}
else
printf("%c", c);
}
}

Related

Having trouble reading in user input data for a program which counts the number of occurrences of letters in a string

The code seems to only count one of the occurances when using scanf() or a defined getChar() I have set up but will count all and display when the string is defined in code. How can I get the output to work correctly while having a user input.
I've tried a few different approaches at taking the user input as seen but still I don't seem to be getting the result desired.
//#define _CRT_SECURE_NO_WARNINGS
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
int main() {
char *s;
fgets(&s[0],98,stdin);
int letter_counts[26] = {0};
int length = strlen(s);
char c;
for (int i = 0; i < length; i++) {
c = toupper(s[i]);
if (c >= 'A' && c <= 'Z')
letter_counts[c - 'A']++;
}
for (int i = 0; i < 26; i++) {
if (letter_counts[i] > 0) {
printf("%c%d ", 'A' + i, letter_counts[i]);
}
}
return 0;
}
I've Now changed it to use the fgets() but I don't seem to be using that correctly either...
Your main problem is that you don't allocate any space to s. Also introduces a couple of constants instead of your magic values for size:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#define ALPHA_LEN 'Z' -'A' + 1
#define STR_LEN 98
int main() {
char s[STR_LEN+1];
if(!fgets(&s[0],STR_LEN+1, stdin)) {
printf("gets failed\n");
return 1;
}
int letter_counts[ALPHA_LEN] = {0};
size_t length = strlen(s);
for (size_t i = 0; i < length; i++) {
char c = toupper(s[i]);
if (isupper(c))
letter_counts[c - 'A']++;
}
for (size_t i = 0; i < sizeof letter_counts / sizeof *letter_counts; i++) {
if (letter_counts[i]) {
printf("%c%d ", 'A' + i, letter_counts[i]);
}
}
printf("\n");
}

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.

Problem with printing char inside if-condition

I have an assignment to cipher letters according to a formula. We are suppose to keep uppercases as uppercases and lowercases as lowercases.
The formula for ciphering is this: ci = (pi + k) % 26.
Int x in my code is k.
Pi is the character in the string.
Right now im facing two problems. The cipher is currently not working (and and the code is not done).
But the chars are not printing. Highly appriciate if you could look at it and give me some clues about why its not printing.
This is my code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
char cipher (string plaintext, int x);
int main (int argc, string argv [])
{
//here is part for validation
//GET STRING
//CRYPT
string plaintext = get_string ("plaintext: ");
for(int i= 0; i < strlen(plaintext); i++)
{
int ci = 0;
int ch = 65;
if (isupper(plaintext[i]))
{
if (x <= 26 - (plaintext[i] - ch))
{
ci = plaintext[i] + x;
printf("%c", plaintext[ci]);
}
//if the key is overflowing the letters left in alpha
else if (x > 26 - (plaintext[i] - ch))
{
ci = ((plaintext[i] + x) % 26) + 64;
printf("%c", plaintext[ci]);
}
}
}
}
The lines
printf("%c", plaintext[ci]);
are wrong. ci here is already the character code to print, so they should be
printf("%c", ci);
or more simply
putchar(ci);

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