8

I'm writing a program that accepts command line arguments and prints them out in alphanumerically sorted order with a custom comparator.

Along the way I got stuck with inserting the command-line arguments in the std::set container. Reviewed some similar code online and found something like:

std::set<char*, decltype(customComparator)> args (argv, argv+argc, customComparator)

What does the argv + argc argument mean/do?

When I tried inserting the cmd argument like:

std::set<char*, decltype(customComparator)> args (argv, customComparator)

There's a red squiggly line on the argv argument.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
clancy
  • 101
  • 5
  • 1
    `argv + argv` is equivalent to `std::end(argv)`, while that won't compile. – πάντα ῥεῖ May 21 '22 at 15:35
  • 2
    This is not a duplicate of [What does `int argc, char *argv[]` mean?](https://stackoverflow.com/questions/3024197/what-does-int-argc-char-argv-mean). The question is what `argv+argc` means, not `argv` and `argc` on their own. – John Kugelman May 21 '22 at 15:35
  • 4
    look into "pointer arithmetic" to get an idea why – Kenny Ostrom May 21 '22 at 15:37
  • thanks @KennyOstrom. I figured it out. It points to the end of the char array – clancy May 21 '22 at 15:42
  • 1
    This is overload (2) of the [std::set constructors](https://en.cppreference.com/w/cpp/container/set/set). `argv` and `argv + argc` are the beginning and end of the range, `customComparator` is the comparator, and you're using the default allocator. – Nathan Pierson May 21 '22 at 15:45
  • 1
    it actually points to the end of the array that contains pointers to `char`, each pointer pointing to an individual argument. – n. m. could be an AI May 21 '22 at 15:49

3 Answers3

11

What is the meaning of "argv + argc"?

argv + argc is a pointer that points to the end of the last command line argument(or to the null shown in the diagram below). This is explained below(both graphically and in text form).

The diagram is shown for argc = 5 :

argv + argc

Explanation

Lets consider the declaration:

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

In the above declaration, the type of the second parameter named argv is actually a char**. That is, argv is a pointer to a pointer to a char. This is because a char* [] decays to a char** due to type decay.

In other words, argv is a pointer that points to the first element of an array with elements of type char*. Moreover, each element argv[i] of the array(with elements of type char*) itself point to a character which is the start of a null terminated character string. That is, each element argv[i] points to the first element of an array with elements of type char.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    `NULL` is proper after `argv[4]` in your example to differentiate the `NULL` pointer from the `nul-character`. (I get it, but you wouldn't want a new user thinking all were the same) – David C. Rankin May 22 '22 at 06:23
  • 1
    @DavidC.Rankin Yes, do you recommend using some other notation? I can add it in my diagram. – Jason May 22 '22 at 06:27
  • 1
    No. I like your diagram, it really helps, the `NULL`/`null` was the only thing that stood out. – David C. Rankin May 22 '22 at 06:29
  • 1
    @DavidC.Rankin Oh, thanks for the appreciation :) – Jason May 22 '22 at 06:31
  • @DavidC.Rankin Do you recommend that for the character arrays to which `argv[i]` points that i should replace the last with `'\0'` but let the `null` remain after the `argv[4]` ? – Jason May 22 '22 at 06:34
  • I would do that. the `null` is subject to different interpretations, but in the context at the end of the string it was clear it meant *nul-character*. but changing to `'\0'` would be more clear. – David C. Rankin May 22 '22 at 06:36
  • @DavidC.Rankin Done, now there should be no room left for beginners considering them the same. – Jason May 22 '22 at 06:41
  • You really like `null` instead of `NULL` as the pointer value for the next `argv[]` value after the last argument provided by the user? – David C. Rankin May 22 '22 at 06:47
  • argv+argc is not necessary NULL/null, it is not initialized and dereferenced it will give undefined behaviour. – mpromonet May 22 '22 at 06:47
  • No. `argv[]` is `char *[]` (an array of pointers) where the next pointer after the last user provided argument is set `NULL` as a sentinel. – David C. Rankin May 22 '22 at 06:48
  • @DavidC.Rankin I have changed `null` to `NULL`. My original intention when creating this diagram was that `null` is the same as `NULL` but now that you've mentioned it i have changed it to `NULL` explicitly and `null` in the `char` was to be treated as the null character instead of `NULL`. – Jason May 22 '22 at 06:51
6

The code you're showing uses the iterator based constructor, which receives a begin iterator, and a past the end iterator.

The thing is, a pointer is also considered an iterator by the STL. The ++ptr operator works, as well as ptr != end_ptr and *ptr.

So, if you want to construct an STL container from a C-style collection of objects, it's very well possible to do so. argv is the beginning of all the args value(s), and argv[argc - 1] is the end. To get a pointer past the end, simply do argv + argc.

Milan
  • 1,743
  • 2
  • 13
  • 36
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • "A pointer can very much act like an iterator" feels a bit weird to say. Iterators are defined by the behaviors they exhibit, and a pointer into an array _is_ an iterator, not something different that happens to act similar. – Nathan Pierson May 21 '22 at 15:48
6
  1. This overload of the std::set constructor accepts two iterators and a comparator. The two iterators should define a half-open range. The second iterator points to the end of the range, which for many kinds of ranges, is the one past the last element.
  2. A pointer is an iterator.
  3. If argv points to the first element of an array, and argc is an integer, then argv + argc points to argcth element of the same array (starting from zero).
  4. Since there are exactly argc meaningful elements in the argv array, argv + argc points one past the last meaningful element of the array. (There happens to be another element there, bit it is a null pointer and we are not interested in it).

All in all, the range [argv, argv + argc) is exactly the kind of half-open range standard library expects in lots of places.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • What did you mean by *"half-open range"*? Thanks in advance! – Milan Jul 19 '22 at 14:59
  • Perhaps that the second iterator is excluded = one past the last element (cf. 1.)? In the mathematical sense of half-open intervals. – Sebastian Jul 19 '22 at 15:52