Why do we need argc while there is always a null at the end of argv?

Solution 1:

Yes, argv[argc]==NULL is guaranteed. See C11 5.1.2.2.1 Program startup (my emphasis)

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

The value of argc shall be nonnegative. argv[argc] shall be a null pointer.

Providing argc therefore isn't vital but is still useful. Amongst other things, it allows for quick checking that the correct number of arguments has been passed.

Edit: The question has been amended to include C++. n3337 draft 3.6.1 Main function says

2 ...argc shall be the number of arguments passed to the program from the environment in which the program is run. .... The value of argc shall be non-negative. The value of argv[argc] shall be 0.

Solution 2:

Yes, argv[argc] is guaranteed to be a null pointer. argc is used for convenience.

Quoting the official explanation from C99 Rationale, note the words redundant check:

Rationale for International Standard — Programming Languages — C §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.

Solution 3:

It's for historical reasons, and compatibility with old code. Originally, there was not a guarantee that there would exist a null pointer as the last element of the argv array. But argc has always existed.

Solution 4:

We "need" it, because it's required by various standards.

We are free to ignore the value completely, but since it is first parameter of main, we must have it in parameter list. In C++ (and probably non-standard C dialects), you can just omit the parameter name, like this C++ snippet (easy to convert to C):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

In standard C, with common warnings settings, unused parameter generates warning, which can be fixed by a statement like (void)argc; which causes the name to be used without generating any code.

argc is nice to have, because otherwise many programs would need to walk thorugh the parameters to get the count. Also, in many programming languages with arrays that have length, there isn't any argc parameter, there's just an array with the items.