C is parsed without looking ahead. You could write a single-pass C compiler (not the most useful thing, but the language was designed with this in mind). When the compiler sees the call to printArray
, i.e. the line printArray(list, 5);
, it doesn't know yet what printArray
's real declaration is - it hasn't read it yet. But it has to do something with that call, and instead it makes a guess: the compiler implicitly declares, at that moment, the function as-if you had the following declaration:
int printArray();
In C, this declaration really means
int printArray(...);
And thus, the call to printArray
is generated with such an implicit declaration - the function is called as if it was a variadic function. But it isn't a variadic function. You later attempt to define it in an incompatible way, as:
void printArray(int [], int);
This is not allowed and triggers an error: in C, all the declarations must agree with the definition. C allows multiple declarations - they are not an error, as long as they all agree. In your case they didn't: the implicit one didn't match the explicit one that came later.
There are two ways of fixing this error:
Declare void printArray(int list[], int size);
before the point of use, e.g. before main
. You can still define it later - after main
.
Change the signature of printArray
to match what the compiler implied, i.e. printArray(...) { ... }
. The only problem is: such a signature would be useless. You can pass whatever arguments you want into that function, but there's no way to actually use them from inside the function. That variadic argument mechanism of C requires at least one named argument. So no luck there. A minimum viable printArray
function with variadic arguments could look as follows - and of course then it's not defined as printArray(...)
anymore, so the compiler would raise the error you see due to the mismatch of implicit declaration and definition, and you're back to square one.
void printArray(int list[], ...)
{
va_list args;
va_start(args, list);
int count = va_arg(args, int);
for (int i = 0; i < count; ++i) printf("%d ", list[i]);
printf("\n");
va_end(args);
}
The problem is in va_start
: you have to pass it the first named argument to the function. With a signature like printArray(...)
, there are no named arguments, and thus you can't use va_start
, and there's no way of accessing any arguments passed to such function from the inside of it - not while depending on Standard (portable) C. On various architectures there are non-portable "hacks" to bypass this issue, but they are not recommended at all.
Note: If you want to declare a function with no arguments in C, it should be declared as:
int myFunction(void); /* <- like this, not like -> */ int myFunction();
To add to the potential confusion, C++ sees things differently: there, the int foo(void)
is redundant, since it interprets int foo()
as a function taking no parameters, and not as int foo(...)
like C would.