37

So I'm attempting to check the arguments that I'm inputting into my program, and one of them is either the word "yes" or "no", entered without the quotes.

I'm trying to test equivalency ( if (argv[n] == "yes") ) but that seems to be returning false every time when the input is, in fact, yes(When I output it it confirms this). What am I missing here that I'm doing improperly? If I understand properly argv[n] returns a cstring that is null-terminated, so it should allow me to do this.

Ben
  • 371
  • 1
  • 3
  • 3

6 Answers6

77

You're comparing pointers. Use strcmp, or std::string.

int main(int argc, char * argv[]) {

  if (argv[1] == "yes"); // Wrong, compares two pointers
  if (strcmp(argv[1], "yes") == 0); // This compares what the pointers point to
  if (std::string(argv[1]) == "yes"); // Works fine
  if (argv[1] == std::string("yes")); // Works fine

  // Easy-mode    
  std::vector<std::string> args(argv, argv+argc);
  for (size_t i = 1; i < args.size(); ++i) {
      if (args[i] == "yes") {
          // do something
      }
  }

}
Erik
  • 88,732
  • 13
  • 198
  • 189
  • So "yes", for example, is a pointer to a string literal? That makes sense. Thank you. – Ben Mar 03 '11 at 16:04
  • 2
    What about "easier mode" where you use `std::find` instead of the for loop over the `vector`? – Mark B Mar 03 '11 at 16:20
  • std::find is fine if he's asking "is one of my arguments yes". He's asking "is this argument yes or no". This is interpretation of the question though, rereading it I see that your interpretation could just as well be right. – Erik Mar 03 '11 at 16:28
  • 1
    @Ben: `"yes"` on its own actually refers to an array rather than a pointer, but it decays to a pointer to the first element in the usual way for arrays. – Steve Jessop Mar 03 '11 at 18:10
5

Here's a better alternative to std::string, and when efficiency is important - in C++17 you now have the very useful std::string_view. This lets you work with the arguments similarly to a std::string, without incurring the cost of copying.

Currently available in std::experimental in GCC:

#include <experimental/string_view>
...
if(std::experimental::string_view(argv[1]) == "yes") {
  // do things
}
Riot
  • 15,723
  • 4
  • 60
  • 67
4
if(strcmp(argv[0],"yes")==0) { // equal to "yes"

strcmp is zero if the 2 strings are the same.

Bernd Elkemann
  • 23,242
  • 4
  • 37
  • 66
1

You could also take a look into boost::program_options, though this seems a little off topic and overkill, but once you get used to it it's easy, convenient and safe to use. Some advantages are auto-generated --help for your program, plus things like string evaluation can be done safe using lexical_cast.

count0
  • 2,537
  • 2
  • 22
  • 30
0

If you don't know exactly where the argument will appear, you might consider using find_if (C++17):

#include <algorithm>
#include <string>

int main(int argc, char * argv[])
{
    auto const begin = argv;
    auto const end = argv + argc;

    auto is_yes = [](std::string const & s) { return s == "yes"; };
    auto const it = std::find_if(begin, end, is_yes);

    // do stuff with `it`
    // ....
}
Josie Thompson
  • 5,608
  • 1
  • 13
  • 24
-1

Modern C++, with a bit of const correctness...

/*BINFMTCXX: -Wall -Werror -std=c++17
*/

   #include <iostream>
   #include <string>
   #include <vector>
   using std::string; using std::vector; using std::cerr;

int main( int argc, char * const argv[] )
   {
   assert( argc >= 1 ); // exploratory -- could fail in principle, but not really
   const vector<string> args(argv+1,argv+argc); // convert C-style to modern C++
   for ( auto a : args ) cerr<<(a=="yes")<<"\n"; // operator '==' works as expected
   }

Note: The standard doesn't guarantee that you can use const in the signature of main, nor does it forbid it.

As used here, const ensures that we won't change things we don't intend to change -- which is the purpose of const in the C++ language.

See also...

Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • Oh dear, did they go with dropping the `auto` requirement in range-for in the end, then? Yuck :( – Lightness Races in Orbit Feb 26 '18 at 01:03
  • 1
    _"convert C-style to modern C++"_ It does more than that - it invites `argc+1` unnecessary dynamic allocations and `argc` totally unnecessary string copies. At least make it a vector of string views... – Lightness Races in Orbit Feb 26 '18 at 01:05
  • 1
    `int main( int argc, char * const argv[] )` is non-portable. (The links you provide do not cover this usage) – M.M Feb 26 '18 at 01:10
  • 1
    Also this would cause undefined behaviour in the case `argc == 0` – M.M Feb 26 '18 at 01:13
  • It's like this answer was intentionally baiting another war about the signature of main – M.M Feb 26 '18 at 01:21
  • @M.M: There needn't be war. I said it wasn't guaranteed by the standard, you said it was non-portable. Agree to agree. I'm just presenting some on-topic ideas about how this could well be done. I tried to capture the links that best addressed the signature question -- there is an issue, though, of dup-closing questions that would directly address this point (such as my first "see also"). – Brent Bradburn Feb 26 '18 at 01:32
  • @LightnessRacesinOrbit: I wasn't previously aware of string_view -- I'll look into that. Thanks! – Brent Bradburn Feb 26 '18 at 01:37
  • Having sort of stopped following C++ advances a few years ago, I only recently found out about `std::string_view`. However, I'd already implemented my own because, well, it's an obvious tool to have ;p – Lightness Races in Orbit Feb 26 '18 at 01:39
  • [`string_view`](http://en.cppreference.com/w/cpp/header/string_view) provides a drop-in replacement for `string` in my example, but it seems to be not yet widely supported. It worked on Ubuntu 16.04 with g++5, clang-4, and clang-5 -- but I had to use `` and `std::experimental::string_view`. At some point in the future, this will be a nice optimization for cases such as this. – Brent Bradburn Feb 26 '18 at 01:52
  • The `+1` in `argv+1` is, in principle, system specific. I don't think there is a straightforward way of making that work in a portable way, according to the standard. It is my understanding, though, that using `+1` will basically always be the right thing to do: https://stackoverflow.com/a/3024202 – Brent Bradburn Feb 26 '18 at 02:00
  • To make it portable, check for `argc == 0` first ... (and use a portable signature for main) – M.M Feb 26 '18 at 02:24
  • @M.M: That doesn't make it portable because, if such a system exists, you wouldn't know whether or not to ignore the `[0]` argument. – Brent Bradburn Feb 26 '18 at 02:28
  • An interesting, though verbose, approach based `string_view` was already posted. https://stackoverflow.com/a/42864876/86967 – Brent Bradburn Feb 26 '18 at 05:01
  • 1
    @LightnessRacesinOrbit: You're right -- `auto` is required in C++17. I've learned a lot today. [Is auto an optional keyword in ranged based for loops?](https://stackoverflow.com/q/32706051/86967) – Brent Bradburn Feb 26 '18 at 05:29