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.

5
  • 7
    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). Commented Jan 4, 2020 at 16:49
  • 2
    The "why" needs references to 1970's data/authors - else we are left with speculation. Commented Jan 4, 2020 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. Commented Jan 4, 2020 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? :) Commented Jan 4, 2020 at 17:51
  • 4
    argv[argc] is not a pointer to NULL. It is a null pointer. Its value is NULL. It does not point to NULL. Commented Jan 4, 2020 at 18:25

5 Answers 5

5

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.

Sign up to request clarification or add additional context in comments.

Comments

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 |

1 Comment

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

Comments

2

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

Comments

0

To answer the why.

The C standard did not invent this convention; it documented existing practice. In doing so, one of the goals was to let existing programs continue to work. Since there are existing programs that relied on argc, that parameter had to be conserved. And since there were other programs that relied on argv[] being NULL-terminated, that too had to be conserved.

The existing practice in turn was mostly an implementation detail of the early UNIX implementation.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.