1

In the C standard ISO/IEC 9899:2018 (C18), §5.1.2.2.1 - "Program startup", is written:

2 - If they are declared, the parameters to the main function shall obey the following constraints:

argv[argc] shall be a null pointer.


My Question is:

  • Why char *argv[argc]/char **argv shall be/ is a pointer to NULL?

This is what doesn´t make sense to me. argv[] is an array of pointers pointing to char. argv is a pointer to an array of pointers, pointing to char. Even if there are no flags given by the call, the pointer shouldn´t turn to a pointer to NULL.

Isn´t char* argv[] an array of pointers to char and char **argv a nested pointer to char pointers? How can a nested pointer to char (char**) be a pointer to NULL?


I have read the answers to argv[argc] ==? where the above-mentioned phrase from the standard is quoted as answers and also questioned to @pmg´s answer, who gave me the answer:

independent of the names used, by the c specification char *argv[argc] declares an array named argv capable of holding argc pointers to char. When passed to a function, the array gets converted to a pointer to its 1st element (so a pointer to pointer to char [this is why it is usual to see main(int argc, char **argv)]) losing information about size (char *a[10] has 10 elements; char **a is a pointer --- if the pointer points to an array, there is no way of knowing how many elements the underlying array has).

but unfortunately despite the humble effort, I still can´t understand why a pointer to pointer (nested pointer) to char (char**) turns into a pointer to NULL.

The answers to Is argv[argc] equal to NULL Pointer also do not answer why it shall be a pointer to NULL, only that is a pointer to NULL while quoting the above statement of the standard.


Thanks in advance.

  • 6
    Since `argc` is the number of elements in the `argv` array, the highest index of a valid entry is `argc-1`. That is, the last "argument" is `argv[argc-1]`. Technically, that could make `argv[argc]` undefined. The choice was made to make it NULL. What this does is provide additional ways of looping through the argument list (checking for NULL instead of using `argc` as a loop count). – lurker Jan 04 '20 at 16:49
  • 2
    The "why" needs references to 1970's data/authors - else we are left with speculation. – chux - Reinstate Monica Jan 04 '20 at 17:00
  • Probably that may be explained by historical reasons, but I don't know what those are. That constraint allows loops to traverse all command line arguments using only `argv`: `while (*argv) puts(*argv++);`. Perhaps that kind of loops were widespread at the time of standardization process. – Lxer Lx Jan 04 '20 at 17:33
  • *The "why" needs references to 1970's data/authors*. Are you sure that `argv[argc]` has been implemented as NULL going back to the 1970's? :) – lurker Jan 04 '20 at 17:51
  • 3
    `argv[argc]` is not a pointer to `NULL`. It is a null pointer. Its **value** is `NULL`. It does not point to `NULL`. – Eric Postpischil Jan 04 '20 at 18:25
  • @EricPostpischil what's the difference between a null pointer and a pointer to ```NULL```? – qwerty_url Jun 24 '21 at 20:10
  • 1
    @qwerty_url: `NULL` is (in effect) a value a pointer can have. (I say “in effect” because there are technical definitions of it and of “null pointer constant” that are not relevant here.) A pointer either points to some object or function or is a null pointer (in which case it does not point to any object or function). If we consider some `char *x` that has a defined value, then either `x` points to a `char` or it is a null pointer. If it is a null pointer, it does not point to anything; it does not point to `NULL`. – Eric Postpischil Jun 24 '21 at 20:34
  • 1
    @qwerty_url: If we had a `char **p`, that is a pointer to a pointer, so it could point to some place where we have stored a null pointer. Even so, this would be a pointer to a null pointer; it would not be a pointer to `NULL` (due to the technical definition of `NULL` as being a macro with a certain form). – Eric Postpischil Jun 24 '21 at 20:35

4 Answers4

4

It is done for two reasons:

  1. For extra safety: if you try accessing an element beyond [argc - 1] you will crash, instead of interpreting garbage as an extra argument, and doing something bad with it, like treating it as a filename and writing to the file.

  2. For convenience: this way, you can make use of argv without knowing argc.

How it works:

There is no magic really, here is the memory layout:

char**  |    char*     |  char[]
--------+--------------+---------
argv -> | argv[0] ->   | "arg1"
        | argv[1] ->   | "arg2"
        | argv[2] NULL |
Mike Nakis
  • 50,434
  • 8
  • 92
  • 124
  • This does not answer the question asked. This answers why `argv[argc]` is `NULL`, but the question asks (incorrectly) why `argv[argc]` is a pointer to `NULL`. – Eric Postpischil Jan 04 '20 at 18:28
3

From

Rationale for International Standard Programming Languages C Revision 5.10 April-2003

5.1.2.2.1 Program startup

The specification of argc and argv as arguments to main recognizes extensive prior practice. argv[argc] is required to be a null pointer to provide a redundant check for the end of the list, also on the basis of common practice.


Update: As pointed out by Eric Postpischil, this answers why argv[argc] is a null pointer. Of course argv[argc] is not a pointer to NULL, as asked in the question (NULL is a macro defined as a null pointer constant; pointer to NULL makes no sense). So the question and answers may be rendered moot.

Lxer Lx
  • 282
  • 1
  • 6
2

What is meant by

— argv[argc] shall be a null pointer.

Is that index argc of the array argv is a null pointer.

That is

if (argv[argc] == NULL)

will always come out true.

Some programmer dude
  • 380,411
  • 33
  • 383
  • 585
2

IMO it is for convenience while(*argv != NULL) ....

0___________
  • 47,100
  • 4
  • 27
  • 62