views:

293

answers:

12

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'
+1  A: 

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.

Marcus Johansson
+1  A: 

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

Pablo Santa Cruz
+4  A: 

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.

Nathan Fellman
A: 

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.

tenfour
+11  A: 
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.

James McNellis
Thanks to everyone, especially James, for the answer.Why would anyone use call by value if it doesn't change the input's value?
Kevin
Because you may need a value of something but don't need to change it.
Javier Badia
@Kevin: Because the function may just need the value. Functions without side effects are easier to reason about (not that you'll get very far using C as a functional programming language), and passing by value removes possible side effects.
David Thornley
+1  A: 

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.

Shawn D.
+2  A: 

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.

Nikolai N Fetissov
A: 

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.

baultista
A: 

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.

noisy
A: 

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.

Nathon
+2  A: 

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.

John Bode
+1  A: 

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.

Dustin Getz