Let's look at the "calling" of functions first.
In C, the arguments to a function are typically "by value". Below, after calling sqrt(x)
, the value x
is not changed for sqrt()
received a copy of the value x
, thus never gaining an ability to affect x
.
y = sqrt(x);
// x did not change
printf("%f is the square root of %f\n", y, x);
Array parameters to a function appear to be "by reference". After fgets()
is called, buf
is expected to be altered. fgets()
did not receive a copy of, but a "reference" to the char
array. Thus fgets()
could affect the contents of the array.
char buf[80] = { 0 }; // array 80 of char
printf("Before <%s>\n", buf); // "<>"
fgets(buf, sizeof buf, stdin);
printf("After <%s>\n", buf); // "<Hello World!>"
Let's now look at the "receiving" part: the function.
Function parameters of type double
, int
, struct
types are received by value. The value of f
here is the copy of the x
above. Any changes made to f
do not affect the x
in the calling code.
double sqrt(double f) {
double y;
... // lots of code
return y;
}
Now comes the tricky bit and this is where there is lots of discussion in C.
The parameter s
in fgets()
below was not assigned the buf
above (array 80 of char), instead s
was assigned the pointer type derived from buf
: address of the first element of an buf
. By knowing the address of the array elements of buf
(via s
), fgets()
affects what was printed above.
char *fgets(char * restrict s, int n, FILE * restrict stream) {
// code
s[i] = ThisAndThat();
// code
return s;
}
Let's now see how fgets()
otherwise might be called:
char *p = malloc(80);
*p = '\0';
printf("Before <%s>\n", p); // "<>"
fgets(p, 80, stdin);
printf("After <%s>\n", p); // "<Hello World!>"
In this 2nd example, p
is a "pointer to char". It is passed by value to fgets()
. fgets()
received, via s
, a copy of p
.
The central idea: fgets()
does not know if it received an "address of the first element of an array" or a copy of a "pointer to char". In both cases, it treats s
as a "pointer to char".
Let's assume fgets()
did the following. Before s
being changed, it affects the data pointed to by s
. Then s
, the pointer, changed. s
is a local variable and this assignment does not change the calling routines variables buf
nor p
.
char *fgets(char * restrict s, int n, FILE * restrict stream) {
// lots of code
s[0] = '\0';
// more code
s = NULL;
return s;
}
Note: There are other issues such as passing functions as parameters and encapsulating arrays in structures to consider.