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;
}
}
}
Related
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
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.
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]);
}
}
I'm trying to figure out why my code is not iterating correctly on z. I would like to iterate every 1 z, but it seems like it's a bit random. Does anyone have any suggestions on how I might do this? If there anything else I'm doing wrong, please let me know. I think I'm really close. I'm also curious how I block spaces/other characters from being encrypted.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int shift(char c);
int main(int argc, string argv[])
{
// Check to see if two arguments are enterted at launch
int cipher = 0;
if (argc != 2)
{
// If not return error & return 0
printf("Usage: ./vigenere keyword \n");
return 1;
}
else
{
int strlength = strlen(argv[1]);
// Iterates through characters in second argument (key), checking to see
if they are digits
for (int k = 0; k < strlength; k++)
{
if (isdigit(argv[1][k]))
{
// If not return error & return 1
printf("Usage: ./vigenere keyword\n");
return 2;
}
}
//char *c =argv[1];
string plaintext = get_string("Plaintext: ");
int len = (int) strlen(plaintext);
//int b = atoi(c);
//char code[len];
//strcpy (code, plaintext);
int z=0;
for (int j = 0; j < len; j++)
{
int key = shift(argv[1][z]);
//printf("%i",z);
if (isupper(argv[1][z]))
{
//printf("theory\n");
cipher = ((((plaintext[j] - 'A') + key) + 'A'));
//cipher = ((((plaintext[j] - 'A') + key) % 26) + 'A');
//printf("%c", (((plaintext[j] - 'A') + key) % 26) + 'A');
//printf("%i",z);
printf("%c",cipher);
}
if (islower(argv[1][z]))
{
//printf("theory\n");
cipher = (((plaintext[j] - 'a') + key) + 'a');
//printf("%i",z);
printf("%c",cipher);
}
//z++;
//else if (!isalpha(plaintext[j]))
//{
//printf("%c", plaintext[j]);
//}
if (z > strlen(argv[1])-1)
{
z=0;
}
/* else
{
z++;
}
else
{
z++;
}
*/
//z++;
}
printf("\n");
}
}
int shift(char c)
{
int i = c;
if (i <= 'Z' && i >= 'A')
{
return ((i - 'A') % 26);
}
else
{
return ((i - 'a') % 26);
}
}
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;
}