i'm new to CS and have been tackling cs50. its been a great experience so far as I was a math major and most of the concepts and assignments have been clicking really well.
i know part of the learning process is to solve your bugs yourself, but after a few hours staring at the one line that i narrowed down is causing the segmentation fault, I'm getting pretty frustrated.
I've attached my code below. i spent an hour watching a tutorial on pointers but still can't narrow down why I can pass in argv[1] to my function validateKey() but can't access the memory when i try to use it.
I saw experienced programmers stating that its crucial to be able to identify where exactly the segmentation fault is arising, so after debugging I noticed anytime in the program I try to access argv[1] (whether in main or local), that memory access is restricted
greatly appreciate your time and support!
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
int findIndex(char keyVal);
void cipherText(string s, string key);
bool validateKey(string s);
string alphabet = "abcdefghijklmnopqrstuvwxyz";
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage ./substitution key\n");
return (1);
}
int length = strlen(argv[1]);
if (length != 26)
{
printf("Key must contain 26 characters\n");
return (1);
}
else
{
if (validateKey(argv[1])) //allows to pass argv[1]
{
string userText = get_string("plaintext: ");
cipherText(userText, argv[1]); //allows to pass
printf("\n");
return (0);
}
else
{
printf("Usage ./substitution key\n");
return (1);
}
}
}
bool validateKey(string s)
{
int n = strlen(s);
int hash[n][1];
for (int i = 0; i < n; i++)
{
int b;
if (isdigit(s[i]))
{
return false;
}
b = s[i];
if (hash[b][0] == 1)
{
return false;
}
else hash[b][0] = 1;
}
return true;
}
int findIndex(char keyVal)
{
for (int i = 0; i < 26; i++)
{
if (alphabet[i] == tolower(keyVal) || alphabet[i] == toupper(keyVal))
{
return i;
break;
}
}
return -1;
}
void cipherText(string s, string key)
{
printf("ciphertext: ");
for (int i = 0, n = strlen(s); i < n; i++)
{
if (!(isalnum(s[i])) || isdigit(s[i]))
{
printf("%c", s[i]);
continue;
}
int index = findIndex(s[i]);
if (index < 0) break;
if (isupper(s[i]))
{
printf("%c", toupper(key[index])); //SEGMENTATIONF
continue;
}
else if (islower(s[i]))
{
printf("%c", tolower(key[index]));
}
else printf("%c", s[i]);
}
}
Related
I'm learning CS50x course. And the homework of problem set 2 is Caesar's algorithm.
I made it to work normally. But there's one thing make me confused:
the bool only_digits function - it requires a final return true to work normally. I searched on Google and people said there has to be a default return value, okay, I understand.
But when I switched it from TRUE to FALSE, the program just treated all the command-line arguments as FALSE. Therefore the program couldnt work.
I'm new to algorithm and programming. Please help me understand this part.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
bool only_digits(string s);
char rotate(char c, int n);
int main(int argc, string argv[])
{
// Make sure program was run with just one command-line argument
// Also make sure every character in argv[1] is a digit
if (argc < 2 || argc >2 || only_digits(argv[1]) == false)
{
printf("Usage: ./caesar key\n");
return 1;
}
// Convert argument to int
int x = atoi(argv[1]);
// Prompt the user
string plaintext = get_string("plaintext: ");
// Encrypt the plaintext
printf("ciphertext: ");
for (int i = 0, len = strlen(plaintext); i < len; i++)
{
char cipher = rotate(plaintext[i], x);
printf("%c", cipher);
}
printf("\n");
}
// Function check if only digit
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (isdigit(s[i]))
{
while(s[i] == '\0')
return true;
}
else
{
return false;
}
}
return true; /* This part, I dont understand why */
}
// Function rotate
char rotate(char c, int n)
{
if (isalpha(c))
{
if (isupper(c))
{
c = 'A' + (c - 'A' + n) % 26;
return c;
}
else c = 'a' + ((c - 'a' + n) % 26);
return c;
}
else return c;
}
So I'll talk here about a single function, the one with the return true :
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (isdigit(s[i]))
{
while(s[i] == '\0')
return true;
}
else
{
return false;
}
}
return true; /* This part, I dont understand why */
}
So you ask if (isdigit(s[i]) and then you start a while loop that terminates as soon as s[i] != '\0' which is already true as soon as you enter the if-body.
What you'd like to do is to check if there are any non-digits in your string.
Something like
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (!isdigit(s[i]))
return false;
}
return true; /* if we didn't find a non-digit, we're fine */
}
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.
I have created a bit of code, that can check an input text for double characters. I got to work if I had all my code inside my main function, but have some trouble when I want to create an extra function. The error I am getting is the following: "error: control may reach end of non-void function", which I have identified to that the system cannot identify a return value from my count_double_characters function.
Can you help me understand what I am doing wrong?
#include <stdio.h>
#include <string.h>
int count_double_characters(char *ch);
int main(void)
{
char input[400];
printf("Write the text you want to check: ");
fgets(input, sizeof(input), stdin);
count_double_characters(input);
}
int count_double_characters(char *ch)
{
char n = strlen(ch);
int count_double = 0;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (ch[i] == ch[j])
{
count_double++;
}
}
}
if (count_double > 0)
{
char s = printf("Its a double!\n");
return s;
}
else if (count_double == 0)
{
char d = printf("Looks good\n");
return d;
}
}
Consider this section of your code:
if (count_double > 0)
{
char s = printf("Its a double!\n");
return s;
}
else if (count_double == 0)
{
char d = printf("Looks good\n");
return d;
}
// if count_double is less than 0, the program goes here
// but there is non return statement, meaning that the function
// does not return any value.
// That what's the error message is telling you
}
Now you will tell me that count_double can never be 0, which is correct, but apparently the compiler is not smart enough to detect this.
To correct, you can simply drop the if (count_double == 0) or replace it with if (count_double <= 0).
I am new here and working on the second homework Caesar of cs50, it seems most of my review is correct except the last one -- I cannot handle the situation of lacking argv[1], which means if I only type ./caesar, it will return segmentation fault. I am wondering why this code if (argc != 2) cannot return 0 when argc == 1, however it works when argc > 1, I find that is weird. Can anyone help me?? Thanks in advance!
# include <stdio.h>
# include <cs50.h>
# include <string.h>
# include <ctype.h>
# include <math.h>
# include <stdlib.h>
int check_the_key(int argc, string y);
int main(int argc, string argv[])
{
string x = argv[1];
int y = argc;
int k = check_the_key(y, x);
if (k == 0)
{
printf("ERROR!!!!!\n");
return 1;
}
else
{
// printf("The key is %i\n", k);
string text = get_string("Input your text:");
int i;
int n;
printf("ciphertext: ");
for (i = 0, n = strlen(text); i < n; i++)
{
if (islower(text[i]))
{
printf("%c", (text[i] - 97 + k) % 26 + 97 );
}
else if (isupper(text[i]))
{
printf("%c", (text[i] - 65 + k) % 26 + 65);
}
else
{
printf("%c", text[i]);
}
}
printf("\n");
return 0;
}
}
int check_the_key(int argc, string y)
{
int number = argc;
string key = y;
int numberkey = atoi(key);
if (argc != 2)
{
return 0;
}
else
{
if (numberkey > 0)
{
return numberkey;
}
else
{
return 0;
}
}
}
I know what is going on! Because I need to pass some value into atoi(), if I only call ./caesar, there is no value I can pass into atoi(), so it causes segmentation fault. Which means I need to change code order slightly, put int numberkey = atoi(key); inside the else loop. So the code will run if (argc != 2) first, if no, then go to the next step! Here is the code after change.
int check_the_key(int argc, string y)
{
int number = argc;
string key = y;
if (argc != 2)
{
return 0;
}
else
{
int numberkey = atoi(key);
if (numberkey > 0)
{
return numberkey;
}
else
{
return 0;
}
}
}
I've been working on cs50 pset2, and I thought I had the vigenere cipher down after working on it for a few days. This code is meant to take an alphabetical argument(argv[]) given by the user, and use that as a key to crypt a phrase given by the user(string) by its number in the alphabetical index. For example, if you give the argument 'abc' and the string 'cat' then the output should be 'cbv'(a moving 0, b moving 1, c moving 2) The argument should also wrap around so that if the string is longer, the argument will wrap to its first character and continue until the string has ended.
This is what I have for code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if(argc != 2)
{
printf("Try again\n");
return 1;
}
string k = (argv[1]);
int klen = strlen(k);
for(int x = 0; x < klen; x++)
{
if(isalpha(k[x]))
{
if(isupper(k[x]))
{
k[x] = tolower(k[x]);
}
k[x] -= 'a';
}
else
{
printf("Try again\n");
return 1;
}
}
string code = GetString();
int clen = strlen(code);
for(int a = 0, b = 0; a < clen; a++)
{
if(isalpha(code[a]))
{
int key = k[b%klen];
if(isupper(code[a]))
{
printf("%c", (((code[a] - 'A') + key)%26) + 'A');
b++;
}
else
{
printf("%c", (((code[a] - 'a') + key)%26) + 'a');
b++;
}
}
else
{
printf("%c", code[a]);
}
}
printf("\n");
}
The code seems to work for the length of the key +1.
For example,
I input an argument of 'aaaa'
Then input a string of 'bbbbb'
and receive 'bbbbb' correctly.
However, if I input the same 'aaaa'
Then input a string longer than the key +1 'bbbbbbb'
I receive 'bbbbbNN'
I believe I have an issue with my order of operations but have tried moving parenthesis around to no avail. I was hoping someone could point me in the right direction as to why my key isn't wrapping properly.
Your biggest risk with code like this is all the similar, repetitive clauses. A bug in just one is hard to track done. And doing any processing on the key, while processing the code, is just inefficient.
Here's a rework that completely processes the key before processing the code and tries to get the processing down to just one case. See if it works any better for you:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
fprintf(stderr, "Try again\n");
return EXIT_FAILURE;
}
string key = strdup(argv[1]);
size_t key_length = strlen(key);
for (int x = 0; x < key_length; x++)
{
if (isalpha(key[x]))
{
if (isupper(key[x]))
{
key[x] = tolower(key[x]);
}
key[x] -= 'a';
}
else
{
fprintf(stderr, "Try again\n");
return EXIT_FAILURE;
}
}
string code = GetString();
int code_length = strlen(code);
for (int a = 0, b = 0; a < code_length; a++)
{
if (isalpha(code[a]))
{
int start = isupper(code[a]) ? 'A' : 'a';
printf("%c", (((code[a] - start) + key[b++ % key_length]) % 26) + start);
}
else
{
printf("%c", code[a]);
}
}
printf("\n");
free(key);
return EXIT_SUCCESS;
}