Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't C assign an array directly but can assign an array in a struct?

Tags:

c

This code doesn't work:

int main() {
    int arr1[10];
    int arr2[10];

    arr2 = arr1;
    return 0;
}

But this works:

struct foo {
    int arr[10];
};

int main() {
    struct foo f1;
    struct foo f2;

    f2 = f1;
    return 0;
}

But in my opinion, they do the same thing: just copy an array to another array.

like image 949
wonter Avatar asked Aug 24 '19 04:08

wonter


2 Answers

A consequence of the historical development of C is that you cannot refer to arrays directly.

In arr2 = arr1;, both arr2 and arr1 name an array. But there is a rule in C that says when an array is used in an expression, it is automatically converted to a pointer to its first element, with certain exeptions.1 C is certainly capable of copying one array to another, as with memcpy(arr2, arr1, sizeof arr2);. The problem is there is simply no way of referring to the array in an assignment statement.

This automatic conversion of arrays was made to provide convenience for accessing elements of array and working with arrays in the ways that were used when the C language was first being developed. It was not anticipated there would be a need to refer to the entire array as a whole object, and nothing was built into the language for that. (Even today, it is not necessary—there are few operations we want perform on an array as a single object, other than copying it.)

Early C implementations also would not let you copy structures by assignment. C was a fairly basic language, providing just simple operations, and copying entire structures would have been a fancy thing. Later, the ability to copy structures was added.

In f2 = f1;, f2 and f1 refer to the structures, and there is no rule about them being automatically converted to anything, as there is for the arrays.

So the problem is simply a matter of being able to express the desired operation.

Footnote

1 The rule is in C 2018 6.3.2.1 3, and the exceptions are when the array is the operand of sizeof or unary & or is a string literal that is used to initialize an array (as in char x[] = "abc";"abc" is a string literal, which is an array).

like image 134
Eric Postpischil Avatar answered Oct 31 '22 04:10

Eric Postpischil


Here

int main() {
    int arr1[10];
    int arr2[10];

    arr2 = arr1;
    return 0;
}

arr2 = arr1; doesn't work because arr2 is array and array name itself base address i.e const & you can't change that address i.e arr2 can not point to any other address. By doing arr2 = arr1; you are trying to change arr2 base address which is not possible. While here

f2 = f1; /* structure member copy, f2 is structure variable and it can assigned with another structure variable f1 */

f2 is a structure variable and by doing f2 = f1; the f1 members gets copied into f2.

But in my opinion, they do the same thing: just copy an array to another array.

yes, but compiler won't allow to perform first one arr2 = arr1 due to the fact that you can't change the base address of arr2 while in another f2=f1 f1 structure variable members gets copied to f2 member by member and since f2 is not an array, its possible.

Paragraph from 6.3.2.1 Lvalues, arrays, and function designators

  1. When an object is said to have a particular type, the type is specified by the lvalue used to designate the object. *A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const- qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const- qualified type.

Here

arr2 = arr1;

the lvalue operand arr2 is not modifiable.

Another para about the same which tells about decaying

  1. Except when it is the operand of the sizeof operator, the _Alignof 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.
like image 39
Achal Avatar answered Oct 31 '22 06:10

Achal