confused about this argv use - c++

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)

Related

print value of char array which is loaded with void pointer

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].

find() returning maximum value of unsigned int

I'm finishing up a homework assignment that requires me to redirect input and output in the same command. When searching the command (that is a string) for both "<" and ">" the if statement always returns true. This is because it finds the maximum value of an unsigned int on a 64bit system.
The if (uCommand.find("<",0) && uCommand.find(">", 0)) statement will always be true. When I run the uCommand.find(">", 0) in gdb is returns 18446744073709551615.
int main(int argc, char *argv[]) {
// local variables
char **toks;
int retval;
int ii;
int redirect;
int search;
string fileName;
// initialize local variables
toks = NULL;
retval = 0;
ii = 0;
// main (infinite) loop
while (true)
{
// get arguments
toks = gettoks();
if (toks[0] != NULL)
{
for (ii = 0; toks[ii] != NULL; ii++) {
uCommand += " ";
uCommand += (string)toks[ii];
}
// Search for input, output, or dual redirection
if (uCommand.find("<", 0) && uCommand.find(">", 0))
{
redirect = dualRedirect(toks, uCommand);
addHist(uCommand);
}
else if (uCommand.find("<", 0)) {
redirect = inRedirect(toks, uCommand);
addHist(uCommand);
}
else if (uCommand.find(">", 0)) {
redirect = outRedirect(toks, uCommand);
addHist(uCommand);
}
// Look for hist or r and execute the relevant functions
if (!strcmp(toks[0], "r"))
repeatCommand(uCommand);
else if (!strcmp(toks[0], "hist")) {
addHist(uCommand);
showHist();
}
else if (redirect == 0) {
execCommand(toks);
addHist(uCommand);
}
// Increment the command count. This only runs if a something is entered
// on the command line. Blank lines do not increment this value.
commandCount++;
}
}
// return to calling environment
return(retval);
}
I'm assuming uCommand is a std::string, as you didn't include its declaration.
std::string::find returns std::string::npos when the find fails to find anything. This is normally (size_t)-1, size_t is an unsigned type, meaning that npos is an extremely large value. You can't treat this as a bool as anything non-zero is treated as true.
Your code should be
if (uCommand.find("<", 0) != std::string::npos && uCommand.find(">", 0) != std::string::npos)

Checking command line inputs for errors in C++

I had this program working just a bit ago but changed something and now my error handling has gone bonkers. I'm practically hitting my head against the wall here trying to put it back the way it was, but no matter what I do now, it spits out an error.
The program is supposed to take command line arguments to define the rows and columns and create a dynamic 2D array based on that. The format is "-rows (number) -columns (number)". I tried to add a few more cases before I turned in the assignment, but I must have changed some logic elsewhere, because even after I removed the new part it still won't work no matter what I input. At this point I think I just need a pair of fresh eyes to point me in the right direction.
int main(int argc, char* argv[]) {
// Checks if the user input the correct number of arguments.
// If so, checks if they were input corecctly. If so, it assigns
// the user input values to rows/columns, and if not, prints
// an error message.
if(argc == 5) {
for(int i = 1; i < argc; i++) {
rows = getArg(argc, argv, i, compare1);
}
for(int i = 1; i < argc; i++) {
columns = getArg(argc, argv, i, compare2);
}
} else {
printError(argv);
}
That is the relevant part of main.
Below are the functions involved in checking for errors. The one I actually have been working on is getArg, so I'm assuming this is where the logic is failing, but I included the other necessary function for clarity.
// Description: Checks if user input was valid
// Parameters: Command line arguments, int i from the for
// loop used to run this check on all command line arguments
// in main, and an array of chars used to compare the user's
// inputs to "-rows" or "-columns"
// Return value: If user input was valid, returns an int
// If not, exits program.
int getArg(int argc, char* argv[], int i, char compare[]) {
int arg;
if (strcmp(argv[i], compare) == 0) {
if (isInt((i + 1), argv)) {
arg = atoi(argv[i + 1]);
} else {
printError(argv);
}
} else {
printError(argv);
}
return arg;
}
// Description: Checks user input for valid integers
// Parameters: Command line arguments
// Return value: Returns true if input is an int;
// false if not.
bool isInt(int argc, char* argv[]) {
bool isInt;
for (int j = 0; j < strlen(argv[argc]); j++) { //For loop runs through each char in the array at argc
if (isdigit(argv[argc][j])) { // Checks to see if char is an integer
isInt = true;
return isInt;
} else {
isInt = false; // If there is ever a non-integer character, exit loop and return false
return isInt;
}
}
}
The first for loop in main continues to scan the argument list after it has matched "-rows". The loop makes the following calls (I'm assuming compare1="-rows" here since you didn't mention it):
i=1: getArg(argc=5, argv={"a.out", "-rows", "2", "-columns", "3"}, i=1, compare="-rows")
returns 2
i=2: getArg(argc=5, argv={"a.out", "-rows", "2", "-columns", "3"}, i=2, compare="-rows")
calls printError(argv) because strcmp("2", "-rows") is nonzero
Also, as Abhishek mentioned, isInt only ever checks the first character of the string because you return in the isInt = true branch.
One possible error that I can spot is that you are not looping correctly in your isInt() function.
You would invariably return out of the function after the 1st iteration.
Its nice you got an answer, but this is one is pretty easy to use and on entire SO you'll find this suggestion wherever such questions are tagged for C++
Using boost::program_options
#include <iostream>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main( int argc, char *argv[ ] )
{
try {
int rows,cols;
po::options_description desc("Allowed options");
desc.add_options()
( "help", "produce this help message" )
( "rows", po::value< int>(&rows)->required(), "No. of Rows" )
( "cols", po::value< int>(&cols)->required(), "No. of Cols" )
;
po::variables_map vm;
po::store( po::parse_command_line( argc, argv , desc ), vm );
po::notify( vm );
if ( vm.count( "help" ) )
{
std::cout << desc;
return 0;
}
std::cout<<"Rows :"<<rows<<" "<<"Cols :"<<cols<<std::endl;
}
catch( std::exception& e )
{
std::cout << e.what() << "\n";
return 1;
}
return 0;
}
Usage :
./test --cols 4 --rows 3
Outputs :
Rows :3 Cols :4
Good Tutorial Here

Scan arguments and determine what they are with a c++ program

This is a homework assignment first off.
We have to create a "common application-programming model in UNIX/Linux known as the filter".
I'm stuck on reading the input passed through as arguments (it's all I ever seem to have trouble on).
For example, the cmd is open and the following line is entered:
program -isomebinaryfile.bin
I need to determine what the first letter is after the hyphen (-) and so on and so forth.
Is scanf what I would be using? My main is set up to be able to accept arguments:
int main (int argc, char *argv[])
{
FILE *inf = NULL;
char *arg = argv[0];
}
Can someone give me a little help?
Unless your assignment is only to handle processing of arguments, you may want to look up getopt - it's a standard library parser for arguments.
As for the meat of your question, there are a lot of options, and you could use sscanf as part of it, but you don't have to.
To parse the one argument you mentioned, you need to do the following: check if the argument begins with -i, grab the data out of the argument.
The easiest way to check if the argument begins with -i is:
if (argv[1][0] == '-' && argv[1][1] == 'i')
Alternatively, if you have a lot of argument options, all beginning with '-', you may want something like:
char * i = NULL;
char * o = NULL;
char * s = NULL;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
switch(argv[i][1]) {
case 'i':
i = argv[i][2];
break;
case 's':
s = argv[i][2];
break;
case 'o':
o = argv[i][2];
break;
default:
cerr << "Unknown option: " << argv[i][1];
}
} else {
cerr << "Error: all options must begin with '-'";
}
Note, I'm using argv[1], not 0. argv[0] is always the name of the executable.
The fastest way to extract the rest of the argument is simple pointer arithmetic:
char * filename = argv[1] + 2; // (Or you could equivalently say = &argv[1][2]
This is most efficient - it reuses the strings that are already in argv. If you're planning on changing the strings around, you'd do better with strcpy:
char * filename = (char *)malloc(strlen(argv[1]) - 2);
strcpy(filename, argv1 + 2);
// and eventually you'd have to free(filename)...
Play around and experiment with all the string functions. You'll find them essential to all of your later programs.
You need to use getopt. The manual page has an example.
argv is an array of strings. You can loop over them like
for (int i=1; i<argc; i++) { // skip argv[0] as that's this program's name
const char* arg = argv[i];
}
Once you have the string for a particular argument, you can use the string manipulation functions from <string.h>
if (arg[0] == '-' && strlen(arg) > 0) {
arg++; // advance past the leading '-'
if (strcmp(arg, "command_one") == 0) {
// handle command_one
}
else if (strcmp(arg, "command_one") == 0) {
....
else {
printf("Error: unexpected command %s\n", arg);
}
Get arguments from argv ("argument vector"). In your example, argc and argv will be as follows:
argc == 2
argv[0] == "cmd"
argv[1] == "-isomebinaryfile.bin"
Finding the first letter after the hyphen in argv[1] is a simple loop.

Checking arguments in terminal

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 ;)