1

I'm reading K&R and have a problem here. I don't know how this function is changing the value of the calling variable. Shouldn't this be call by value, not call by reference since to[] and from[] aren't explicity declared as pointers? The value of foo is changed to "Testing".

#include <stdio.h>

void copy(char to[], char from[]) {
    int i = 0;
    while ((to[i] = from[i]) != '\0') i++;
}

int main() {
    char foo[] = "";
    char bar[] = "Testing";
    copy(foo, bar);
    printf("%s\n", foo);
    return 0;
} 

Also, why isn't this arr_alter function changing the value of test_arr? It seems that looping through each element in the array changes the value of the calling variable yet this does not.

#include <stdio.h>

void arr_alter(char arr[]) {
    arr = "Changed";
}

int main() {
    char test_arr[] = "Testing";
    arr_alter(test_arr);
    printf("%s\n", test_arr);
    return 0;
} 

In short, why is function #1 treating the arguments as pointers while function #2 is not?

I'm a bit confused, all help would be greatly appreciated.

Hello
  • 113
  • 3
  • 11
  • This [C FAQ](http://c-faq.com/aryptr/aryparmasgn.html) may help you understand. Your parameters are treated like pointers by the compiler. – clcto Aug 18 '15 at 20:34
  • 2
    Undefined behavior. Your first example tries to write outside the bounds of array foo, which is only one character long. – FredK Aug 18 '15 at 20:35
  • 1
    possible duplicate of [Difference between passing array and array pointer into function in C](http://stackoverflow.com/questions/5573310/difference-between-passing-array-and-array-pointer-into-function-in-c) – ecatmur Aug 18 '15 at 20:35
  • 1
    With `arr = "Changed"` you seem to be thinking of strings as things that can be passed around and assigned as easily as ints. It doesn't work that way in C -- strings are data structures. The syntax in `char test_arr[] = "Testing";` looks like a simple assignment, but it really isn't. It is just syntactic sugar for initializing an array and can only be done once. You can't subsequently directly use `=` to change that char array to hold a different string. – John Coleman Aug 18 '15 at 20:44

3 Answers3

4

Arrays are passed as pointers, by value.

You can take

void copy(char to[], char from[])

as equivalent to

void copy(char * to, char * from)

The difference between the two cases is that the first case dereferences the pointer with the array element operator [].
The second case does not do this, it overwrites the passed pointer. But the pointer was passed by value, so neither the array content nor the passed pointer of the caller change.

alain
  • 11,939
  • 2
  • 31
  • 51
2

First of all the first program has undefined behaviour. Array foo is defined as having only one element (the terminating zero of the "empty" string literal)

char foo[] = "";

However you are going to copy string "Testing" in the array.

copy(foo, bar);

This results in overwritting the memory that does not belong to array foo.

Array foo should be enough large to be able to accomodate string "Testing".

For example

char foo[8];

According to the C Standard (6.7.6.3 Function declarators (including prototypes))

7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation....

On the other (6.3.2.1 Lvalues, arrays, and function designators)

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

Thus in this function declaration

void copy(char to[], char from[]);

parameters to and from are adjusted to pointers. So this function declaration is equivalent to the following function declaration

void copy(char *to, char *from);

and the both declare the same one function.

You may write in the program the both declarations. For example

#include <stdio.h>

void copy(char to[], char from[]);
void copy(char *to, char *from);

void copy(char to[], char from[]) {
    int i = 0;
    while ((to[i] = from[i]) != '\0') i++;
}
//...

but the definition of the function shall be only one.

And in this function call

copy(foo, bar);

according to the second quote from the Standard arrays foo and bar are converted to pointers to their first elements.

As for the function from the second program then function parameters are its local variables. A function deals with copies of its arguments. So any changes of a copy of an argument do not influence on the argument itself.

You can imagine the definition of function arr_alter and its call the following way

arr_alter(test_arr);

//...

void arr_alter( /*char arr[] */) {
    char *arr = test_arr;

    arr = "Changed";
}

After exiting the function its local variable arr will be destroyed. Variable test_arr will not be changed and moreover arrays have no the assignment operator. You can not reassign an array such a way.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

char to[] and char from[] is the equivalent to assigning a char ptr to the first element of the array.

Say you had char s[10]= "hello"; print(s);

Is the same as

print(&s[0]);

The address of the first slot in the array.

Joey
  • 203
  • 1
  • 11