BartC said:With function names and arrays, these are effectively passed by
reference in C without needing to use & in the caller or * in the
callee (when using () or  operators).
Referring to the way C handles arrays in function calls as "pass by
reference" glosses over the fact that the behavior is based on rules
that apply to arrays in general. The decay of array expressions
to pointers has nothing specifically to do with function calls;
it applies equally to assignment, initialization, array indexing,
and so forth. The other relevant rule, that an array parameter is
"adjusted" to a pointer parameter, is specific to functions, but
I'd call it a kind of syntactic sugar, not something fundamental
to the semantics of the language as pass-by-reference would be.
Saying that arrays are "passed by reference" has led too many
inexperienced C programmers to assume, quite reasonably, that sizeof
applied to an array parameter should yield the size of the array.
C has pass-by-reference in the same sense that C has linked lists.
It provides tools (pointers) from which you can build code that
has the effect of pass-by-reference, or of linked lists, but it
has neither as a feature of the language.