4

Let me explain with an example -

#include <iostream>

void foo( int a[2], int b[2] ) // I understand that, compiler doesn't bother about the
                               // array index and converts them to int *a, int *b
{
    a = b ;  // At this point, how ever assignment operation is valid.

}

int main()
{
    int a[] = { 1,2 };
    int b[] = { 3,4 };

    foo( a, b );

    a = b; // Why is this invalid here.

    return 0;
}

Is it because, array decays to a pointer when passed to a function foo(..), assignment operation is possible. And in main, is it because they are of type int[] which invalidates the assignment operation. Doesn't a,b in both the cases mean the same ? Thanks.

Edit 1:

When I do it in a function foo, it's assigning the b's starting element location to a. So, thinking in terms of it, what made the language developers not do the same in main(). Want to know the reason.

Mahesh
  • 34,573
  • 20
  • 89
  • 115
  • Same reason why `sizeof(a)` differs in those locations: I don't know :) – Tugrul Ates Mar 11 '11 at 22:36
  • Array to pointer conversion is tricky. Read this if you feel like it : http://c-faq.com/aryptr/index.html – fouronnes Mar 11 '11 at 22:40
  • 2
    Don't use arrays in C++, unless you have a very good reason to do so. `std::vector<>` will do almost everything you want. – David Thornley Mar 11 '11 at 22:51
  • @David Thornley - Just out of curiosity asked the question, which is a bit related to another post http://stackoverflow.com/questions/5278540/modifying-2d-array-in-a-function/5278595#5278595 – Mahesh Mar 11 '11 at 23:10
  • related [FAQ](http://stackoverflow.com/questions/4810664/) – fredoverflow Mar 12 '11 at 09:34

3 Answers3

9

You answered your own question.

Because these

int a[] = { 1,2 };
int b[] = { 3,4 };

have type of int[2]. But these

void foo( int a[2], int b[2] )

have type of int*.

You can copy pointers but cannot copy arrays.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • 1
    also worth noting that the `a = b` inside the function does not affect the actual arrays outside the function. – Tim Mar 11 '11 at 22:41
  • By the way, to achieve copy semantics with arrays a possible solution is to wrap them in a `struct` or in a class: the default copy constructor & assignment operator will do the trick. But in that case you will probably want to use directly the `std::array` template. – Matteo Italia Mar 11 '11 at 22:41
  • @ybungalobill - When I do it in a function `foo`, it's assigning the `b's` starting element location to `a`. So, thinking in terms of it, what made the language developers not do the same in `main()`. Want to know the reason. Thanks. – Mahesh Mar 11 '11 at 22:42
  • @Matteo: even better: use std::vector. – Yakov Galka Mar 11 '11 at 22:43
  • @ybungalobill: there are cases when heap allocation is overkill, or where you want to specify exactly the (small) size of the array; in those cases (but there are many others) `std::array` are a good alternative to `std::vector`. – Matteo Italia Mar 11 '11 at 22:45
  • 1
    @Mahesh: this syntax came from C, and C language developers though of C as a set of macros for assembly, so from their point of view these were just pointers. Note that in `main` no pointers are involved, so there is nothing to copy, while `f` receives pointers as parameters on the machine level. – Yakov Galka Mar 11 '11 at 22:46
  • @Mahesh: the ubiquitous array-to-pointer decay and the `Type Parameter[]` syntax for function parameters (that is exactly the same as `Type * Parameter`) are artifacts of the transition from B/BCPL to C; have a look at [this paper](http://cm.bell-labs.com/cm/cs/who/dmr/chist.html) for more info. – Matteo Italia Mar 11 '11 at 22:56
1

The answer is in the concept "pass by value", which means that the called function receives copies of the arguments -- which are pointers to ints. So a and b are local copies of those pointers (which don't exist in the caller; they were the results of conversions from the arrays, that is, the addresses of their first elements). It would be no different if you wrote

void foo( int aparam[2], int bparam[2] )
{
    int* a = aparam;
    int* b = bparam;

    a = b ;
}

Dennis Ritchie has acknowledged that the array syntax for parameters is a wart on the language, and was only there to ease conversion of B programs -- ancient history! It also had a deleterious effect on the design of C++, because arrays cannot be passed by value. This syntax is a constant source of confusion. So ... don't use it; pretend it's not legal. If everyone does that, it can fade away and maybe in a few decades can be given proper semantics.

Update: For more information on call-by-value (the only form of call in C and Java; see my comments below), call-by-reference (added in C++), and other evaluation strategies, see http://en.wikipedia.org/wiki/Evaluation_strategy

Jim Balter
  • 16,163
  • 3
  • 43
  • 66
  • **pass by value** isn't a correct term to use, when arrays are passed. Its **pass by reference**. – Mahesh Mar 11 '11 at 23:05
  • 1
    @Mahesh You're quite mistaken. It is possible for arrays, like anything else, to be passed either by reference or by value; the fact that you are not familiar with languages in which arrays can be passed by value does not mean that they can't be. If it weren't for the C array-parameters-are-pointers botch, it would be quite possible to pass small arrays on the stack, just as structs can be passed on the stack. This is quite obvious if you just think about it for a moment. – Jim Balter Mar 12 '11 at 00:02
  • @Mahesh P.S. It is common for people to be confused by the fact that references are passed by value in languages like Java, which is a pure pass-by-value system, or in C by passing pointers. Pass-reference-by-value is a quite different thing from pass-by-reference. For a detailed discussion of this point, see http://javadude.com/articles/passbyvalue.htm – Jim Balter Mar 12 '11 at 00:07
-2

In the main function
a and b are constant pointers actually they are the address of the first elements. They are like l-value. you cannot copy to l-value but you can change the value of the integers they point to.

In the foo function
a and b are pointers. so you can change their values.

Bander
  • 341
  • 2
  • 5
  • `a` and `b` are **not** constant pointers in the main function, they are **arrays**. Pointers and arrays are not the same thing. The immediately obvious difference is that the value of `sizeof(a)` and `a+n` are not what they would be if `a` were a pointer. – Jim Balter Mar 11 '11 at 23:07
  • Arrays are not pointers -- read the standard. and I have no idea what your equation is supposed to signify, but `int a[2]` is allocated on the stack and is destroyed when exiting the scope, whereas `new int[]` is on the heap ... and your second `a` is a array of pointers to `int`. – Jim Balter Mar 12 '11 at 07:46
  • Arrays are constant pointers. "int a[2]" is the same as "int const * a[] = new int[2]". and regarding sizeof, it's because the compiler keeps track of all array and deals within itdifferently – Bander Mar 12 '11 at 08:19
  • @jim, just to clarify . I know that int a[] will be allocated in stack whereas int const * a[] = new int[2] will be in heap .. that's an essential concept in c++ ... i was just trying to simplify the reason . anyway thinks – Bander Mar 12 '11 at 17:22