问题
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for(i=1;i<argc;i++)
printf("%s%s", argv[i], (i<argc-1)? " ":"");
printf("\n");
return 0;
}
Given above is a simple C program that outputs command line inputs. Here argc
is the argument counter. argv
is said to be an array that contains arguments. My question is: why does it define as a pointer to a character array instead of a normal array? Also what is the need for defining its zeroth element (argv[0]) as the name by which the program is invoked.
I am a beginner and please explain it high level perspective.
回答1:
argv
is defined as a pointer rather than as an array because there is no such thing as an array parameter in C.
You can define something that looks like an array parameter, but it's "adjusted" to array type at compile time; for example, these two declarations are exactly equivalent:
int foo(int param[]);
int foo(int param[42]); /* the 42 is quietly ignored */
int foo(int *param); /* this is what the above two declarations really mean */
And the definition of main
can be written either as:
int main(int argc, char *argv[]) { /* ... */ }
or as
int main(int argc, char **argv) { /* ... */ }
The two are exactly equivalent (and the second one, IMHO, more clearly expresses what's actually going on).
Array types are, in a sense, second-class types in C. Code that manipulates array almost always does so via pointers to the elements, performing pointer arithmetic to traverse the elements.
Section 6 of the comp.lang.c FAQ explains the often confusing relationship between arrays and pointers.
(And if you've been told that arrays are "really" pointers, they're not; arrays and pointers are distinct things.)
As for why argv[0]
points to the program name, that's just because it's useful. Some programs print their names in error messages; others may change their behavior depending on the name by which they're invoked. Bundling the program name with the command-line arguments was a fairly arbitrary choice, but it's convenient and it works.
回答2:
The char *argv[]
is a pointer that an array of char *
has decayed into. For example, invoking a command like this:
$ ./command --option1 -opt2 input_file
could be viewed as:
char *argv[] = {
"./command",
"--option1",
"-opt2",
"input_file",
NULL,
};
main(4, argv);
So basically there is an array of strings outside main
, and it is passed to you in main
:
char *argv[]
\- --/ ^
V |
| It was an array
|
of strings
Regarding argv[0]
being the invocation command, the reason is largely historical. I don't know what the first person who thought of it thought about, but I can tell at least one usefulness for it.
Imagine a program, such as vim
or gawk
. These programs may install symbolic links (such as vi
or awk
) which point to the same program. So effectively, running vim
or vi
(or similarly gawk
or awk
) could execute the exact same program. However, by inspecting argv[0]
, these programs can tell how they have been called and possibly adjust accordingly.
As far as I know, neither of the programs I mentioned above actually do this, but they could. For example vim
called through a symbolic link named vi
could turn on some compatibility. Or gawk
called as awk
could turn off some GNU extensions. In the modern world, if they wanted to do this, they would probably create scripts that gives the correct options, though.
回答3:
It is not defined as a normal array because in C the size of array elements has to be known at compile time. The size of char *
is known, the size (length) of your arguments is not.
argv[0]
contains the name of the invoked process because it is possible to invoke it by any arbitrary name. e.g. exec
family of calls can specify what it wants and you are allowed to invoke a program via a symlink. argv[0]
allows the program to offer different functionality depending on the invocation name.
回答4:
The questions you ask are really answered best by simply saying its all "by definition". i.e. a set of rules designed and agreed upon by a committee.
Here is what C11 says: (see emphasized sections)
5.1.2.2.1 Program startup
1 The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char argv[]) { / ... */ }
or equivalent;10) or in some other implementation-defined manner.
2 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.
— If the value of argc is greater than zero, the array members argv[0] through
argv[argc-1] inclusive shall contain pointers to strings, which are given
implementation-defined values by the host environment prior to program startup.
The intent is to supply to the program information determined prior to program startup
from elsewhere in the hosted environment. If the host environment is not capable of
supplying strings with letters in both uppercase and lowercase, the implementation
shall ensure that the strings are received in lowercase.
— If the value of argc is greater than zero, the string pointed to by argv[0]
represents the program name; argv[0][0] shall be the null character if the
program name is not available from the host environment. If the value of argc is
greater than one, the strings pointed to by argv[1] through argv[argc-1]
represent the program parameters.
— The parameters argc and argv and the strings pointed to by the argv array shall
be modifiable by the program, and retain their last-stored values between program
startup and program termination.
来源:https://stackoverflow.com/questions/21732633/why-is-argv-argument-vector-in-c-defined-as-a-pointer-and-what-is-the-need-for