Simply put, arrays are not assignable. They are a "non-modifiable lvalue". This of course begs the question: why? Please refer to this question for more information:
Why does C++ support memberwise assignment of arrays within structs, but not generally?
Arrays are not pointers. x here does refer to an array, though in many circumstances this "decays" (is implicitly converted) to a pointer to its first element. Likewise, y too is the name of an array, not a pointer.
You can do array assignment within structs:
struct data {
int arr[10];
};
struct data x = {/* blah */};
struct data y;
y = x;
But you can't do it directly with arrays. Use memcpy.
Simply put, arrays are not assignable. They are a "non-modifiable lvalue". This of course begs the question: why? Please refer to this question for more information:
Why does C++ support memberwise assignment of arrays within structs, but not generally?
Arrays are not pointers. x here does refer to an array, though in many circumstances this "decays" (is implicitly converted) to a pointer to its first element. Likewise, y too is the name of an array, not a pointer.
You can do array assignment within structs:
struct data {
int arr[10];
};
struct data x = {/* blah */};
struct data y;
y = x;
But you can't do it directly with arrays. Use memcpy.
int x [sz];
int *y = x;
This compiles and y will be the same as x.
Why does C not support direct array assignment?
It is arguably a shortcoming, due to missing features around arrays, but one the original designers choose not to resolve. Add in the (over) emphasis on pointers and pointer arithmetic and keeping track of these things yourself as would be done in assembly.
Arrays in C don't really have sizes. Yes, you can int A[100]; ... sizeof(A) ... for a declared array, but once A is used in an expression, its type is immediately converted to pointer to element (here int*) and the original array's size is lost. This is particularly evident with parameters where an array is passed.
There's not even a convenient built-in for length (e.g. say, lengthof) that would work for arrays of any element size — instead we have to write something like (sizeof(A)/sizeof(*A)).
A lot of code in C relies on use of pointers where length is kept by the program using other variables or knowledge rather than having the language keep track.
Often, declaring an array in a struct/union as a last member is secret code for variable length. See for example:
#include <stdio.h>
int A [100];
extern int B [];
struct foo {
int E, F;
int C [];
};
int main()
{
printf("Hello, %ld, %ld, %ld\n", sizeof A, sizeof *B, sizeof (struct foo) );
return 0;
}
I can't say for sure but apparently resolving the short comings only for declared arrays but not for pointers seemed not all that useful. So, some larger built in length mechanism would have been required for general use with pointers.
Still, something could have been done, say by having some syntax that allows the user to specify a number of elements — like A = B[0:n] or A[0:n] = B or some other variant — but they simply stopped short of that, leaving it for memcpy and memmove. Let's also note that when you choose between memcpy and memmove, with the former you're saying that the source and destination do not overlap, whereas with memmove you're saying they might overlap so backwards copying of the elements may be better than forwards (and it will check at runtime).
So, the various problems:
- pointer oriented rather than array oriented
- no implicit size information on pointers
- aliasing issues
- arrays can be created without even using any array declaration (e.g. using
malloc), so by their nature they have a length the program has to keep track of on its own- fixed sized arrays are only useful in narrow contexts
I think punting to the standard library was pretty reasonable here, plus as you note for fixed sized arrays, we can wrap them in a struct/union..
C originally came from a predecessor language called B, made by Ken Thompson. In B, there were no types. Everything was a "word" (basically, an int).
In B, arrays were just pointers to the first element. If you declared an array:
auto arr[10];
This would allocate 10 words on the stack (to be freed automatically when the function returned, thus auto), and arr would be a pointer to the first one.
When the type system was added, Dennis Ritchie didn't want any existing code to break. This is why, for example, on early versions of C if you omitted the type it would default to int. It's also where pointer decay (array arguments to functions being just pointers) came from.
For this reason, arrays ended up being a second-class citizen in C for a long time. Because of the stability of the language, even the more modern C standards (like C23 which is supposed to come out this year) have to try to fix it without breaking anything, and this particular issue (copying arrays) is not really a priority, because you rarely actually want to copy an array (especially a large one).
Source: The Development of the C language
Simple C array declaration / assignment question - Stack Overflow
[Help] Why can't you assign an array to another array?
Can’t assign arrays
New to C - how do I assign array values to a new array?
Videos
If you really to assign values (as opposed to initialize), you can do it like this:
Copy GLfloat coordinates[8];
static const GLfloat coordinates_defaults[8] = {1.0f, 0.0f, 1.0f ....};
...
memcpy(coordinates, coordinates_defaults, sizeof(coordinates_defaults));
return coordinates;
Although in your case, just plain initialization will do, there's a trick to wrap the array into a struct (which can be initialized after declaration).
For example:
Copystruct foo {
GLfloat arr[10];
};
...
struct foo foo;
foo = (struct foo) { .arr = {1.0, ... } };
You can only do multiple assignment of the array, when you declare the array:
int values[3] = {1,2,3};
After declaration, you'll have to assign each value individually, i.e.
if (1)
{
values[0] = 1;
values[1] = 2;
values[2] = 3;
}
Or you could use a loop, depending on what values you want to use.
if (1)
{
for (i = 0 ; i < 3 ; i++)
{
values[i] = i+1;
}
}
In C99, using compound literals, you could do:
memcpy(values, (int[3]){1, 2, 3}, sizeof(int[3]));
or
int* values = (int[3]){1, 2, 3};
The following code snippet has an error error: invalid initializer:
int main() {
int a[3] = {0, 1, 2};
int b[3];
b = a;
return 0;
}There were some StackOverflow answers regarding this, but I still have some questions about it.
My Understanding
There is the mantra that "arrays decay into pointers", but I'm aware that does not mean that arrays are equivalent to pointers.
Here,
int main() {
int *p = malloc(3 * sizeof(int));
for (int i = 0; i < 3; i++)
p[i] = i;
}
The compiler will allocate a pointer's worth of memory to p, and the value of p is the address of some location on the heap. In the top code snippet, the compiler allocates 3 ints worth of memory and the value of a is that entire block of memory.
So for me, the above code snippet is similar to declaring an int. When declaring some int i, the compiler allocates an int's worth of memory for i and i's value is that block of memory.
And for an int, this would compile just fine:
int main() {
int x = 5;
int y;
y = x;
return 0;
}
I don't see why the compiler couldn't just take the data stored at a and copy that over to b, just like how it does above.
I also started messing around with the code some more, and I noticed that this worked for some reason:
int main() {
int a[3] = {1, 2, 3};
int *b;
b = a;
return 0;
}What's the difference here?
EDIT: fixed typos
This should be a valid code as taken from CS50:
// Copy string into memory, including '\0'
for (int i = 0; i <= strlen(s); i++)
{
t[i] = s[i];
}But in other places (for instance https://www.reddit.com/r/C_Programming/comments/14oolus/comment/jqexig6/?utm_source=share&utm_medium=web2x&context=3), I have read that arrays cannot be assigned values this way. Must be missing something for sure.