Reputation: 33
I'm a little stuck on part of a CS50 encryption exercise where we have to implement a program that encrypts messages using Caesar’s cipher, in language C.
Specifically this part: "Modify caesar.c such that instead of printing out the command-line argument provided, your program instead checks to make sure that each character of that command line argument is a decimal digit (i.e., 0, 1, 2, etc.) and, if any of them are not, terminates after printing the message Usage: ./caesar key."
My code as follows:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
int main (int argc, string argv[])
{
//checks if the user provides exactly one command-line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
printf("success\n");
}
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
// check if any of the characters of the command-line argument is not a decimal digit
if (isdigit(argv[1][i]))
{
printf("success\n");
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
As you can see the first part works (checking for one command line argument), but when I enter a string of decimal digits as that argument, like 123c or 1c23 it still prints success.
Obviously that's because the loop checks if the first char in the string is a digit and if so immediately prints success. Hence I want to find a simple way in my code to check each character of the argument is a digit and only then print success or Usage: ./caesar key.
Thanks for any help, please let me know if more background info of the problem set is needed.
Upvotes: 1
Views: 1709
Reputation: 32586
doing
for (int i = 0, n = strlen(argv[1]); i < n; i++) { // check if any of the characters of the command-line argument is not a decimal digit if (isdigit(argv[1][i])) { printf("success\n"); return 0; } else { printf("Usage: ./caesar key\n"); return 1; } }
you only consider the first character of argv[1]
because you return in both branch of the if
you can do
for (int i = 0; argv[1][i]; i++)
{
// check if any of the characters of the command-line argument is not a decimal digit
if (!isdigit((unsigned char) argv[1][i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
printf("success\n");
return 0;
but an empty argument is considered accepted and very probably you also want to get the number so rather than to loop as you do you can use strtol
or scanf
to both get the number and check you have a number, so for instance :
#include <stdio.h>
int main(int argc, char ** argv)
{
//checks if the user provides exactly one command-line argument
if (argc != 2)
{
printf("Usage: %s key\n", *argv);
return 1;
}
int key;
char c;
// check argv[1] is only a number
if (sscanf(argv[1], "%d %c", &key, &c) != 1)
{
printf("'%s' is not a valid key\n", argv[1]);
return 1;
}
printf("valid key %d\n", key);
return 0;
}
Compilation and executions :
pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ ./a.out
Usage: ./a.out key
pi@raspberrypi:/tmp $ ./a.out aze
'aze' is not a valid key
pi@raspberrypi:/tmp $ ./a.out 1a
'1a' is not a valid key
pi@raspberrypi:/tmp $ ./a.out a1
'a1' is not a valid key
pi@raspberrypi:/tmp $ ./a.out 1
valid key 1
pi@raspberrypi:/tmp $ ./a.out 123
valid key 123
pi@raspberrypi:/tmp $ ./a.out "123 "
valid key 123
pi@raspberrypi:/tmp $ ./a.out "123 a"
'123 a' is not a valid key
pi@raspberrypi:/tmp $ ./a.out " 123 "
valid key 123
pi@raspberrypi:/tmp $ ./a.out " "
' ' is not a valid key
pi@raspberrypi:/tmp $ ./a.out ""
'' is not a valid key
pi@raspberrypi:/tmp $
as you see spaces are tolerated, this is very usual reading a number
Of course if you do not want negative number do
if ((sscanf(argv[1], "%d %c", &key, &c) != 1) || (key < 0))
[edit for your remark]
For the first part even when I run if (!isdigit((unsigned char) argv[1][i])) the code still doesn't work correctly. F.e. if I run f.e. ./caesar 12p is still prints success (same problem as before).
that means you did not get all my code and probably continue to have your if
with the two branches, if I put my first proposal in a full program :
#include <stdio.h>
#include <ctype.h>
int main(int argc, char ** argv)
{
//checks if the user provides exactly one command-line argument
if (argc != 2)
{
printf("Usage: %s key\n", *argv);
return 1;
}
for (int i = 0; argv[1][i]; i++)
{
// check if any of the characters of the command-line argument is not a decimal digit
if (!isdigit((unsigned char) argv[1][i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
}
printf("success\n");
return 0;
}
Compilation and executions :
pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ ./a.out 12p
Usage: ./caesar key
pi@raspberrypi:/tmp $ ./a.out 12
success
pi@raspberrypi:/tmp $
Upvotes: 5