27

I've tried to google this and have read:

But they all state the obvious: you can't assign to arrays because the standard says so. That's great and all, but I want to know why the standard doesn't include support for assigning to arrays. The standard committee discusses things in detail, and I'd be surprised if they never discussed making arrays assignable. Assuming they've discussed it, they must have some rationale for not letting arrays be assigned to.

I mean, we can put an array in a struct and assign to the struct just fine:

struct wrapper
{
    int array[2];
};

struct wrapper a = {{1, 2}};
struct wrapper b = {{3, 4}};
a = b; // legal

But using an array directly is prohibited, even though it accomplishes effectively the same thing:

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

What is the standard committee's rationale for prohibiting assigning to arrays?

Community
  • 1
  • 1
Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • i think the answer in http://stackoverflow.com/questions/14826952/why-cant-arrays-of-same-type-and-size-be-assigned would give you enough reason – Daniel A. White Jan 10 '15 at 21:35
  • To be clear: You are not looking for any old objection to assigning arrays, you want *specifically* documentation of the standards committee considering and rejecting assignment of arrays. Is that right? – Aaron Golden Jan 10 '15 at 21:38
  • @DanielA.White So it's because of pointer decay? – sashoalm Jan 10 '15 at 21:38
  • 5
    @People thinking this is primarily opinion based: it's not; I'm curious about historical discussions the standard committee has had (assuming they have), and how those discussions concluded to not support this. – Cornstalks Jan 10 '15 at 21:38
  • @AaronGolden: yes. Similar to [one of my previous questions](http://stackoverflow.com/questions/15129263/is-there-a-non-atomic-equivalent-of-stdshared-ptr-and-why-isnt-there-one-in), where [Howard Hinnant was able to provide exact details of the standards committee discussing and rejecting a proposal](http://stackoverflow.com/a/15140227/1287251). – Cornstalks Jan 10 '15 at 21:40
  • 2
    Some earlier C _did_ allow for array assignments in select situations. http://stackoverflow.com/questions/18412094/a-legal-array-assignment-is-it-possible/18412972` – chux - Reinstate Monica Jan 10 '15 at 21:51
  • @chux: As far as I can tell, gcc permits array assignments in some situations due to a bug. I don't believe any earlier version of the C language permitted array assignments. – Keith Thompson Jan 21 '15 at 02:28
  • @Cornstalks: Did one of the answers answer your question? – Keith Thompson Jan 21 '15 at 02:29

6 Answers6

20

In C, assignment copies the contents of a fixed-size object to another fixed-size object. This is well defined and fairly straightforward to implement for scalar types (integers, floating-point, pointers, complex types since C99). Assignment of structs is nearly as simple; larger ones might require a call to memcpy() or equivalent, but it's still straightforward since the size and alignment are known at compile time.

Arrays are a different matter. Most array objects have sizes that aren't determined until run time. A good example is argv. The runtime environment constructs an array of char for each command-line argument, and an array of char* containing pointers to the arguments. These are made available to main via argv, a char**, and via the dynamically allocated char[] arrays that the elements of argv point to.

C arrays are objects in their own right, but they're not generally accessed as objects. Instead, their elements are accessed via pointers, and code traverses from one element to the next using pointer arithmetic.

Languages can be designed to treat arrays as first-class objects, with assignment -- but it's complicated. As a language designer, you have to decide whether an array of 10 integers and an array of 20 integers are the same type. If they are, you have to decide what happens when you try to assign one to the other. Does it copy the smaller size? Does it cause a runtime exception? Do you have to add a slice operation so you can operate on subsets of arrays?

If int[10] and int[20] are distinct types with no implicit conversion, then array operations are inflexible (see Pascal, for example).

All these things can be defined (see Ada), but only by defining higher-level constructs than what's typical in C. Instead, the designers of C (mostly Dennis Ritchie) chose to provide arrays with low-level operations. It's admittedly inconvenient at times, but it's a framework that can be used to implement all the higher-level array operations of any other language.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
10

The reason is basically historic. There was a C even before ISO C89 which was called "K&R" C, after Kernighan and Ritchie. The language was designed to be small enough so a compiler would fit in severely limited (by today's standards) memory of 64kb.

This language did not allow assigning arrays. If you wanted to copy same-sized arrays, memcpy was there for your needs. Writing memcpy(a, b, sizeof a) instead of a = b is certainly not a big complication. It has the additional advantage of being generalizable to different-sized arrays and array slices.

Interestingly, the struct assignment workaround you mention also did not work in K&R C. You had to either assign members one by one or, again, use memcpy. The first edition of K&R's The C Programming language mentions struct assignment as a feature for future implementation in the language. Which eventually happened with C89.

Jens
  • 69,818
  • 15
  • 125
  • 179
9

The answer is simple: It never was allowed before the committee got involved (even struct-assignment was considered too heavy), and considering there's array-decay, allowing it would have all kinds of interesting consequences.

Let's see what would change:

int a[3], b[3], *c = b, *d = b;
a = b; // Currently error, would assign elements
a = c; // Currently error, might assign array of 3?
c = a; // Currently pointer assignment with array decay
c = d; // Currently pointer assignemnt

So, allowing array-assignment would make (up to) two currently disallowed assignments valid.

That's not the trouble though, it's that near-identical expressions would have wildly different results.

That gets especially piquant if you consider that array-notation in function arguments is currently just a different notation for pointers.
If array assignment was introduced, that would become even more confusing.
Not that enough people aren't completely confounded by things as they are today...

int g(int* x);  // Function receiving pointer to int and returning int
int f(int x[3]);// Currently the same. What afterwards? Change to value-copy?
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Assignment to arrays is currently never meaningful, so what can be the problem with extending the language to allow assignment to arrays (from arrays of the same size perhaps)? I don't see any room for confusion actually! The meaning of existing code wouldn't change. Is there a corner case I'm missing? Anyway, we allow `i=3`, but not `3=i`, so we're already OK with a lack of 'symmetry' around assignment. – Aaron McDaid Jan 10 '15 at 22:17
  • 1
    @AaronMcDaid: The problem is completely inconsistent semantics. Did you read the line about function arguments too? (added example declarations) – Deduplicator Jan 10 '15 at 22:19
  • Ah yes. I had thought of arrays function arguments, but only just to think "they're crazy". I had forgotten to fully think through the fact that they 'look' like assignment-to-arrays. I would like to just get rid of arrays from the top level of function parameter types - they shouldn't be allowed at all. In fact, I think it should be done ASAP anyway, regardless of any proposal to allow assignment to arrays. – Aaron McDaid Jan 10 '15 at 22:26
8

Understand that the intent wasn't to make array expressions unassignable; that wasn't the goal1. Rather, this behavior falls out of a design decision Ritchie made that simplified array handling in the compiler, but in exchange made arrays expressions "second-class" objects; they lose their "array-ness" in most contexts.

Read this paper (especially the section titled "Embryonic C") for some background; I also have a more detailed answer here.


1. With the possible exception of Perl or PHP2, most blatant language WTFs are generally accidents of design or the result of compromises; most languages aren't deliberately designed to be stupid.

2. I'm only trolling a little bit; Perl and PHP are straight-up messes.
Community
  • 1
  • 1
John Bode
  • 119,563
  • 19
  • 122
  • 198
5

C is written in such a way that the address of the first element would be computed when the array expression is evaluated.

Quoting an excerpt from this answer:

This is why you can't do something like

int a[N], b[N];
a = b;

because both a and b evaluate to pointer values in that context; it's equivalent to writing 3 = 4. There's nothing in memory that actually stores the address of the first element in the array; the compiler simply computes it during the translation phase.

Community
  • 1
  • 1
haccks
  • 104,019
  • 25
  • 176
  • 264
2

Maybe it would be helpful to turn the question around, and ask why you'd ever want to assign arrays (or structs), instead of using pointers? That's much cleaner & easier to understand (at least if you've assimilated the Zen of C), and it has the benefit of not concealing the fact that a lot of work is hidden under the "simple" assignment of multi-megabyte arrays.

jamesqf
  • 215
  • 2
  • 4
  • 2
    Very few, if any, arrays are multi-megabyte, as that wouldn't fit on the stack of most systems. I'm not talking about dynamically allocated or sized arrays. I'm talking about normal arrays (of the form `type name[constant-integer]`). It's not a lot of work for the assignment, either: it's literally just a `memcpy`, as it is with other assignments in C. – Cornstalks Jan 11 '15 at 19:28