C, How to use exit code properly? - c

When I try to submit my work, the system told me to use the exit code. When I use return 0 and recheck, the system told me to use return 1...
(https://i.stack.imgur.com/dnVLV.png)
:) caesar.c exists.
:) caesar.c compiles.
:( encrypts "a" as "b" using 1 as key
expected "ciphertext: b\...", not "ciphertext: b"
:( encrypts "barfoo" as "yxocll" using 23 as key
expected "ciphertext: yx...", not "ciphertext: yx..."
:( encrypts "BARFOO" as "EDUIRR" using 3 as key
expected "ciphertext: ED...", not "ciphertext: ED..."
:( encrypts "BaRFoo" as "FeVJss" using 4 as key
expected "ciphertext: Fe...", not "ciphertext: Fe..."
:( encrypts "barfoo" as "onesbb" using 65 as key
expected "ciphertext: on...", not "ciphertext: on..."
:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
expected "ciphertext: ia...", not "ciphertext: is..."
:( handle lack of argv[1]
expected exit code 1, not 0
:( handles non-numeric key
timed out while waiting for program to exit
:( handles too many arguments
expected exit code 1, not 0
How can I fix it and what's wrong with my code?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
int ok;
char r1;
if (argc == 2)
{
for (int i = 0, s = strlen(argv[1]); i < s; i++)
{
if (!isdigit(argv[1][i]))
{
printf("Sorry\n");
return 0;
}
else
{
ok = atoi(argv[1]);
string c = get_string("Enter:");
printf("ciphertext: ");
for (int t = 0, a = strlen(c); t < a; t++)
{
if (c[t] < 91 && c[t] > 64)
{
r1 = (c[t] - 64 + ok) % 26 + 64;
printf("%c", r1);
}
else if (c[t] < 123 && c[t] > 96)
{
r1 = (c[t] - 96 + ok) % 26 + 96;
printf("%c", r1);
}
else
{
printf("%c", c[t]);
}
}
return 0;
}
}
}
else
{
printf("Sorry\n");
}
printf("\n");
return 0;
}
I try to do well with my homework and all green...

There are multiple issues in your code:
you should return a non zero exit status upon error.
if the number given as a command line argument has more than 1 digit, you perform multiple iterations (one for each digit). You should move the encoding loop out of the first for loop.
using hard coded ASCII values for upper and lower case letters makes the code less portable and hard to read. You should use character constants 'A', 'Z', etc.
r1 = (c[t] - 64 + ok) % 26 + 64; is incorrect and may produce # instead of Z for some inputs. You should use r1 = (c[t] - 65 + ok) % 26 + 65; or better r1 = (c[t] - 'A' + ok) % 26 + 'A';
same mistake for r1 = (c[t] - 96 + ok) % 26 + 96;
Here is a modified version:
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "missing argument\n");
return 1;
}
char *arg = argv[1];
char *p;
int shift = (int)strtol(arg, &p, 10);
if (!(arg[0] >= '0' && arg[0] <= '9') || p == arg || *p != '\0') {
fprintf(stderr, "invalid shift argument: %s\n", arg);
return 1;
}
char *s = get_string("Enter string: ");
printf("ciphertext: ");
for (int t = 0; s[t] != '\0'; t++) {
unsigned char c = s[t];
/* assuming ASCII: upper and lowercase letters are contiguous */
if (c >= 'A' && c <= 'Z') {
c = (c - 'A' + shift) % 26 + 'A';
} else
if (c >= 'a' && c <= 'z') {
c = (c - 'a' + shift) % 26 + 'a';
}
putchar(c);
}
putchar('\n');
return 0;
}

You use the exit code by adding a return <value>, at the appropriate code line.
With <value> being what matches your interface definition, in case of your online judge it seems to be a 1.
In your code you at least fail to do so here:
else
{
printf("Sorry\n");
}
which should be
else
{
printf("Sorry\n");
return 1;
}
An alternative is the more explicit https://en.cppreference.com/w/c/program/exit for situations in which the path to the end of the program is not as obvious.
(This is mostly what the comment by Lundin mentions. I turned it into an explicit answer.)
However, to completely satisfy the judge you need to work on your output.
With the info given in the question, a solution for those problems is not possible.

Related

My CS50 caesar program works fine but it doesn't pass check50

This program is supposed to encrypt strings with the user's key. If the argument count is not 2 and the argv[1] (key) is not a positive number then it prints the usage instructions and returns 1.Else it does the rest of the program.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
//Get the key
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
for (int key = 0; key < strlen(argv[1]); key++)
{
if(isalpha(argv[1][key]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
//Convert string to int
int key = atoi(argv[1]);
//Get the plaintext
string plaintext = get_string("Plaintext: ");
//Output the ciphertext
printf("ciphertext: ");
for (int i = 0, length = strlen(plaintext); i < length; i++)
{
if(!isalpha(plaintext[i]))
{
printf("%c", plaintext[i]);
continue;
}
int offset = isupper(plaintext[i]);
for (int j = 0; plaintext[i] != '\0'; i++)
{
if (isalpha(plaintext[i]) != 0)
{
if (isupper(plaintext[i]) != 0)
{
printf("%c", ((plaintext[i] - 65 + key) % 26) + 65);
}
else
{
printf("%c", ((plaintext[i] - 97 + key) % 26) + 97);
}
}
else
{
printf("%c", plaintext[i]);
}
}
int p = plaintext[i] - offset;
int c = (p + key) % 26;
printf("%c", c + offset);
}
printf("\n");
return 0;
}
These are the check50 results:
:) caesar.c exists.
:) caesar.c compiles.
:( encrypts "a" as "b" using 1 as key
expected "ciphertext: b\...", not "ciphertext: b\..."
:( encrypts "barfoo" as "yxocll" using 23 as key
expected "ciphertext: yx...", not "ciphertext: yx..."
:( encrypts "BARFOO" as "EDUIRR" using 3 as key
output not valid ASCII text
:( encrypts "BaRFoo" as "FeVJss" using 4 as key
output not valid ASCII text
:( encrypts "barfoo" as "onesbb" using 65 as key
expected "ciphertext: on...", not "ciphertext: on..."
:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
expected "ciphertext: ia...", not "ciphertext: ia..."
:) handles lack of argv[1]
:) handles non-numeric key
:) handles too many arguments
But I can't figure out where's the problem. It literally says
-expected "ciphertext: b...", not "ciphertext: b..."
They seem completely same to me.
Edit:
I've changed 65 and 97 to 'a' and 'A'.That solved the ASCII value problem.
I also removed this line.But the problems still remain.
for (int j = 0; plaintext[i] != '\0'; i++)
I've figured out everything and it passed the check50 tests.Thank you for all the help.My solution is below the comments.
I've noticed that things get complicated after the second for loop and I removed everything
int offset = isupper(plaintext[i]);
to
printf("%c", c + offset);
And then I created a new function called mix_text and add that function with a %s in the line of printing ciphertext.This new function takes plaintext and key as its inputs and returns a string.Here's how it looks.
string mix_text(string plaintext, int key)
{
string ciphertext = plaintext;
for (int i = 0, len = strlen(plaintext); i < len; i++)
{
if (isupper(plaintext[i]))
{
ciphertext[i] = (plaintext[i] - 'A' + key) % 26 + 'A';
}
else if (islower(plaintext[i]))
{
ciphertext[i] = (plaintext[i] - 'a' + key) % 26 + 'a';
}
}
return ciphertext;

CS50 Caesar - Converting from ASCII number to character

Going through the CS50 exercise Caesar, and I'm still very new to C. My code to validate the key is all working, but as i try to convert from plaintext to the cipher text I keep getting caught up with the conversion form the ASCII number to the char. For example if I run the plaintext with the argv[1] as 27 I get /023/024. I recognize the math is off and if anyone has any pointers about that that would be great, but the main thing I'm curious about is why when I try to assign f into input[i] I get this "/000" type format.
string input = get_string("plaintext: ");
int len = strlen(input);
int i = 0;
while (input[i] != '\0')
{
int mod = atoi(argv[1]);
int t = input[i] + mod;
int f = t % 26;
input[i] = f;
i++;
}
printf("ciphertext: %s\n", input);
Your implementation of doing the %26 is wrong because when you do t % 26 you will get a letter but you have forgotten to add the ASCII value if it is a small of a larger one.
you must change your code to
Here is my code which I had used,
It is correct and hope it helps you...
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2) //checking if there are 2 arguments while calling the main method the first one here will be "./caesar" and the second will be the input given
{
printf("Wrong command\n");
return 1;
}
int k = atoi(argv[1]);//converting string input to integer
string a = argv[1];
for (int i = 0; i < strlen(a); i++)//checking if the input is a number for each character
{
if (a[i] < '0' || a[i] > '9')
{
printf("False\n");
return 1;
}
}
if (k < 0)
{
printf("Wrong command\n");
return 1;
}
else
{
//if everything is successful we ask for the plaintext
string code = get_string("plaintext: ");
//we just print 'ciphertext' and not the 'ciphered text'
printf("ciphertext: ");
for (int i = 0, n = strlen(code); i < n; i++)
{
if (islower(code[i]))
{
printf("%c", (((code[i] + k) - 97) % 26) + 97);
}
else if (isupper(code[i]))
{
printf("%c", (((code[i] + k) - 65) % 26) + 65);
}
else
{
printf("%c", code[i]);
}
}
printf("\n");
return 0;
}
}
Your mistake is that, you are not checking if it is an upper case or lower case and you are not subtracting 97 or 65 before doing the modulus...
If any other doubts, you are free to ask.
Here is the result after running check50 for the 2021 version
:) caesar.c exists.
:) caesar.c compiles.
:) encrypts "a" as "b" using 1 as key
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
:) encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
:) handles lack of argv[1]
All successful

How can I exclude non-numeric keys? CS50 Caesar Pset2

I'm doing the CS50 Caesar problem and for the most part, my code works. I am not able to pass one of the check50 tests - my code does not handle non-numeric keys, and it timed out while waiting for the program to exit.
I have tried utilizing isdigit but it does not seem to work.
The check50 tests results copied pasted below:
:) caesar.c exists.
:) caesar.c compiles.
:) encrypts "a" as "b" using 1 as key
:) encrypts "barfoo" as "yxocll" using 23 as key
:) encrypts "BARFOO" as "EDUIRR" using 3 as key
:) encrypts "BaRFoo" as "FeVJss" using 4 as key
:) encrypts "barfoo" as "onesbb" using 65 as key
:) encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
:) handles lack of key
:( handles non-numeric key
timed out while waiting for program to exit
:) handles too many arguments
#include <stdio.h>
#include <cs50.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
if (argc == 2 && (isdigit(argv[1] !=0))
{
int k = atoi (argv[1]); // convert string to int
string s = get_string ("plaintext: "); // obtain text
printf("ciphertext: ");
for (int i = 0; i < strlen(s); i++) // text loop
{
if (s[i] >= 'a' && s[i] <= 'z')
{
printf("%c", 'a' + ((s[i] - 'a') + k) % 26);
}
else if (s[i] >= 'A' && s[i] <= 'Z')
{
printf("%c", 'A' + ((s[i] - 'A') + k) % 26);
}
else
{
printf("%c", s[i]);
}
}
printf("\n");
return 0;
}
else
{
printf("./caesar key\n");
}
return 1;
}
I guess that the timing out is happening because your program is waiting for plaintext while the judge is not giving that because it excepts your program to exit right after giving non-numeric key.
You can use strtol(), which accepts a pointer to pointer to character and saves position of first invalid character.
Then, you can check if the input is numeric by checking if the returned pointer is pointing at the terminating null charcter.
char* p;
int k = (int)strtol (argv[1], &p, 10);
if (*p != '\0') {
puts("non-numeric key");
return 1;
}
Just loop through every digit of argv[1] and check if it's an integer.
for (int i = 0; i < strlen(argv[1]); i++)
{
if (isdigit(argv[1][i]) == 0)
{
return 1;
}
}

CS50 - pset2 - substitution

I can't see what my code for pset2 substitution is missing. When I use check50 to test the program it returns this result:
:) substitution.c exists
:) substitution.c compiles
:( encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
expected "ciphertext: Z...", not "ciphertext: Z..."
:( encrypts "a" as "z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
expected "ciphertext: z...", not "ciphertext: z..."
:( encrypts "ABC" as "NJQ" using NJQSUYBRXMOPFTHZVAWCGILKED as key
expected "ciphertext: NJ...", not "ciphertext: NJ..."
:( encrypts "XyZ" as "KeD" using NJQSUYBRXMOPFTHZVAWCGILKED as key
expected "ciphertext: Ke...", not "ciphertext: Ke..."
:( encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZTEOGXHCIPJSQD as key
expected "ciphertext: Cb...", not "ciphertext: Cb..."
:( encrypts "This is CS50" as "Cbah ah KH50" using yukfrnlbavmwzteogxhcipjsqd as key
expected "ciphertext: Cb...", not "ciphertext: Cb..."
:( encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZteogxhcipjsqd as key
expected "ciphertext: Cb...", not "ciphertext: Cb..."
:( encrypts all alphabetic characters using DWUSXNPQKEGCZFJBTLYROHIAVM as key
expected "ciphertext: Rq...", not "ciphertext: Rq..."
:) handles lack of key
:) handles invalid key length
:) handles invalid characters in key
:) handles duplicate characters in key
:) handles multiple duplicate characters in key
However, when I manually type in a key and plaintext it works exactly as it is supposed to. Furthermore, the 'expected' result of check50 seems to be exactly the same as the output so it is not obvious what is wrong.
my code is as follows:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int get_validkey(string A);
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("useage: ./substitution key\n");
return 1;
}
int validation = get_validkey(argv[1]);
if (validation == 1)
{
printf("key must contain 26 alphabetical characters\n");
return 1;
}
// prompting user for plaintext
string plaintext = get_string("plaintext: ");
printf("ciphertext: ");
int length = strlen(plaintext);
for (int c = 0; c <= length ; c++)
{
// printing any non-alphabet characters unchanged
if (plaintext[c] < 'A' || (plaintext[c] > 'Z' && plaintext[c] < 'a') || plaintext[c] > 'z')
{
printf("%c", plaintext[c]);
}
else
{
for (int b = 0; b <= 25; b++)
{
if (plaintext[c] == 65 + b)
{
char upper = argv[1][b];
int up = isupper(upper);
if (up == 0)
{
upper = toupper(upper);
printf("%c", upper);
}
if (up != 0)
{
printf("%c", upper);
}
}
else if (plaintext[c] == 97 + b)
{
char lower = argv[1][b];
int low = islower(lower);
if (low == 0)
{
lower = tolower(lower);
printf("%c", lower);
}
if (low != 0)
{
printf("%c", lower);
}
}
}
}
}
printf("\n");
return 0;
}
// function assesses if the key input is valid and returns 0 if it is and 1 if it is not
int get_validkey(string A)
{
int inputlength = strlen(A);
if (inputlength != 26)
{
return 1;
}
else
{
for (int g = 0; g < 26; g++)
{
// checks if the character is non alphabetical
if (A[g] < 'A' || (A[g] > 'Z' && A[g] < 'a') || A[g] > 'z')
{
return 1;
}
// scans all characters before A[g] to see if it has already been used
for (int k = (g - 1); k >= 0; k--)
{
if (A[k] == A[g])
{
return 1;
}
// also checks if different case of the same character has been used
if (A[k] == A[g] + 32)
{
return 1;
}
if (A[k] == A[g] - 32)
{
return 1;
}
}
// scans all characters after A[g] to check if it has been used already. (Not sure if this is necessary)
for (int l = (g + 1); l < 26; l++)
{
if (A[l] == A[g])
{
return 1;
}
// also checks if a different case of the same letter is used
if (A[l] == A[g] + 32)
{
return 1;
}
if (A[l] == A[g] - 32)
{
return 1;
}
}
}
return 0;
}
}
I am very new to programming and any help would be greatly appreciated.
I've encountered the same problem, but then I realized that when I was iterating the for loop for my plain text which is, for (int c = 0; c <= length ; c++), that the programming language itself internally starts with 0 when counting. Even though we knew it should be equal to the length of the plain text, the language will iterate to that null element within the array of string. I suggest you do this, for (int c = 0; c <= length ; c++). Hope, it helps.

Vigenere Cipher logic error

#include<stdio.h>
#include<cs50.h>
#include<ctype.h>
#include<string.h>
int main(int argc, string argv[]){
int k,j,i=0,ch,pos;
bool apha=true;
string in = GetString();
int num = strlen(in);
for(int z=0;z<strlen(argv[1]);z++){
if(!isalpha(argv[1][z])){
apha=false;
}
}
if(argc!=2||!apha){
printf("Dude we only accept alphabets...");
return 1;
}
string key = argv[1];
int keylength = strlen(key);
for (i=0,j=0;i<num;i++,j++){
if(isupper(key[i])){
k=key[j%keylength]-'A';
}
if(islower(key[i])){
k=key[j%keylength]-'a';
}
if(isupper(in[i])){
pos=in[i]-'A';
ch = ((pos + k)%26) + 'A';
printf("%c",ch);
}
if(islower(in[i])){
pos=in[i]-'a';
ch = ((pos + k)%26) + 'a';
printf("%c",ch);
}
if(isspace(in[i])){
printf(" ");
}
if(ispunct(in[i])){
printf("%c",in[i]);
}
}
printf("\n");
}
Output condition checks:
:) vigenere.c exists
:) vigenere.c compiles
:) encrypts "a" as "a" using "a" as keyword
:( encrypts "world, say hello!" as "xoqmd, rby gflkp!" using "baz" as keyword
\ expected output, but not "xoqkj, yfd gfllp!\n"
:( encrypts "BaRFoo" as "CaQGon" using "BaZ" as keyword
\ expected output, but not "CaQEun\n"
:( encrypts "BARFOO" as "CAQGON" using "BAZ" as keyword
\ expected output, but not "CAQEON\n"
:( handles lack of argv[1]
\ expected output, not a prompt for input
:( handles argc > 2
\ expected output, not a prompt for input
:( rejects "Hax0r2" as keyword
\ expected output, not a prompt for input
What is wrong with my code? I have scrutinized the logic and the error seems to be in the way the key has been wrapped, though I could not find any errors. Where have I gone wrong?
There are several problems with your code:
You're error checking isn't correct. You check if(argc!=2||!apha) after you've already evaluated strlen(argv[1]) -- by then it's too late! Check the validity of argc before accessing argv and don't double up the argument count error and alphabetic key error, they're independent. Also, error messages should go to stderr, not stdout.
You're completely mishandling the key indexing. As #Bob__ noted, the indexing in this code:
if(isupper(key[i])){
k=key[j%keylength]-'A';
}
needs to be consistent
if (isupper(key[j % keylength])) {
k = key[j % keylength] - 'A';
}
But also, you're not incrementing j correctly, you have it tracking i:
for (i=0,j=0;i<num;i++,j++){
Instead, i should increment for every character in the input string, j should increment for every encryptable letter in the input string.
Reworking your code to fix the above errors and general style issues, we get something like:
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
int main(int argc, string argv[]) {
if (argc != 2) {
fprintf(stderr, "Please supply an encryption key.\n");
return 1;
}
string key = argv[1];
int key_length = strlen(key);
bool is_alpha = true;
for (int z = 0; z < key_length; z++) {
if (!isalpha(key[z])) {
is_alpha = false;
}
}
if (!is_alpha) {
fprintf(stderr, "Sorry, we only accept alphabetic keys.\n");
return 1;
}
string in = GetString();
size_t length = strlen(in);
for (int i = 0, j = 0; i < length; i++) {
if (isalpha(in[i])) {
int ch, k = key[j++ % key_length];
if (isupper(k)) {
k -= 'A';
} else {
k -= 'a';
}
if (isupper(in[i])) {
int pos = in[i] - 'A';
ch = ((pos + k) % 26) + 'A';
} else {
int pos = in[i] - 'a';
ch = ((pos + k) % 26) + 'a';
}
printf("%c", ch);
} else if (isspace(in[i])) {
printf(" ");
} else if (ispunct(in[i])) {
printf("%c", in[i]);
}
}
printf("\n");
return 0;
}
USAGE SIMULATION
> ./a.out baz
world, say hello!
xoqmd, rby gflkp!
>
Here is the answer as I got it-
-The most striking error is probably the:
if(isupper(key[i])){
k=key[j%keylength]-'A';
}
It should check for the corresponding character so should check for:
if (isupper(key[j % keylength])) {
k = key[j % keylength] - 'A';
}
-Also, the increment of the key-increment is important, to do that just increment only if it is an alphabet. So an isalpha check for that is needed (as you don't want the character to change even for a space).

Resources