If a function has been written for variable number of arguments (e.g. printf), then it is possible to pass a variable number of arguments to a function.
These work with either of two patterns
The Map Pattern
Like printf, an early non optional parameter describes the remaining parameters which have been added. These are then plucked from the stack appropriately.
The terminating pattern
A function can be written to sum a set of parameters, which have some mechanism for detecting the terminator.
int sum( int first_arg, ... );
Where a special token is added to the function to call correctly.
If a function has been written to only accept a fixed number of arguments, you have to pass that number of arguments.
This is because the calling code, and the called code have to agree on how much stack is used. Any difference in this contract, will result in undefined behavior, which can mean a crash, or you program may be exploitable by a malicious actor.
Given that the function has a set number of parameters, you need to supply all of these.
foo()you can't differentiatefoo(10)fromfoo(10, "OK").