How can I write a program to check the arguments in the terminal are correct?
For example, if I have a program hello.cpp and I want to call it as:
./hello yes 10
I want the program to make sure that the first argument is yes or no and the second argument is a number between 1-10. So how can I read these arguments into my program to do the checking?
Thanks!
Command line arguments are passed as a count and individual strings in the argc and argv arguments to main().
int main(int argc, char *argv[])
{
...
}
Simply check the value in argc and the strings in argv for the appropriate values.
You meant to execute like this, ./hello yes 10
there is an option argc and argv in c
where argc is the number of arguments passed and argv with the index shows the argument passed itself.
Take a look at the below code for iterating through all arguments.
int main(int argc, char *argv[]){
int i = 0;
for (i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}
As mentioned by other users, The main function is the entry point of your program, and the way it gets data from the command line is through its parameters.
The first int argument is the count of all the arguments passed, including the program name, the second char ** argument is a pointer to each parameter passed, including the program name:
int main
(
int argc, // <-- how many parameters has been provided?
char **argv, // <-- what values has each parameter?
)
{
...
return 0;
}
So, knowing that, your call ./hello yes 10 must be like that:
argc = 3
argv[0] = "./hello"
argv[1] = "yes"
argv[2] = "10"
The names argc and argv are just a convention, you can name them at your pleasure, but it's a good practice to keep the names that everyone are used for.
And the argument doesn't are forced to be int, char ** they must follow a quite rigid convention, borrowed from this answer:
It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both the following definitions of main: int main() and int main(int argc, char* argv[])
Knowing that, let's focus on your question:
First of all, you must ensure that 2 arguments are passed, so you must check the argc value and ensure that equals exactly 3.
the first argument is yes or no
Next, you must store your argv[1] (because 0 contains the program name) into a string and compare it with the values "yes" and "no":
std::string YesOrNo(argv[1]);
if (YesOrNo == "yes" || YesOrNo == "no")
And finally, you must store your argv[2] into an integer and check if it is equal or less to 10:
std::stringstream Stream;
int Value = 0;
Stream << argv[2];
Stream >> Value;
if (Value <= 10)
So, the result is:
int main(int argc, char **argv)
{
if (argc == 3)
{
std::string YesOrNo(argv[1]);
if (YesOrNo == "yes" || YesOrNo == "no")
{
std::stringstream Stream;
int Value = 0;
Stream << argv[2];
Stream >> Value;
if (Value <= 10)
{
// Your stuff..
}
}
}
return 0;
}
I let you deal with all the uppercase and lowercase stuff and the false positives with the numeric argument, at least I'm not going to do all your homework ;)
Related
I have below code where I am passing address of array of charectors to function "GetStr". GetStr function prototype is fixed.
Here in below code I am passing command line argument where string to function "GetStr" and update the value in the address of variable "str".
PRoblem:
At Print 1, I am getting the value what I passed from command line arguments. A Print 2 in main function, I am unable to print or get the value back. Could you please let me know how to print the value at "Print 2" statement
int GetStr(void *RetVal, int argc, char **argv)
{
if(argc != 0){
if(argv != NULL && argv[1] != '\0'){
RetVal = argv[1];
}
else{
RetVal = '\0';
}
cout<< " RetVal: " << (char *)RetVal <<endl; ->>> PRINT 1
}
else{
return -1;
}
return 0;
}
Driver:
int main(int argc, char **argv)
{
char str[8];
GetStr(str,argc,argv);
cout<<"HH: "<<((char *)(str))<<endl; ->>> PRINT 2
}
You have to use strcpy() to copy a string. You're just assigning the address of argv[1] to the local variable RetVal, which has no effect on the array in the caller.
You should also check argc to determine if argv[1] has been supplied.
int GetStr(void *RetVal, int argc, char **argv)
{
if(argc != 0){
if(argv != NULL && argc >= 2){
strcpy((char*)RetVal, argv[1]); // copy first argument
}
else{
*(char*)RetVal = '\0'; // Set to empty string
}
cout<< " RetVal: " << (char *)RetVal <<endl; ->>> PRINT 1
}
else{
return -1;
}
return 0;
}
Note that it's necessary to cast RetVal before indirecting through it in the assignment, because you can't dereference a void pointer.
The parameter RetVal is a local variable of the function GetStr. Changes of it do not influence on the original argument passed to the function. Moreover as the original argument is an array then arrays do not have the assignment operator. You have to copy characters pointed to by argv[1] to the passed array.
So in any case this statement
RetVal = argv[1];
and this
RetVal = '\0';
have no effect relative to the passed array. And it is unclear what you are trying to do in the second statement above. Either you want to set the pointer to NULL. Or you want to set the first pointed byte to the terminating zero character that is invalid because the pointer is not dereferenced and moreover has the type void *.
Also it seems that instead of this expression in the if statement
argv[1] != '\0'
you mean either
argv[1][0] != '\0'
or
argv[1] != nullptr
In any case these two if statements
if(argc != 0){
if(argv != NULL && argv[1] != '\0'){
can be substituted for one if statement as
if ( not ( argc < 2 ) )
The function can look at least the following way
int GetStr( void *RetVal, int argc, char **argv )
{
int error = argc < 2 ? -1 : 0;
if ( not error )
{
strcpy( RetVal, argv[1] );
}
return error;
}
The function should not output anything except for the debug purpose. It is the caller of the function will decide whether to output a message if any.
Pay attention to that the function is unsafe because the passed array can be less than it is required to copy the string pointed to by argv[1].
I need to give default behavior to a command line app if no arguments are entered.
If no arguments are entered, I need the program to set argv[1][0] = '1' and argv[1][1] = '\0' for the null terminator.
I keep getting a core dump when I try to compile my code in g++, and here is what is causing the issue:
int main(int argc, char * argv[]){
//for testing we put some dummy arguments into argv and manually set argc
//argc = 1;//to inlcude the program name
//we put a defualt value into argv if none was entered at runtime
if(argc == 1){
argv[1][0] = '1';
argv[1][1] = '\0';//add a null terminator to our argv argument, so it can be used with the atoi function
}
Also, I am not on C++ 11.
RE-FACTORED CODE: (Which basically just codes around the issue so that we don't have to manipulate argv[] in the main function)
int argvOneAsInt;
if(argc != 1){
argvOneAsInt = atoi(argv[1]);//use atoi to convert the c-string at argv[1] to an integer
}
else{
argvOneAsInt = 1;
If argc equals 1, then the second value in the array argv is NULL. You are dereferencing that NULL pointer right here:
argv[1][0] = '1';
Instead of trying to manipulate argv, rather change the logic in the code. Use an array you control in memory, copy argv to it and then manipulate the array.
This all looks rather dodgy. I would probably do something like this:
int main(int argc, char* argv[])
{
std::string arg1 = "1"; // set default
if(argc > 1) // override default if present
arg1 = argv[1];
// Now use arg1 and forget about argv[]
}
just to support your question, what ever you wanted was not faulty but you forgot to allocate memory where you wanted to assign your values.
Check this:
#include <string.h>
#include <malloc.h>
using namespace std;
int main(int argc, char * argv[]){
//for testing we put some dummy arguments into argv and manually set argc
//argc = 1;//to inlcude the program name
//we put a defualt value into argv if none was entered at runtime
if(argc == 1){
argv[1] = (char*)malloc(strlen("1\0"));
argv[1][0] = '1';
argv[1][1] = '\0';
//argv[1][2] = '\0';
//argv[1] = '\0';//add a null terminator to our argv argument, so it can be used with the atoi function
}
}
now it should work the way you want.
How can I put the default values for main function arguments like the user defined function?
Well, the standard says nothing which prohibits main from having default arguments and say you've successfully coalesced the compiler to agree with you like this
#include <iostream>
const char *defaults[] = { "abc", "efg" };
int main(int argc = 2, const char **argv = defaults)
{
std::cout << argc << std::endl;
}
Live example. It compiles with no errors or warnings, still it's useless; a futile experiment. It almost always would print 1.
Every time you invoke the program, say, with no arguments (or any number of arguments for that matter), argc gets set to 1 and argv[0] points to the program name, so doing it is pointless i.e. these variables are never left untouched and hence having defaults makes little sense, since the defaults would never get used.
Hence such a thing is usually achieved with local variables. Like this
int main(int argc, char **argv)
{
int const default_argc = 2;
char* const default_args[] = { "abc", "efg" };
if (argc == 1) // no arguments were passed
{
// do things for no arguments
// usually those variables are set here for a generic flow onwards
argc = default_argc;
argv = default_args;
}
}
I think you want to do two different things for the following cases.
When no arguments are passed
When arguments are passed.
Here is how you do it.
int main(int argc, char *argv[])
{
if(argc == 1)
{
// case #1
}
else
{
// case #2
}
}
Using argc and argv? Thoses will pass argument from the command line to your program. You can't really use default arguments. You have to pass them during the call to your program like this :
$> ./my_addition "4" "7"
int main(int argc, char *argv[])
{
// argc <=> 'argument count' (=3)
// argv <=> 'argument vector' (i.e. argv[1] == "4")
// argv[0] is usually the bin name, here "my_addition"
for (int i = 0; i < argc; ++i)
std::cout << argv[i] << std::endl;
return (0);
}
Maybe you could use a script to run your program, this could maybe be the closest solution to default argument for main().
exec_my_prog.sh:
#!/bin/zsh
call_your_program + very_meny_args
And calling ./exec_my_prog.sh would run your program with the "default" arguments.
int
main(int argc,char **argv){
for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
argCount = 1;
switch (argv[0][1]) {
case 'q':
testnum = atoi(argv[1]);
argCount++;
break;
default:
testnum = 1;
break;
}
}
//...............
my question is what does the argv[0][1] mean and the condition in for() confused me i mean for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount)
//thanks guys....**argv[0][1] should be argv[0][1],thats my mistake not the code writers.
That code doesn't look correct. **argv[0][1] tries to dereference a char.
argv[0][1] would make sense, and means "take the second char of the first char* in argv." IMHO, the code is trying to detect a -q command-line flag (and subsequently setting testnum to the int version of the next argument, blindly assuming it is present), but it's skipping checking for the -, and blindly assuming it's there, and no other arguments would ever have q as a second character.
This code needs to be refactored. Here's one way:
int main(int argc, char **argv) {
int testnum = 1;
for (int argi = 1; argi < argc; ++argi) {
if(argv[argi][0] == '-') {
switch (argv[argi][1]) {
case 'q':
if(argi + 1 == argc || argv[argi + 1][0] == '-') {
/* Handle missing argument error. */
return 1;
}
testnum = atoi(argv[++argi]);
break;
default:
/* Handle unrecognized flag error. */
return 1;
}
}
else
{
/* Handle non-flag parameter. */
}
/* Continue with program. */
return 0;
}
argv[0] represents the name of the program as it was invoked on the command line. If you typed ./myprogram --help, then argv[0] would be "./myprogram".
argv[0][1] will be the second character of that string, '/' in the example above.
Let’s see that for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount):
It initializes the loop by doing argc-- then argv++ (argv now points to the second user parameter string) and argc declares an argument less.
The loop is for all arguments argc>0, and at every iteration, the number of treated arguments argCount is taken off the number of all arguments argc. That makes sense.
However switch (**argv[0][1]) doesn’t make any sense, argv[0][1] is a char, as seen before, not a pointer, so it cannot be dereferenced.
This code looks very crazy. I guess you intended to do the following:
int main(int argc,char **argv){
char** p = argv + 1; // skipping program name
while (*p != 0) { // over all parameters
testnum = 1;
if (*p[1] == 'q') { // skipping - of "-q", not a good idea
p ++;
if (*p != 0) { // may be null, read testnum from parameter,
// ?? no check whether this is an integer at all
testnum = atoi(*p);
}
}
}
(not tested, may not compile nor work)
I have a program that reads in a single argument from the command line and performs certain operations on it. I'm using argv and argc. When I fail to pass an argument to the program, it segfaults. I've tried checking if argc isn't a certain value and then printing the value out, but it still segfaults. Here's the code in question. Note that it works as expected when passed a single argument. Here's the code in question:
int main(int argc, char *argv[])
{
int numTimes = atoi(argv[1]); //converts content of argv[1] into integer
if(argc != 2)
{
printf("Enter a valid integer.");
}
You need to check argc before you try to access that argument. Just move the argc test to sometime before before you call atoi(argv[1]).
Just check the number of arguments before trying to accessing a specific element. Something like this:
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("Enter a valid integer.");
return 0;
}
int numTimes = atoi(argv[1]); // now we're sure to have at least 1 argument passed
// ...
}
You have to do the check before attempting to access the arguments.