isdigit function is not catching mixed values in argv[] - c

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// check for correct 1 integer argument else print instructions
if (argc == 2 && isdigit(*argv[1]))
{
printf("plaintext: ");
printf("rawtext: ");
return 0;
}
else
{
printf("Usage: [KEY]\n");
return 1;
}
}
The program should print "Usage: [KEY]" if the user enters ./program 2z but isdigit is not catching "z". Is there a way to correct this or is there any other alternative to isdigit function?

You need to call isdigit() in a loop, testing each character, since it only checks one character at a time.
if (argc == 2 && argv[1][0]) {
for (int i = 0; argv[1][i]; i++) {
if (!isdigit(argv[1][i]) {
printf("Error: key must be numeric\n");
return 1;
}
}
printf("plaintext: ");
printf("rawtext: ");
return 0;
} else {
printf("Usage: %s key\n", argv[0]);
return 1;
}

Related

C, Why there is a Segmentation fault (core dumped)

#include <cs50.h>
#include <stdio.h>
#include<ctype.h>
int main(int argc, string argv[])
{
int KEY;
if(isdigit(argv[1]))
{
KEY = (int)argv[1];
}
else
{
printf("Usage: ./caesar key");
}
printf("\n");
printf("%i\n",argc);
}
I can't find out the problem when I type the following
How do I fix it?
This is not a high-level language with various syntax sugar features.
Important Notes:
Conversion of const char * to int is not done by just type-casting it.
isdigit() works only for int (single characters), not const char * it will cause Undefined Behavior.
argc is the length of pointer array argv
string is not a valid type for main() function arguments, it should be int main(int argc, char const **argv) { }
Must check whether argv[1] even exists or not
Once you print the usage your program should exit
Any error message should be printed on stderr
Must Use return EXIT_SUCCESS;, which is defined in the header file stdlib.h, when exiting the application, or use return EXIT_FAILURE; if something goes wrong.
Final Code
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char const **argv)
{
if(argc == 1)
{
fprintf(stderr, "Usage: %s <KEY>", argv[0]);
return EXIT_FAILURE;
}
for(size_t i = 0; argv[1][i]; i++)
{
if(!isdigit(argv[1][i]))
{
fprintf(stderr, "expected only integer value\n");
return EXIT_FAILURE;
}
}
// we don't need to check whether `argv[1]` is all digit or not at this point
int KEY = strtod(argv[1], NULL);
printf("argc = %d\n", argc);
printf("KEY = %d\n", KEY);
return EXIT_SUCCESS;
}

Why is my loop stopping at the first argument (char of argv) in C?

I can't understand why my code is stopping at the first char of the command-line arguments.
I think the problem is in the loop, I need it to check if the command-line argument is a digit, so the first and second parts aren't important.
Thank you and sorry for the messy, I am new to this.
int main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
else
{
// checking if command-line argument is a number
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
printf("%c\n", argv[1][i]);
if (isdigit(argv[1][i]))
{
return 0;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
}
}
}
You're doing a return in the valid case, so you're only checking the first char of argv[1].
You want to not terminate the loop in the valid case, accumulating the value.
Here's some refactored code:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// so we don't have to include cs50.h ...
typedef char *string;
int
main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2) {
printf("Usage: ./caesar key\n");
return 1;
}
// checking if command-line argument is a number
int keyval = 0;
for (char *cp = argv[1]; *cp != 0; ++cp) {
if (! isdigit(*cp)) {
printf("Usage: ./caesar key\n");
return 1;
}
// accumulate the number as we go along, digit-by-digit
keyval *= 10;
keyval += (*cp - '0');
}
printf("keyval=%d\n",keyval);
return 0;
}
Here's an alternate way:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// so we don't have to include cs50.h ...
typedef char *string;
int
main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2) {
printf("Usage: ./caesar key\n");
return 1;
}
// checking if command-line argument is a number
for (char *cp = argv[1]; *cp != 0; ++cp) {
if (! isdigit(*cp)) {
printf("Usage: ./caesar key\n");
return 1;
}
}
// we can use a standard function to get the value
int keyval = atoi(argv[1]);
printf("keyval=%d\n",keyval);
return 0;
}
Here's another way:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// so we don't have to include cs50.h ...
typedef char *string;
int
main(int argc, string argv[])
{
// checking if there is more than one command-line argument
if (argc != 2) {
printf("Usage: ./caesar key\n");
return 1;
}
// checking if command-line argument is a number
char *cp;
int keyval = strtol(argv[1],&cp,10);
// invalid digit found
if (*cp != 0) {
printf("Usage: ./caesar key\n");
return 1;
}
printf("keyval=%d\n",keyval);
return 0;
}
Note that strtol will accept a negative value (e.g. -37) as valid. So, if negative values are not acceptable, we'd need an additional check [just before the valid printf]:
// negative value found
if (keyval < 0) {
printf("Usage: ./caesar key\n");
return 1;
}

Can anyone tell me why im getting a Segmentation Fault (cs50 substitution)

In my program I get the errors that I controlled, but when I try to avoid those preset errors and enter what I want the user to enter, it returns a segmentation fault.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
string key = argv[1];
if (argc < 2 || argc > 2)
{
printf("Usage: ./substitution key\n");
exit(1);
}
if (argc == 2 && strlen(key) < 26)
{
printf("Key must contain 26 characters.\n");
exit(1);
}
if (strlen(key) > 26)
{
printf("Key must contain 26 characters.\n");
exit(1);
}
for (int i = 0; i < 26; i++)
{
if (isalpha(key) == 0)
{
printf("MAKE SURE YOUR KEY ONLY HAS LETTERS\n");
}
}
printf("test");
}
#Retired Ninja is spot on. isalpha on key was causing the segmentation. Here is a slightly optimized way of the code.
#include <stdio.h>
#include "cs50.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./substitution key\n");
exit(1);
}
string key = argv[1];
int keylen = strlen(key);
if (keylen != 26)
{
printf("Key must contain 26 characters.\n");
exit(1);
}
for (int i = 0; i < 26; i++)
{
unsigned char const c = key[i];
if (!isalpha(c))
printf("MAKE SURE YOUR KEY ONLY HAS LETTERS\n");
}
printf("test\n");
}

how to iterate through argv through command line and C

#include <stdio.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: one file only", argv[0]);
return (1);
} else {
for(int i = 0; i < argc; i++) {
putchar(argv[i]);
}
}
}
Say I want to print the input it takes in, for instance
$ gcc -Wall fileabove.c
$ ./a.out abcdefghijlmn
abcdefghijlmn
Basically just prints out whatever text I put into it.
putchar(argv[i]);
is incorrect, because putchar expects a single character (type char), you are passing a pointer (char*). It should be
puts(argv[i]);
So the correct code:
#include <stdio.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: one file only\n", argv[0]);
return 1;
}
// no need for the else
// you exit program anyway if argc != 2
// makes code more readable
puts(argv[1]);
return 0;
}
If you want to print character by character:
#include <stdio.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: one file only\n", argv[0]);
return (1);
}
for(size_t i = 0; argv[1][i] != '\0'; ++i)
putchar(argv[1][i]);
putchar('\n');
return 0;
}
edit changed puts("") to putchar('\n') and removed strlen as Jonathan Leffler mentioned in the comments.
The argument array is always in the format of first index being the called program name and the subsequent index values being the parameters in order. Because you only want one argument to process, I have simplified your code as follows:
#include <stdio.h>
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "%s usage: one file only\n", argv[0]);
return 1;
} else {
printf("%s\n",argv[1]); //print only parameter and new line
}
return 0;
}
When the user doesn't specify one parameter, then the error pops up including the program name. When the parameter is specified, it is stored in the second index of the array (index 1) and in my code, I simply printed it out using printf.

Using argc and argv in Caesar cipher in C

So, I am trying to use argc and argv in Caesars cipher in order to execute the program with just [./ key ;string] (e.g. ./ 13 Caesar). I have tried in lots of ways, although I must admit I am really lost here. I was thinking I should just use main(void) and ask the input with fgets, but I still have some curiosity in: How could I make it work with “int main(int argc, char *argv[])?”. Any clues you can give me?
Thank you for your help. Here is the code with the current outputs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int key;
int result;
char str[60];
int k = 0;
printf("argc =%d\n", argc);
printf("argv =%d\n", argv);
printf("key =%d\n", key);
if (argc != 2)
{
printf("You didn't enter a key.\n");
return 1;
}
else
{
int k = key % 26;
printf("k =%d\n", k);
if (k == 0)
{
printf("Invalid key.\n");
return 1;
}
}
}
Output:
$ ./ceasar 13
argc =2
argv =-13216
key =0
k =0
Invalid key.
Edit: Tentative Answer
int main(int argc, char* argv[])
{
int i;
int key = atoi(argv[1]);
int result;
char str[60];
for (i = 0; i < argc; i++)
{
printf("argv[%d] = %s\n", i, argv[i]);
}
if (argc != 2)
{
printf("You didn't enter a key.\n");
return 1;
}
else
{
if (key == 0)
{
printf("Invalid key.\n");
return 1;
}
}
}
Printing argv with the "%d" specifier is undefined behavior, read printf()'s manual and use "%p".
On the other hand, if you want to print the string you should access the appropriate element with array notation. For example
printf("First Argument: %s\n", argv[1]);
this applies to all arguments, noting that argv[0] is the name of the executable as invoked in the command line.
You should also be careful before accessing argv[1] to check that argc > 2, and always check the current argument + !.

Resources