8
#include<stdio.h>    

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

Result in this error:

array type 'int [3]' is not assignable

I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer. b should just point to the address of a. Why isn't this doable?

Dan
  • 577
  • 1
  • 3
  • 9
  • 3
    Because, that's not how it's done in C. Use a loop or `memcpy`, for example. – Fiddling Bits Jul 09 '20 at 14:44
  • 2
    you can use a pointer for `b`: `int *b = a;` – Serge Jul 09 '20 at 14:45
  • 1
    Arrays are not pointers. Arrays' names decay to pointers in function calls and such. That's it. As for why C doesn't just automatically copy all the elements for you, because it wasn't designed that way originally, and the language evolves glacially. Plain arrays are still arguably one of the main oddities in C and C++. – underscore_d Jul 09 '20 at 14:46

5 Answers5

8

"I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer."

"b should just point to the address of a. Why isn't this doable?"

You seem to confuse here something. b isn't a pointer. It is an array of three int elements.

b = a;

Since b is used here as lvalue in the assignment, it is taken as of type int [3], not int *. The pointer to decay rule takes no place in here for b, only for a as rvalue.

You cannot assign an array (here b) by a pointer to the first element of another array (here a) by using b = a; in C.

The syntax doesn't allow that.

That's what the error

"array type 'int [3]' is not assignable"

is saying to you for b.

Also you seem to be under the misunderstanding that the pointer to decay rule means that an array is anyhow converted to a pointer object, which can in any manner store addresses of locations of different objects.

This is not true. This conversion is only happening in a very implicit kind of way and is subject of this SO question:

Is the array to pointer decay changed to a pointer object?


If you want to assign the values from array a to the array b, you can use memcpy():

memcpy(b, a, sizeof(a));
7

I know arrays are lvalues and are not assignable but in this case, all the compiler has to do is reassign a pointer. b should just point to the address of a. Why isn't this doable?

Because b isn't a pointer. When you declare and allocate a and b, this is what you get:

+---+
| 1 | a[0]
+---+
| 2 | a[1]
+---+
| 3 | a[2]
+---+
 ...
+---+
| 4 | b[0]
+---+
| 5 | b[1]
+---+
| 6 | b[2]
+---+

No space is set aside for any pointers. There is no pointer object a or b separate from the array elements themselves.

C was derived from an earlier language called B, and in B there was a separate pointer to the first element:

   +---+
b: | +-+--+
   +---+  |
    ...   |
     +----+
     |
     V
   +---+
   |   | b[0]
   +---+
   |   | b[1]
   +---+
    ...
   +---+
   |   | b[N-1]
   +---+

When Dennis Ritchie was developing C, he wanted to keep B's array semantics (specifically, a[i] == *(a + i)), but he didn't want to store that separate pointer anywhere. So instead he created the following rule - unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array, and that value is not an lvalue.

This has several practical effects, the most relevant here being that an array expression may not be the target of an assignment. Array expressions lose their "array-ness" under most circumstances, and simply are not treated like other types.

Edit

Actually, that misstates the case - array expression may not be the target of an assignment because an array expression is not a modifiable lvalue. The decay rule doesn't come into play. But the statement "arrays are not treated like other types" still holds.

End Edit

The upshot is that you cannot copy the contents of one array to the other using just the = operator. You must either use a library function like memcpy or copy each element individually.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1
    Frankly even if you use pointers to blocks of memory, you also can't "copy the contents of one array to the ther by justing using `=`". You still need to duplicate the actual underlying memory. – Bartek Banachewicz Jul 10 '20 at 07:27
5

Others already explained what you got wrong. I'm writing that answer to explain that actually the compiler could assign an array to another, and you can achieve the same effect with minimal change to your sample code.

Just wrap your array in a structure.

#include <stdio.h>

int main(){
  struct Array3 {
    int t[3];
  };
  struct Array3 a = {{1,2,3}};
  struct Array3 b = {{4,5,6}};
  a = b;
  printf("%d %d %d", a.t[0], a.t[1], a.t[2]);
  return 0;
 }

Once the array is wrapped in a structure copying the array member of the structure works exactly as copying any other member. In other words you are copying an array. This trick is usefull in some cases like when you really want to pass an array to a function by copying it. It's slightly cleaner and safer than using memcopy for that purpose, which obviously would also work.

Henceforth the reason why it is not allowed for top level arrays is not because the compiler can't do it, but merely because that's not what most programmers usually wants to do.

Usually they just want to decay the array to a pointer. Obviously that is what you thought it should do, and direct copy of array is likely forbiden to avoid specifically that misunderstanding.

kriss
  • 23,497
  • 17
  • 97
  • 116
  • This is example is useful and absolutely relevant. Nonetheless, an array cannot be assigned by another array, so your second sentence is incorrect/wrong. You show to assign a structure object by another one, which is something quite different than to assign arrays. – RobertS supports Monica Cellio Jul 09 '20 at 15:25
  • @RobertSsupportsMonicaCellio: copying an array if it were allowed would be like copying any other kind of object: copying some chunk of memory from some address to another. For a long time the example I gave of structure assigment was also forbidden (Was it introduced by C89 ?). While copying that structure for all practical purpose it copies all members including the wrapped array. Of course it's some underlying memcopy, but the same is totally possible for arrays. Except it would be confusing. – kriss Jul 09 '20 at 16:12
  • The most confusing thing would probably be parameter passing, because even when you provide a size this is a case where arrays are always decayed to pointers. It would be hard to fix that to allow copying of arrays through assigment without breaking much code. – kriss Jul 09 '20 at 16:14
  • What I wanted to say is just that the assignment (`x = y`) of arrays isn't possible in C and hinted at the wording "*that actually you can assign an array to another*" is incorrect if you see it in a strict kind of way. It is the wording what I hinted, not your answer in general. If you edit that, I'll give an upvote. – RobertS supports Monica Cellio Jul 09 '20 at 16:49
  • 1
    @RobertSsupportsMonicaCellio: I slightly changed the working. – kriss Jul 09 '20 at 17:38
2

From The C Programming Language:

The array name is the address of the zeroth element.

There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable. But an array name is not a variable.

My understanding is that the array name is a constant, so it can't be assigned.

cd-00
  • 585
  • 5
  • 10
1

The variable b in your code is allocated on the stack as 3 consecutive ints. You can take the address of b and store it in a variable of type int*. You could assign a value to it if you allocate the array on the heap and store only the pointer to it on the stack, in this case you could, in fact, be able to change the value of the pointer to be the same as a.

Fullfungo
  • 345
  • 2
  • 13