0

The main method argument uses an undefined array argv[]

int main(int argc, char *argv[])
{
 .... Do stuff....
}

Why is it undefined arrays are only allowed in the main() method?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
duper21
  • 399
  • 3
  • 10

4 Answers4

2

In fact this declaration

int main(int argc, char *argv[])

is equivalent to

int main(int argc, char **argv)

It is the host environment that supplies an array of strings and passes the pointer to the first string in the array as an argument for the parameter argv.

From the C Standard (5.1.2.2.1 Program startup)

— 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

As for the comment

The argv array has no size, how is this possible?

then a function parameter declared as an array of type T is adjusted to pointer to T.

So for example these function declarations

void f( int a[100] );
void f( int a[10] );
void f( int a[] );

declare the same one function and the all declarations are adjusted to the declaration

void f( int *a );

The same way when an argument of an array type is passed to a function then the array is implicitly converted to pointer to its first element.

So for example the function above can be called like

int a[100];
f( a );

or

int a[10];
f( a );

or

int *a;
f( a );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Would it be correct to say arrays can be declared without size in functions as they will decay into a pointer which is why char *argv[] is allowed? – duper21 Aug 13 '19 at 18:46
  • It took me a while to understand but I honestly can not thank you enough – duper21 Aug 13 '19 at 18:47
  • @druper21, No, it is *not* correct to say that arrays can be declared without size in functions. Although a fine distinction, function parameters declared with array syntax, whether with or without bounds, are pointers, not arrays. This is their inherent meaning, not the result of automatic conversion (a.k.a. "decay"), but it does match up with array decay in the caller. Arrays without *explicit* size can otherwise be declared inside functions only if they have an accompanying initializer to establish their size implicitly, or if they have linkage. – John Bollinger Aug 13 '19 at 19:09
  • @JohnBollinger To clarify what do you mean by "an accompanying initializer to establish their size implicitly, or if they have linkage"? – duper21 Aug 13 '19 at 19:21
  • @duper21, I have discussed this in more depth, especially the initializer part, in my own answer. The linkage bit pertains to the rarely-exercised alternative of (re)declaring an external variable inside a function, by including the keyword `extern` in its declaration. External variables are sometimes colloquially called "global", but that's not the technical term for them in C, and it can be taken to have implications that don't in fact hold in C. – John Bollinger Aug 13 '19 at 19:50
1

Nothing is special about main here. An array declaration such as char *argv[] or int example[] has incomplete type, which is valid in certain contexts but not others. However, in the declaration of arguments to a function, the final type cannot be an array type; the array notation acts as a stand-in for a pointer to the first member of an array of that type. The actual type of argv in main is char **.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • So char *argv[] declared by its own cannot exist but can in a function as it decays into **argv? – duper21 Aug 13 '19 at 18:39
1

Why is it undefined arrays are only allowed in the main() method?

By "undefined arrays" you appear to mean arrays with unspecified size. There are several different cases to consider.

  1. Function parameters declared with array syntax in fact do not have array type after all, whether a bound is specified or not. Rather, such a parameter has a pointer type. It is not necessary to specify a bound (for the first dimension), and if one is specified then it is insignificant. This matches up with the automatic conversion from array to pointer ("decay") that would happen in the caller if the corresponding argument were an array, but in the called function the parameter is a pointer, a whole pointer, and nothing but a pointer.

    This applies to any function, not just main().

  2. Any variable can be declared at file or block scope as an array without an explicit bound but with an initializer; in this case, the array bound is established implicitly as the minimum necessary to accommodate all elements initialized by the initializer.

    Example:

    int some_primes[] = { 2, 3, 5, 7, 11 };  // dimension 5
    
  3. A file-scope (outside any function) variable or one that otherwise has linkage can be declared as an array without explicit bounds and without an intializer to establish the bound implicitly. The type of such a variable is "incomplete" until and unless another, compatible declaration of the same variable completes it by providing the bound, but many array operations can be performed on it at points in the source where it remains incomplete.

  4. Only local variables of array type and without initializers must be declared with an explicit bound. ("Local variables" are those declared at block scope and with no linkage.) These are a fairly common case, though, so I suppose the need to declare a size for them was part of the inspiration for the question.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • If function parameters declared with array syntax do not have array type **at all**, why does `#include ` / `void foo(char x[printf("Hello, world.\n")]) {}` / `int main(void) { foo(0); }` print “Hello, world.”? Some aspect of the array type must be in there. (This was tested using Apple LLVM 10.0.1 with clang-1001.0.46.4.) – Eric Postpischil Aug 13 '19 at 22:46
  • All that demonstrates, @EricPostpischil, is that the dimension expression is evaluated when the function is called. That does not in any way make `x` the identifier of an array. – John Bollinger Aug 13 '19 at 23:12
  • How can the dimension expression be evaluated when the parameter does not have array type **AT ALL**? Pointers do not have dimensions. If there is a dimension expression, there must be some aspect of an array type. Telling people the parameter does not have array type **AT ALL** conflicts with the facts. – Eric Postpischil Aug 13 '19 at 23:33
  • @EricPostpischil, the dimension expression is part of the declaration of the parameter. That is orthogonal to what type is thereby declared for the parameter by that syntax in that context. A function parameter declaration expressed using that syntax declares the parameter as a pointer, not an array. – John Bollinger Aug 13 '19 at 23:39
  • No. There are multiple steps. The parameter is first declared as an array. It is subsequently adjusted to be a pointer. But, as demonstrated, the array declaration does not completely vanish. The phrase “at all” means “in any way” or “to any extent/” But it is clear there **is** a way in which the declaration of the array as a parameter has a persistent effect. This means the statement that it does not have array type “at all” is false. If you are going to qualify statements with absolutes like “at all,” you should ensure they are true. This one is not. – Eric Postpischil Aug 14 '19 at 00:17
  • If you had just said a parameter declared as an array ends up with a pointer type and not an array type, I would not be harping on this. But when you emphasize it with “at all,” then it should be correct. – Eric Postpischil Aug 14 '19 at 00:21
  • Very well, @EricPostpischil, I have adjusted the wording to "after all" instead of "at all", which to me, in the particular usage here, has no significant difference in meaning, but which I hope you find less objectionable. – John Bollinger Aug 14 '19 at 00:39
0

I'm a little confused about this question. argc is the number of commandline arguments passed into the executable. argv is an array of those arguments. Neither are undefined.

Both argc and argv are simply parameter names, and you can change them to whatever you'd like. They are simply called argc and argv by convention.

Michael Bianconi
  • 5,072
  • 1
  • 10
  • 25
  • The second argument argv has no size, how is that possible? – duper21 Aug 13 '19 at 18:13
  • Because the number of elements in the outer dimension of an array which is used as function argument is not necessary for the compiler to know. – Weather Vane Aug 13 '19 at 18:15
  • You only need to specify multidimensional array sizes when using ```char array[n][]```. ```char *array[]``` and ```char **array``` are both fine to use. – Michael Bianconi Aug 13 '19 at 18:15
  • @MichaelBianconi I think you mean `char array[][n]` – Weather Vane Aug 13 '19 at 18:20
  • To rephrase it another way: normally declaring an array without a size such as int example[] is not permitted, so why is char *argv[] permitted – duper21 Aug 13 '19 at 18:21
  • 1
    `*argv[]` is allowed in any function argument list. It is the same as `**argv` in this context. – Eugene Sh. Aug 13 '19 at 18:22
  • 1
    Please see [What is array decaying?](https://stackoverflow.com/questions/1461432/what-is-array-decaying) – Weather Vane Aug 13 '19 at 18:23
  • @EugeneSh. I know it is allowed but I am hoping to understand why it is allowed. – duper21 Aug 13 '19 at 18:23
  • 2
    @duper21 Your question implies that you believe it is only allowed in `main`. If you mean anything else - please edit the question. – Eugene Sh. Aug 13 '19 at 18:24
  • The only reason for array length in a function argument is so the compiler can compute the address of an array element. C makes no restriction on indexing an array so apart from that it does not care what its length is. – Weather Vane Aug 13 '19 at 18:25
  • ...you need to fully specify an array where it is defined so the correct memory can be allocated, but there is no allocation for a function argument. The function only receives a pointer, not an actual array. – Weather Vane Aug 13 '19 at 18:28
  • That is because it is simply a pointer to an array of char pointers. The count of elements is informed in the first parameter, so you can access from argv[0] to argv[argc]. The first argument (argv[0]) will always contain the name of program being executed and if the program was called with command line parameters it wil be available from argv[1] to argv[argc]. – Fabiano Salles Aug 13 '19 at 18:32