This a problem of terminology, mostly.
An "object" (I use the term as designing "a chunk of RAM") is passed by value when the called function gets a copy of the chunk. It is passed by reference when the called function gets a way to access the one and only chunk.
Consider this:
void f(int x)
{
x = 42;
}
void g()
{
int y = 54;
f(y);
// here "y" still has value 54
}
Here, the function f()
modifies x
, but that is its own x
, a variable which contains a copy of the contents of the y
variable of g()
. What f()
does with its x
does not impact what the y
of g()
contains. The variable is then passed by value.
C++ has a notion of reference which goes like this:
void f(int& x)
{
x = 42;
}
void g()
{
int y = 54;
f(y);
// here "y" now has value 42
}
Here, the special construction (with the "&
") instructs the C++ compiler to play some hidden tricks so that the x
known by f()
is actually a kind of alias on the y
variable used by g()
. There is only one variable: the x
and the y
designate the same chunk of RAM. The variable is here passed by reference.
Now, consider a "C string". In C (and C++), a string is just a bunch of char
values, the last of which having value 0 (this is the conventional string terminator). The code does not handle strings directly; it uses pointers. A pointer is a value which actually designates an emplacement in RAM. The pointer is not the string; the pointer is a kind of number (usually on 32 or 64 bits, it depends on the processor type and the operating system) which tells where in RAM is the first char
of the string. So when you call strcpy()
you actually give it pointers (one for the destination buffer, one for the source string). Those pointers are unmodified: the source string and the destination buffers are not moved in the process; only the contents of the string are copied into the destination buffer.
Hence, strcpy()
needs not have access to the variables which contain the pointers in the caller code. strcpy()
only needs to know where the destination buffer and the source strings are in RAM. Giving a copy of the pointer values to strcpy()
is enough. Hence, those pointers are passed by value.
Note that in the presence of pointers, there are two objects to consider: the variable which contains the pointer, and the chunk of RAM which is pointed to. The pointer itself is passed by value (strcpy()
receives its own copy of the variable which contains the pointer to the destination buffer). We can say that the pointed-to chunk of RAM (the destination buffer) is "passed by reference" since it is not duplicated in the process and the called function (strcpy()
) can modify it. The point here is that the term "reference" has two distinct meanings:
The C++ syntax meaning: "reference" designates the special construction with the "&
" that I have described above.
The language theory formal meaning: "reference" designates a way by which a value is indirectly designated, so that caller and callee may access the same chunk of RAM under distinct names. With that meaning, passing by value a pointer to a called function is equivalent to passing by reference the chunk of RAM to which the pointer points.
A C++ "reference" (first meaning) is a syntaxic way to pass "by reference" (second meaning) a variable.