Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does main(int argc, char* argv[]) take two argument? [duplicate]

Tags:

c

argv

argc

I always thought that argc was required to mark the end of argv but I just learned that argv[argc] == NULL by definition. Am I right in thinking that argc is totally redundant? If so, I always thought C made away with redundancy in the name of efficiency. Is my assumption wrong or there's a historic reason behind this? If the reason is historic, can you elaborate?

like image 344
elik Avatar asked Aug 13 '15 23:08

elik


2 Answers

History.

Harbison & Steel (5th Edition, 9.9 "The main program") says the following:

Standard C requires that argv[argc] be a null pointer, but it is not so in some older implementations.

like image 115
Michael Burr Avatar answered Nov 20 '22 21:11

Michael Burr


Here's the history.

In first edition UNIX, which predates C, exec took as arguments a filename and the address of a list of pointers to NUL-terminated argument strings terminated by a NULL pointer. From the man page:

sys exec; name; args      / exec = 11.
name: <...\0>
...
args: arg1; arg2; ...; 0
arg1: <...\0>
...

The kernel counted up the arguments and provided the new image with the arg count followed by a list of pointers to copies of the argument strings, at the top of the stack. From the man page:

sp--> nargs
      arg1
      ...
      argn

arg1: <arg1\0>
...
argn: <argn\0>

(The kernel source is here; I haven't looked to see if the kernel actually wrote something after the pointer to the last argument.)

At some point, up through the 6th edition, the documentation for exec, execl, and execv began to note that the kernel placed a -1 after the arg pointers. The man page says:

Argv is not directly usable in another execv, since argv[argc] is -1 and not 0.

At this point, you could argue that argc was redundant, but programs had, for some time, been using it rather than looking through the argument list for -1. For example, here's the beginning of cal.c:

main(argc, argv)
char *argv[];
{
    if(argc < 2) {
        printf("usage: cal [month] year\n");
        exit();
    }

In 7th edition, exec was changed to add a NULL pointer after the argument strings, and this was followed by a list of pointers to the environment strings, and another NULL. The man page says:

Argv is directly usable in another execv because argv[argc] is 0.

like image 25
Mark Plotnick Avatar answered Nov 20 '22 22:11

Mark Plotnick