Q: Does C even have ``pass by reference''?
A: Not really.
Strictly speaking, C always uses pass by value. You can simulate pass by reference yourself, by defining functions which accept pointers and then using the & operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function (by passing a pointer instead, see question 6.4 et al.).
Another way of looking at it is that if an parameter has type, say, int * then an integer is being passed by reference and a pointer to an integer is being passed by value.
Fundamentally, C has nothing truly equivalent to formal pass by reference or C++ reference parameters. (On the other hand, function-like preprocessor macros can provide a form of ``pass by name''.)
See also questions 4.8, 7.9, 12.27, and 20.1.
Additional links: A message of mine further explaining how a function can modify a caller's passed array.
K&R1 Sec. 1.8 pp. 24-5, Sec. 5.2 pp. 91-3
K&R2 Sec. 1.8 pp. 27-8, Sec. 5.2 pp. 95-7
ISO Sec. 220.127.116.11
H&S Sec. 9.5 pp. 273-4