Possible to sanitise command line arguments in argv? [duplicate] - c

This question already has answers here:
How to check if a string is a number?
(16 answers)
Closed 2 years ago.
I'm currently learning C and I'm messing around with command line inputs from the user.
I understand that argc is the count, i.e. the amount of entered commands, and argv is an array of what was entered.
I know how to check to see if the user entered a value after the called program with argc > 1 etc, and I know that argv takes string type variables which I can convert to real integers using atoi(). However I'm not sure how to implicitly only accepts integers. I've tried using isdigit etc around argv but I usually end up with a segment error. Is there a way around this?
int main(int argc, string argv[])
{
if (argc == 2 && //code to ensure argv[1] is int)
{
//code
}
}

"...not sure how to implicitly only accepts integers."
This is not implicitly done, you have to explicitly test each string for its contents.
Using functions in the string test category, for example isdigit, walk through each of the argv string arguments, i.e from argv[1] through argv[argc - 1] and test the character type to ensure it is a numeric value, from 0 to 9 and -. (Note: other valid numeric char symbols can included, eg: e, x,et.al. but are not in this limited example.)
A simple example:
given command line: prog.exe 23 45 1f4 -57
int main(int argc, char *argv[])
{
for(int i=1;i<argc;i++)
{
if(!test_argv(argv[i]))
{
//notify user of wrong input, and exit
printf("argv[%d] contains non numeric value. Exiting\n", i);
}
}
//continue with program
return 0;
}
bool test_argv(const char *buf)
{
while(*buf)
{
if((!isdigit(*buf)) && (*buf != '-'))
{
return false;
}
buf++;
}
return true;
}
Results in:

Related

How to detect apostrophe in a char* argument?

I have a c file such that I pass arguments to as such:
./cfile [-size number]
e.g.
./cfile -size 22
Here is an example code for such a file:
int main(int argc, char** argv) {
if (argv[1] != "-size") {
fprintf(stderr, "Wrong format");
return 1;
}
// get_number is some function that returns int value of number if number, NULL otherwise
if (get_number(argv[2]) == NULL) {
fprintf(stderr, "Wrong format");
return 1;
}
return 0;
}
However, when I write
./cfile '-size' '22'
I cannot find a way of making C determine that the apostrophes should not be there.
I want to throw an error due to the apostrophes on each argument, but c seems to treat them as if they are not there.
Is there any way of doing this?
The quotes are interpreted by the shell in order to separate the arguments. They are removed before your program even sees them.
So your program will only see -size for argv[1], not '-size'.
Also, when comparing strings, you need to use strcmp. Using != or == to compare strings is actually comparing pointer values which is not what you want.

comparison between the string and pointer [duplicate]

This question already has answers here:
How do I properly compare strings in C?
(10 answers)
Closed 1 year ago.
I'm trying the following codes, but got unexpected result.
//the first element in argv[] is a
int main(int argc, char *argv[]) {
char a;
if (*argv == "a")
{
printf("a");
}
}
I got nothing after excution, so that means the condition *argv++ == "a" is false. So why?
In this if statement
if (*argv == "a")
there are compared two pointers. The first one is the pointer to the first character of the string pointed to by the pointer *argv and the second one is the pointer to the first character of the string literal "a".
As these two strings occupy different extents of memory then the comparison of the pointers always evaluates to logical false.
If you want to compare pointed strings then you need to use the standard C string function strcmp. For example
if ( strcmp( *argv, "a" ) == 0 )
If you want to compare first characters of the strings then you should write
if ( **argv == *"a" )
or just use the character 'a' instead of the string literal that is more natural
if ( **argv == 'a' )
Pay attention to that if *argv is not equal to NULL then this pointer points to the string that denotes the running program.
Maybe you actually mean the following if statement
if ( argc > 1 && strcmp( argv[1], "a" ) == 0 )
if you want to check whether the first command line argument is equal tp the string literal "a".
char *argv[] is an array of pointers to char.
// myapp.c - program to print out all command line parameters
#include <stdio.h>
int main (int argc, char *argv[]) {
int i ;
for (i = 0; i < argc; i++) {
printf ("arg %d = %s\n", i + 1, argv[i]) ;
}
return 0 ;
}
If one were to compile this code and run it at the command line like this:
myapp This That another
It would print out
arg 1 = myapp
arg 2 = This
arg 3 = That
arg 4 = another
So, let's say *argv points to 0x0800001000 (in RAM) and "a" is held at address 0x090000000 (in RAM). What you are doing is like saying:
if (0x0800001000 == 0x090000000) {
...
}
which is always going to be false (unless something really weird happens)
I'm not entirely sure what you want to do, but there are two possibilities
You want to compare the first string passed in on the command line to "a"
// do it like this
if (strcmp(argv[1],"a") == 0) {
...
}
You want to compare the first character of the first string passed in on the command line to 'a'
// do it like this
if (argv[1][0] == 'a') {
...
}
We use argv[1] because argv[0] is just the name of the executable

How can I reject an alphanumeric command-line argument (i.e. ./main 20x), but not a solely numeric one (i.e. ./main 20)? (in C)

I have figured out how to reject a purely alphabetical argument. I cannot figure out how to reject an alphanumeric user input while passing numeric inputs.
Here is my relevant code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2 || isalpha(*argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}
else...
and my code goes on to successfully carry out the function of my program (save for this one bug).
Any help would be much appreciated! This is for an edX cs50 homework assignment. I finished the whole assignment except for this bug. I searched for an answer for over 3 hours, to no avail. Help me, stack overflownobi. You're my only hope.
You're almost there: your code checks if *argv[1] (i.e. the first character of that argument) is an alphabetic character. Instead, let's use a loop to check the entire argv[1] string. We're also going to use isdigit instead, so that we can reject strings such as 41!#4 which wouldn't get detected using isalpha.
argv is an array of char*, or pointers to characters, meaning that argv[1] is a pointer to the first character of that argument. Given a pointer to the first character of a string, we need to find the string's length using strlen, after which we can write a loop. Let's break this out into a function:
bool string_is_numeric(char* string) {
size_t length = strlen(string);
for(size_t i = 0; i < length; i++) {
if(!isdigit(string[i])) { return false; }
}
return true;
}
You can call this as follows:
if (argc != 2 || !string_is_numeric(*argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}
Note that the code I gave has a few limitations:
It doesn't check whether the number is too large, e.g. to fit into an int.
It doesn't handle decimal values (i.e. those that we would parse into double).
It doesn't allow negative numbers.
Alternative using strtol:
The library function strtol allows you to convert your string to a long int, while also providing you a pointer to the very first character that couldn't be converted.
You can check that pointer: if it points to a null character (i.e. *endptr == '\0'), then strtol reached the end of the string successfully meaning that it was all valid digits.
You'll need to declare a long and a char* to hold the results:
if (argc != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
char* endptr;
long key = strtol(argv[1], &endptr, 10); // 10 meaning decimal
if(*endptr != '\0') {
printf("Key must be numeric and fit into a long\n");
return 1;
}

Declaring a -n argument to accept an integer in the command line - C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am writing a program to print the last n characters of a .txt file. I wish to add the ability to run the program from the command line with a -n argument to input the amount of characters to print.
I have tried declaring int main(int argc, char* argv[]) but that seems to accept any amount of arguments and I only need the one -n argument.
To do that, you can use strncmp and strtol:
int main(int argc, char* argv[])
{
int n = 0;
if(argc > 1)
{
if(!strncmp(argv[1], "-n", 2))
{
n = strtoll(argv[1]+2, NULL, 10);
}
}
if(n == 0) /* fail */;
/* do stuff */
}
This checks if argv has more than just one argument (the name of the program) and then checks for -n, and, if it finds it, converts the number directly after -n to an integer (i.e. -n3 is converted to three).
If you want to accept one argument only and fail otherwise, change argc > 1 to argc == 2.
and I only need the one -n argument. You will need at least 3 arguments if you require the -n argument. (meaning argc - argument count will be 3.)
... This is assuming the -n argument will be followed by an integer value to indicate how many characters are to be read. If the number of characters to be read from your file is 3, it would be called on the command line for example as:
programName.exe -n 3
This results in the arguments of main(int argc, char* argv[]) being populated as:
argc == 3
argv[] == {"programName.exe", "-n", "3"}
So yes, the C main signature int main(int argc, char* argv[]) will accommodate 1 to many arguments, but that does not exclude it from being used to create a program that will accept only 2 arguments. (The first argument listed by convention is always the executable name of the program the code is compiled into.)
If you would like to have only the one additional argument (which would result in a count of 2 actual arguments), skip including the '-n' and define your Usage as requiring a singe positive digit following the program name:
programName.exe 3
Then code it like this:
int main(int argc, char *argv[])
{
char *dummy;
int val;
if(argc != 2)
{
printf("Usage: prog.exe <n> where <n> is a positive integer value.\nProgram will now exit");
return 0;
}
// Resolve value of 2nd argument:
val = strtol(argv[1], &dummy, 10);
if (dummy == argv[1] || ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE))
{
//handle error
}
//use val to read desired content from file
...
return 0;
}

Command line arguments that has options [duplicate]

This question already has answers here:
How to properly compare command-line arguments?
(4 answers)
Closed 4 years ago.
So I have to write a program that contains two possible options depending on what the user chooses by entering either -i or -w. I'm very new to command line arguments in general and I have no idea how to do this. So far I have:
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc == -'i') {
puts("Test 1");
}
else if(argc == -'w') {
puts("Test 2");
}
return 0;
}
It doesn't print anything...
Any explanation is greatly appreciated. I'm just trying to understand the logic behind this.
First of all, you are comparing oranges with appels. argc stores the number of
arguments. Second, even if you used argv[1], the comparison would be still
wrong, because it would be comparing pointers, not the contents. Note that in C
a string is a sequence of characters that terminates to '\0'-terminating byte.
A char* variable only points to the start of that sequence. The == operator
checks for equality of values, in case of pointers (and string literals), it
compares whether both pointers point to the same location.
When you want to compare strings, you have to compare the strings themselves,
that means you have to compare the contents where the pointers are pointing to.
For strings you have to use the strcmp function like this:
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc != 2)
{
fprintf(stderr, "usage: %s option\n", argv[0]);
return 1;
}
if(strcmp(argv[1], "-i") == 0)
puts("Test 1");
else if(strcmp(argv[1], "-w") == 0)
puts("Test 2");
else {
fprintf(stderr, "Invalid option '%s'\n", argv[1]);
return 1;
}
return 0;
}
Note that it is important to check first that you have enough command line
arguments (the first if of my code). If the user didn't pass any argument,
argc will be 1 and argv[1] will point to NULL, which would yield undefined
behaviour if it is passed to strcmp. That's why I only do strcmp when I'm
100% sure that argv[1] is not NULL.
Also if you are coding for a POSIX system (linux, mac, etc), then I recommend using
getopt for parsing of the command line arguments.
You have to check argv[i] where i is the array number of the command line argument being put in, argv[0] would be the file name called upon and after that argv[1] would be the first statement, argv[2] the next and so on
argc means "argument count". meaning the number of arguments
argv is a 2-dimensional array. Strings are 1-dimensional character arrays in C. The second dimension comes from you having multiple String.
So if you want the first String argument, you would access it as follows:
argv[0]
You are also attempting to compare strings, which are more than 1 character long. You should use strcmp to compare strings in C. See How do I properly compare strings?
and if you want to compare equality, you would not use ==, == is for basic data types such as int or char.
argc represents the number of parameters that were passed in at the command line including the program name itself.
In c, a character, e.g., 'i' is an 8-bit number representing the ASCII code of the letter i. So your conditional statement if(argc == -'i') is actually checking whether -105 (105 is the ascii value of the letter i) is the number of arguments that was passed to your program.
To check whether the arguments passed in are "-i" or "-w" you need to perform string comparison, using the c library functions or your own algorithm, and you need to be comparing those strings to argv[i] (where i is the position of the parameter you're checking in the program invocation)
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("The name of the program is %s\n", argv[0]);
if( strcmp(argv[1], "-i") == 0 ) { puts("Test 1"); }
if( strcmp(argv[1], "-w") == 0 ) { puts("Test 2"); }
return 0;
}

Resources