Question

In the C program below, I don't understand why buf[0] = 'A' after I call foo. Isn't foo doing pass-by-value?

#include <stdio.h>
#include <stdlib.h>

    void foo(char buf[])
    {
      buf[0] = 'A';
    }

    int main(int argc, char *argv[])
    {
      char buf[10];

      buf[0] = 'B';
      printf("before foo | buf[0] = %c\n", buf[0]);
      foo(buf);
      printf("after foo | buf[0] = %c\n", buf[0]);

      system("PAUSE"); 
      return 0;
      }

output:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A'
Was it helpful?

Solution

void foo(char buf[])

is the same as

void foo(char* buf)

When you call it, foo(buf), you pass a pointer by value, so a copy of the pointer is made.

The copy of the pointer points to the same object as the original pointer (or, in this case, to the initial element of the array).

C does not have pass by reference semantics in the sense that C++ has pass by reference semantics. Everything in C is passed by value. Pointers are used to get pass by reference semantics.

OTHER TIPS

an array is just a fancy way to use a pointer. When you pass buf to the function, you're passing a pointer by value, but when you dereference the pointer, you're still referencing the string it points to.

Array as function parameter is equivalent to a pointer, so the declaration

void foo( char buf[] );

is the same as

void foo( char* buf );

The array argument is then decayed to the pointer to its first element.

Arrays are treated differently than other types; you cannot pass an array "by value" in C.

Online C99 standard (draft n1256), section 6.3.2.1, "Lvalues, arrays, and function designators", paragraph 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.

In the call

foo(buf);

the array expression buf is not the operand of sizeof or &, nor is it a string literal being used to initialize an array, so it is implicitly converted ("decays") from type "10-element array of char" to "pointer to char", and the address of the first element is passed to foo. Therefore, anything you do to buf in foo() will be reflected in the buf array in main(). Because of how array subscripting is defined, you can use a subscript operator on a pointer type so it looks like you're working with an array type, but you're not.

In the context of a function parameter declaration, T a[] and T a[N] are synonymous with T *a, but this is only case where that is true.

*char buf[] actually means char ** so you are passing by pointer/reference. That gives you that buf is a pointer, both in the main() and foo() function.

Because you are passing a pointer to buf (by value). So the content being pointed by buf is changed.

With pointers it's different; you are passing by value, but what you are passing is the value of the pointer, which is not the same as the value of the array.

So, the value of the pointer doesn't change, but you're modifying what it's pointing to.

arrays and pointers are (almost) the same thing.

int* foo = malloc(...)

foo[2] is the same as *(foo+2*sizeof(int))

anecdote: you wrote

int main(int argc, char *argv[])

it is also legal (will compile and work the same) to write

int main(int argc, char **argv)

and also

int main(int argc, char argv[][])

they are effectively the same. its slightly more complicated than that, because an array knows how many elements it has, and a pointer doesn't. but they are used the same.

in order to pass that by value, the function would need to know the size of the argument. In this case you are just passing a pointer.

You are passing by reference here. In this example, you can solve the problem by passing a single char at the index of the array desired.

If you want to preserve the contents of the original array, you could copy the string to temporary storage in the function.

edit: What would happen if you wrapped your char array in a structure and passed the struct? I believe that might work too, although I don't know what kind of overhead that might create at the compiler level.

please note one thing,

declaration

void foo(char buf[])

says, that will be using [ ] notation. Not which element of array you will use.

if you would like to point that, you want to get some specific value, then you should declare this function as

void foo(char buf[X]); //where X would be a constant.

Of course it is not possible, because it would be useless (function for operating at n-th element of array?). You don't have to write down information which element of array you want to get. Everything what you need is simple declaration:

voi foo(char value);

so...

void foo(char buf[])

is a declaration which says which notation you want to use ( [ ] - part ), and it also contains pointer to some data.

Moreover... what would you expect... you sent to function foo a name of array

foo(buf);

which is equivalent to &buf[0]. So... this is a pointer.

Arrays in C are not passed by value. They are not even legitimate function parameters. Instead, the compiler sees that you're trying to pass an array and demotes it to pointer. It does this silently because it's evil. It also likes to kick puppies.

Using arrays in function parameters is a nice way to signal to your API users that this thing should be a block of memory segmented into n-byte sized chunks, but don't expect compilers to care if you spell char *foo char foo[] or char foo[12] in function parameters. They won't.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top