tags:

views:

658

answers:

3

I've been having trouble with comparison in my c++ program. This is the boiled down version.

#include "stdafx.h"
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, char *argv[])
{
 if(argc>2){cout<<"3+Args"<<endl;}else//???
 if(argc==2){
  cout<<"2args"<<endl;
  if(argv[1]=="/hide-icons"){}
  if(argv[1]=="/show-icons"){}
  if(argv[1]=="/reinstall"){setAsDefault();}
  if(argv[1]=="/?"){showPossibleCommands();}
  if(argv[1]=="/1"){cout<<"go"<<endl;FirstRun();}
 }else{showPossibleCommands();cout<<argv[0]<<endl;}
 return 0;
}

When I run "programname.exe /1", my program writes "2args" but not "go". Am I missing something obvious?

+16  A: 

argv[1] is a char*, so by testing with == you're checking if the pointer points to the same spot as the start of the various string constants you're using... which is not going to be the case. To compare contents instead, use strcmp.

Alex Martelli
Or stricmp if you want the arguments to be case insensitive
Stephen Nutt
Or strncmp if you want to test only the first n characters.
Will Bickford
`stricmp()` isn't standard. Chere's no real standard C (or C++ as far as I can tell - ask a real C++ programmer) way to do a case-insensitive string comparison. GCC provides strcasecmp, VC++ provides stricmp...
Chris Lutz
Alex Martelli
strcasecmp is what the Open Group / IEEE specify in their standards, see http://www.opengroup.org/onlinepubs/9699919799/functions/strcasecmp.html .
Alex Martelli
+4  A: 

The problem is, that your code compares the pointers to the strings, not the stings itself.

You have to replace the compares with calls to the string-compare function.

E.g.

if(argv[1]=="/1"){cout<<"go"<<endl;FirstRun();}

becomes

if(strcmp(argv[1],"/1") == 0) {cout<<"go"<<endl;FirstRun();}

You may have to include string.h to get the strcmp prototype into your code.

Nils Pipenbrinck
+1  A: 

Another option is to convert the C-style arguments into a much more friendly vector of strings and process them instead:

#include <string>
#include <vector>

typedef std::vector<std::string> parameter_list;

int
cpp_main(std::string const& program_name, parameter_list const& params) {
    for (parameter_list::const_iterator arg=params.begin(); arg!=params.end(); ++arg) {
        if (*arg == "/hide-icons") {
        } else if (*arg == "/show-icons") {
        } else if (*arg == "/reinstall") {
            set_as_default();
        } else if (*arg == "/?") {
            show_help(program_name);
        } else if (*arg == "/1") {
            first_run();
        } else {
            show_help(program_name);
        }
    }
    return 0;
}

int
main(int argc, char **argv) {
    return cpp_main(argv[0], parameter_list(&argv[1], &argv[argc]));
}
D.Shawley
iain
The constructor is never dereferencing `argv` outside of its range. This is an STL open range so it copies starting at `argv[1]` and ending at the element before `argv[argc]`. Remember that `end()` is STL is actually the _"past-the-end value for the container"_. If the container is an array, then this is the element following the last element of the array. However, there may be a small possibility that the address of `argv[argc]` (which is calculated) overflows the address range but I think the standard actually provides protection against this happening too.
D.Shawley