C's aversion to arrays [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In introductory books on C it is often claimed that pointers more or less are arrays. Isn't this a vast simplification, at best?
There is an array type in C and it can behave completely different from pointers, for example:
#include <stdio.h>
int main(int argc, char *argv[]){
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *b = a;
printf("sizeof(a) = %lu\n", sizeof(a));
printf("sizeof(b) = %lu\n", sizeof(b));
return 0;
}
gives the output
sizeof(a) = 40
sizeof(b) = 8
or as another example a = b would give a compilation error (GCC: "assignment to expression with array type").
Of course there is a close relationship between pointers and arrays, in the sense that yes, the content of an array variable itself is the memory address of the first array element, e.g. int a[10] = {777, 1, 2, 3, 4, 5, 6, 7, 8, 9}; printf("a = %ul\n", a); prints the address containing the 777.
Now, on the one hand, if you 'hide' arrays in structs, you can easily copy large amounts of data (arrays if you ignore the wrapping struct) just by using the = operator (and that's even fast, too):
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_LENGTH 100000000
typedef struct {int arr[ARRAY_LENGTH];} struct_huge_array;
int main(int argc, char *argv[]){
struct_huge_array *a = malloc(sizeof(struct_huge_array));
struct_huge_array *b = malloc(sizeof(struct_huge_array));
int *x = malloc(sizeof(int)*ARRAY_LENGTH);
int *y = malloc(sizeof(int)*ARRAY_LENGTH);
struct timeval start, end, diff;
gettimeofday(&start, NULL);
*a = *b;
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
printf("Copying struct_huge_arrays took %d sec, %d µs\n", diff.tv_sec, diff.tv_usec);
gettimeofday(&start, NULL);
memcpy(x, y, ARRAY_LENGTH*sizeof(int));
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
printf("memcpy took %d sec, %d µs\n", diff.tv_sec, diff.tv_usec);
return 0;
}
Output:
Copying struct_huge_arrays took 0 sec, 345581 µs
memcpy took 0 sec, 345912 µs
But you cannot do this with arrays itself. For arrays x, y (of the same size and of the same type) the expression x = y is illegal.
Then, functions can't return arrays. Or if arrays are used as arguments, C collapses them into pointers -- it does not care if the size is explicitly given, so the following program gives the output sizeof(a) = 8:
#include <stdio.h>
void f(int p[10]){
printf("sizeof(a) = %d\n", sizeof(p));
}
int main(int argc, char *argv[]){
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
f(a);
return 0;
}
Is there any logic behind this aversion to arrays? Why isn't there a true robust array type in C? What bad would happen if there was one? After all, if an array is hidden in a struct the array does behave as in Go, Rust, ..., i.e. the array is the whole chunk in memory and passing it around will copy its content, not just the memory address of the first element. For example like in Go the following program
package main
import "fmt"
func main() {
a := [2]int{-777, 777}
var b [2]int
b = a
b[0] = 666
fmt.Println(a)
fmt.Println(b)
}
gives the output:
[-777 777]
[666 777]

The C language was initially designed in the early 1970's on a PDP mini-computer which reportedly just filled up half a room, despite its huge 24 kB memory. (That's kB, not MB, or GB).
Fitting a compiler at all into that memory was the real challenge. So the C language was designed to allow you to write compact programs, and quite a few special operators (like +=, --, and ?:) was added for manual optimizations.
Adding features for copying large arrays as parameters didn't occur to the designers. It wouldn't have been useful anyway.
In C's predecessor, the B language, an array was represented as a pointer to storage allocated separately (see the link in Lars' answer). Ritchie wanted to avoid this extra pointer in C and so got the idea that the array name could be turned into a pointer when used in places not expecting an array:
It eliminated the materialization of the pointer in storage, and instead caused the creation of the pointer when the array name is mentioned in an expression. The rule, which survives in today's C, is that values of array type are converted, when they appear in expressions, into pointers to the first of the objects making up the array.
This invention enabled most existing B code to continue to work, despite the underlying shift in the language's semantics.
And structs didn't get added to the language until later. That you can pass an array inside a struct as a parameter was then a feature that offered another option.
Changing the syntax for arrays was already too late. It would break too many programs. There were already 100s of users...

This part of the question...
Is there any logic behind this aversion to arrays? Why isn't there a true robust array type in C? What bad would happen if there was one?
... is not really a code question and open to speculation, but I think a short answer might be beneficial: when C was created, it was targeted at machines with very little RAM and slow CPUs (measured in Kilo-Bytes and Megahertz, resp.). It was meant to replace Assembler as systems programming language, but without introducing the overhead that the other existing high-level languages required. For the same reasons, C is still a popular language for micro controllers, due to the control it gives you over the generated program.
Introducing a 'robust' array type would have had under-the-hood performance and complexity penalties for both the compiler and the runtime, which not all systems couldn't afford. At the same time, C offers the capabilities for the programmer to create their own 'robust' array type and use them only in those situations where its use was justified.
I found this article interesting in this context: Dennis Ritchie: Development of the C Language (1993)

Arrays are arrays and pointers are pointers, they are not the same.
But to make anything usable of arrays the compiler must use qualified pointers.
By definition an array is a contiguous and homogeneous sequence of elements in memory. So far so good, but how interact with it?
To explain the concept I already used, on other forums, an assembly example:
;int myarray[10] would be defined as
_myarray: .resd 10
;now the pointer p (suppose 64 bit machine)
_p: .resq 1
This is the code emitted by compiler to reserve an array of 10 int and a pointer to int in global memory.
Now when referring to the array what you think you can get? Just the address of course (or better the address of the first element). And the address what is? The standard says that it have to be called qualified pointer, but you can really understand now why it is so.
Now look the pointer, when we refer to it the compiler emits code to fetch the contents of the location at address p, but we can even get p itself, the address of the pointer variable, using &p, but we can't do it with an array. Using &myarray will give back the address of the first element again.
This means that you can assign myarray address to p, but not the reverse ;-)

Related

Why is this c code not changing the value of arr[3]?

I am creating an int array and then tricking c into believing that it's an array of short values. I know it's not good practice but I am just trying to understand why this isn't working. Shouldn't this change the value of arr[3] ?
#include <stdio.h>
int main() {
printf("Hello, World!\n");
int arr[5];
arr[0] = 0; arr[1] = 0; arr[2] = 0; arr[4] = 0;
arr[3] = 128;
((short*)arr)[6] = 128; // Shouldn't this change arr[3] ? as 6,7 indices in the arr of short would compromise of arr[3] in arr of ints?
int i = 0;
for (i = 0; i < 5; i++){
printf("%d\n", arr[i]);
}
return 0;
}
PS: Here's a deeper clarification:
When I cast int array to a short array, it seemingly becomes an array of 10 short elements (not 5). So when I change arr[6], I am changing only the first 16 bits of the int arr[3]. So arr[3] should still change and it is NOT that I am changing it to 128 again and not seeing the change.
FOR CLARIFICATION: THIS CODE IS ONLY FOR EXPERIMENTAL REASONS! I AM JUST LEARNING HOW POINTERS WORK AND I GET THAT ITS NOT GOOD PRACTICE.
Your code has undefined behavior, because you are writing a datum with a declared type through a pointer to a different type, and the different type is not char.
int arr[5];
/* ... */
((short*)arr)[6] = /* ANYTHING */;
The compiler is entitled to generate machine code that doesn't include the write to ((short*)arr)[6] at all, and this is quite likely with modern compilers. It's also entitled to delete the entire body of main on the theory that all possible executions of the program provoke undefined behavior, therefore the program will never actually be run.
(Some people say that when you write a program with undefined behavior, the C compiler is entitled to make demons fly out of your nose, but as a retired compiler developer I can assure you that most C compilers can't actually do that.)
Have you considered endianness?
EDIT: Now to add more clarity ...
As others have mentioned in the comments, this is most definitely undefined behavior! This is not just "not good practice", it's just don't do it!
Pointers on C is an excellent book that goes over everything you wanted to know about pointers and more. It's dated but still very relevant. You can probably find most of the information online, but I haven't seen many books that deal with pointers as completely as this one.
Though it sounds like you are experimenting, possibly as part of a class. So, here are a number of things wrong with this code:
endianness
memory access model
assumption of type size
assumption of hardware architecture
cross type casting
Remember, even though C is considered a pretty low level language today, it is still a high level programming language that affords many key abstractions.
Now, look at your declaration again.
int arr[5];
You've allocated 5 ints grouped together and accessed via a common variable named arr. By the standard, the array is 5 elements of at least 2 bytes per element with base address of &arr[0]. So, you aren't guaranteed that an int is 2 bytes, or 4 bytes or whatever. Likewise, as short is defined by the standard as at least 2 bytes. However, a short is not an int even if they have the same byte width! Remember, C is strongly typed.
Now, it looks like you are running on a machine where shorts are 2 bytes and ints are 4 bytes. That is where the endianness issue come into play: where is your most significant bit? And where is your most significant byte?
By casting the address of arr to a short pointer first of all breaks both the type and the memory access model. Then, you want to access the 6th element from the offset of arr. However, you aren't accessing relative to the int you declared arr to be, you are accessing through a short pointer that is pointing at the same address as arr!
These following operations ARE NOT the same! And it also falls into the category of undefined - don't do this ever!
int foo;
int pfooInt;
short bar;
short * pfooShort;
bar = (short) foo;
pfooShort = (short*)&foo;
pfooInt = &foo;
bar = *pfooShort;
pfooShort = (short*)pfooInt[0];
Another thing to clarify for you:
int arr[5];
((short *)arr)[6] ...
This does not transform your int array of 5 elements into a short array with 10 elements. arr is still an int array of 5 elements. You just broke the access method and are trying to modify memory in an undefined manner. What you did is tell the compiler "ignore what I told you about arr previously, treat arr as a short pointer for the life of this statement and access/modify 6th short relative to this pointer."
It is changing arr[3], however you are setting it back to 128 so you arent noticing a change. Change the line to:
((short*)arr)[6] = 72;
and you should see the following output:
Also a couple of things to clean up if you are new to C. You can initialize an array to zero by doing the following.
...
int arr[5] = { 0 };
arr[3] = 128;
...
Hope this helps!

Array initialization at runtime

code link
#include <stdio.h>
int main(void) {
// your code goes here
int a = 2;
int b = 3;
int c;
c = a + b;
int arr[c];
arr[5] = 0;
printf("%d",arr[5]);
return 0;
}
Output is 0
How is it that at runtime it is taking the array number ? Is it a new feature ?
This is a variable length array. They were introduced in the 1999 revision of the C standard.
Sadly support for them came in slowly, so much that the 2011 revision made them an optional feature (but they are still standardized) 1.
Despite looking cool, they have a major caveat. They can cause you to overflow the call stack if the size is "too big". As such, care needs to be taken when using them.
1 Some compiler vendors were resistant, so it was made optional to appease them. Microsoft is an entire case study of this.
This feature (Variable length array) has been introduced in C99. But currently this still is a compiler-dependent behavior. Some compiler(like gcc) supports it. Some(like msvc) doesn't.
BTW, arr[5] in your code, is out of range. Last element should be arr[4].
don't be confused in (static/fixed memory allocation) & (dynamic memory allocation) concepts :)
Let me clear your concept bro.
Relevant to following question,
C supports two type of array.
1.Static Array - are allocated memory at "COMPILE TIME".
2.Dynamic Array - are allocated memory at "RUN TIME".
Ques. how to determine if an Array is static or dynamic?
Ans.
Array declaration syntax:-
int array_Name[size]; //size defines the size of block of memory for an array;
So, coming to the point-->
Point 1. if size is given at compile time to array, it's a "Static Memory Allocation". It is also called "fixed size memory allocation" because size is never changed. It's the LIMITATION of ARRAY in C.
ex.
int arr[10]; //10 is size of arr which is staticly defined
int brr[] = {1000, 2, 37, 755, 3}; //size is equal to the no. of values initilizes with.
point 2. If size is given at compile time to array, it's a Dynamic Memory Allocation.
It is achieved by malloc() function defined in stdlib.h .
Now, its's the clarification of your code :-
#include <stdio.h>
int main(void) {
// your code goes here
int a = 2;
int b = 3;
int c;
c = a + b; //c is calculated at run time
int arr[c]; //Compilor awaiting for the value of c which is given at run time but,
arr[5] = 0; //here arr is allocated the size of 5 at static(compile) time which is never be change further whether it is compile time in next statements or run time.
printf("%d",arr[5]);
return 0;
}
So, array(of size 5) holds value 0 at arr[5].
and ,other array indexes still show Garbage Values.
Hoping, you'll be satisfy with this solution to your problem :)

Why would C have "fake arrays"? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm reading The Unix haters handbook and in chapter 9 there's something I don't really understand:
C doesn’t really have arrays either. It has something that looks like an array
but is really a pointer to a memory location.
I can't really imagine any way to store an array in memory other than using pointers to index memory locations. How C implements "fake" arrays, anyways? Is there any veracity on this claim?
I think the author’s point is that C arrays are really just a thin veneer on pointer arithmetic. The subscript operator is defined simply as a[b] == *(a + b), so you can easily say 5[a] instead of a[5] and do other horrible things like access the array past the last index.
Comparing to that, a “true array” would be one that knows its own size, doesn’t let you do pointer arithmetic, access past the last index without an error, or access its contents using a different item type. In other words, a “true array” is a tight abstraction that doesn’t tie you to a single representation – it could be a linked list instead, for example.
PS. To spare myself some trouble: I don’t really have an opinion on this, I’m just explaining the quote from the book.
There is a difference between C arrays and pointers, and it can be seen by the output of sizeof() expressions. For example:
void sample1(const char * ptr)
{
/* s1 depends on pointer size of architecture */
size_t s1 = sizeof(ptr);
}
size_t sample2(const char arr[])
{
/* s2 also depends on pointer size of architecture, because arr decays to pointer */
size_t s2 = sizeof(arr);
return s2;
}
void sample3(void)
{
const char arr[3];
/* s3 = 3 * sizeof(char) = 3 */
size_t s2 = sizeof(arr);
}
void sample4(void)
{
const char arr[3];
/* s4 = output of sample2(arr) which... depends on pointer size of architecture, because arr decays to pointer */
size_t s4 = sample2(arr);
}
The sample2 and sample4 in particular is probably why people tend to conflate C arrays with C pointers, because in other languages you can simply pass arrays as an argument to a function and have it work 'just the same' as it did in the caller function. Similarly because of how C works you can pass pointers instead of arrays and this is 'valid', whereas in other languages with a clearer distinction between arrays and pointers it would not be.
You could also view the sizeof() output as a consequence of C's pass-by-value semantics (since C arrays decay to pointers).
Also, some compilers also support this C syntax:
void foo(const char arr[static 2])
{
/* arr must be **at least** 2 elements in size, cannot pass NULL */
}
The statement you quoted is factually incorrect. Arrays in C are not pointers.
The idea of implementing arrays as pointers was used in B and BCPL languages (ancestors of C), but it has not survived transition to C. At the early ages of C the "backward compatibility" with B and BCPL was considered somewhat important, which is why C arrays closely emulate behavior of B and BCPL arrays (i.e. C arrays easily "decay" to pointers). Nevertheless, C arrays are not "pointers to a memory location".
The book quote is completely bogus. This misconception is rather widespread among C newbies. But how it managed to get into a book is beyond me.
Author probably means, that arrays are constrained in ways which make them feel like 2nd class citizens from programmer point of view. For example, two functions, one is ok, another is not:
int finefunction() {
int ret = 5;
return ret;
}
int[] wtffunction() {
int ret[1] = { 5 };
return ret;
}
You can work around this a bit by wrapping arrays in structs, but it just sort of emphasizes that arrays are different, they're not like other types.
struct int1 {
int a[1];
}
int[] finefunction2() {
struct int1 ret = { { 5 } };
return ret;
}
Another effect of this is, that you can't get size of array at runtime:
int my_sizeof(int a[]) {
int size = sizeof(a);
return size;
}
int main() {
int arr[5];
// prints 20 4, not 20 20 as it would if arrays were 1st class things
printf("%d %d\n", sizeof(arr), my_sizeof(arr));
}
Another way to say what the authors says is, in C (and C++) terminology, "array" means something else than in most other languages.
So, your title question, how would a "true array" be stored in memory. Well, there is no one single kind of "true array". If you wanted true arrays in C, you have basically two options:
Use calloc to allocate buffer, and store pointer and item count here
struct intarrayref {
size_t count;
int *data;
}
This struct is basically reference to array, and you can pass it around nicely to functions etc. You will want to write functions to operate on it, such as create copy of the actual data.
Use flexible array member, and allocate whole struct with single calloc
struct intarrayobject {
size_t count;
int data[];
}
In this case, you allocate both the metadata (count), and the space for array data in one go, but the price is, you can't pass this struct around as value any more, because that would leave behind the extra data. You have to pass pointer to this struct to functions etc. So it is matter of opinion whether one would consider this a "true array" or just slightly enhanced normal C array.
Like the entire book, it's a case of trolling, specifically, the type of trolling that involves stating something almost-true but wrong to solicit angry responses about why it's wrong. C most certainly does have actual arrays/array types, as evidenced by the way pointer-to-array types (and multi-dimensional arrays) work.

Pointer to 2D arrays in C

I know there is several questions about that which gives good (and working) solutions, but none IMHO which says clearly what is the best way to achieve this.
So, suppose we have some 2D array :
int tab1[100][280];
We want to make a pointer that points to this 2D array.
To achieve this, we can do :
int (*pointer)[280]; // pointer creation
pointer = tab1; //assignation
pointer[5][12] = 517; // use
int myint = pointer[5][12]; // use
or, alternatively :
int (*pointer)[100][280]; // pointer creation
pointer = &tab1; //assignation
(*pointer)[5][12] = 517; // use
int myint = (*pointer)[5][12]; // use
OK, both seems to work well. Now I would like to know :
what is the best way, the 1st or the 2nd ?
are both equals for the compiler ? (speed, perf...)
is one of these solutions eating more memory than the other ?
what is the more frequently used by developers ?
//defines an array of 280 pointers (1120 or 2240 bytes)
int *pointer1 [280];
//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280]; //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers
Using pointer2 or pointer3 produce the same binary except manipulations as ++pointer2 as pointed out by WhozCraig.
I recommend using typedef (producing same binary code as above pointer3)
typedef int myType[100][280];
myType *pointer3;
Note: Since C++11, you can also use keyword using instead of typedef
using myType = int[100][280];
myType *pointer3;
in your example:
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
Note: If the array tab1 is used within a function body => this array will be placed within the call stack memory. But the stack size is limited. Using arrays bigger than the free memory stack produces a stack overflow crash.
The full snippet is online-compilable at gcc.godbolt.org
int main()
{
//defines an array of 280 pointers (1120 or 2240 bytes)
int *pointer1 [280];
static_assert( sizeof(pointer1) == 2240, "" );
//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280]; //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers
static_assert( sizeof(pointer2) == 8, "" );
static_assert( sizeof(pointer3) == 8, "" );
// Use 'typedef' (or 'using' if you use a modern C++ compiler)
typedef int myType[100][280];
//using myType = int[100][280];
int tab1[100][280];
myType *pointer; // pointer creation
pointer = &tab1; // assignation
(*pointer)[5][12] = 517; // set (write)
int myint = (*pointer)[5][12]; // get (read)
return myint;
}
Both your examples are equivalent. However, the first one is less obvious and more "hacky", while the second one clearly states your intention.
int (*pointer)[280];
pointer = tab1;
pointer points to an 1D array of 280 integers. In your assignment, you actually assign the first row of tab1. This works since you can implicitly cast arrays to pointers (to the first element).
When you are using pointer[5][12], C treats pointer as an array of arrays (pointer[5] is of type int[280]), so there is another implicit cast here (at least semantically).
In your second example, you explicitly create a pointer to a 2D array:
int (*pointer)[100][280];
pointer = &tab1;
The semantics are clearer here: *pointer is a 2D array, so you need to access it using (*pointer)[i][j].
Both solutions use the same amount of memory (1 pointer) and will most likely run equally fast. Under the hood, both pointers will even point to the same memory location (the first element of the tab1 array), and it is possible that your compiler will even generate the same code.
The first solution is "more advanced" since one needs quite a deep understanding on how arrays and pointers work in C to understand what is going on. The second one is more explicit.
int *pointer[280]; //Creates 280 pointers of type int.
In 32 bit os, 4 bytes for each pointer. so 4 * 280 = 1120 bytes.
int (*pointer)[100][280]; // Creates only one pointer which is used to point an array of [100][280] ints.
Here only 4 bytes.
Coming to your question, int (*pointer)[280]; and int (*pointer)[100][280]; are different though it points to same 2D array of [100][280].
Because if int (*pointer)[280]; is incremented, then it will points to next 1D array, but where as int (*pointer)[100][280]; crosses the whole 2D array and points to next byte. Accessing that byte may cause problem if that memory doen't belongs to your process.
Ok, this is actually four different question. I'll address them one by one:
are both equals for the compiler? (speed, perf...)
Yes. The pointer dereferenciation and decay from type int (*)[100][280] to int (*)[280] is always a noop to your CPU. I wouldn't put it past a bad compiler to generate bogus code anyways, but a good optimizing compiler should compile both examples to the exact same code.
is one of these solutions eating more memory than the other?
As a corollary to my first answer, no.
what is the more frequently used by developers?
Definitely the variant without the extra (*pointer) dereferenciation. For C programmers it is second nature to assume that any pointer may actually be a pointer to the first element of an array.
what is the best way, the 1st or the 2nd?
That depends on what you optimize for:
Idiomatic code uses variant 1. The declaration is missing the outer dimension, but all uses are exactly as a C programmer expects them to be.
If you want to make it explicit that you are pointing to an array, you can use variant 2. However, many seasoned C programmers will think that there's a third dimension hidden behind the innermost *. Having no array dimension there will feel weird to most programmers.

C array declaration and assignment?

I've asked a similar question on structs here but I'm trying to figure out how C handles things like assigning variables and why it isn't allowed to assign them to eachother if they are functionally the same.
Lets say I have two arrays:
int x[10];
int y[10];
Why won't x = y compile? If they are both the same "signature" like that, then shouldn't you be able to assign them back and forth?
Can I declare these in a way that would allow me to do that in C? It makes sense to me that you would be able to, but maybe there is a way that this can be done? Typedefs for structs seemed to be the solution, would it be the same for array declaration and assignment?
I appreciate your guys help, I'm new to Stackoverflow but it has been a really good resource for me so far!
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.
Some messages here say that the name of an array yields the address of its first element. It's not always true:
#include <stdio.h>
int
main(void)
{
int array[10];
/*
* Print the size of the whole array then the size of a pointer to the
* first element.
*/
printf("%u %u\n", (unsigned int)sizeof array, (unsigned int)sizeof &array[0]);
/*
* You can take the address of array, which gives you a pointer to the whole
* array. The difference between ``pointer to array'' and ``pointer to the
* first element of the array'' matters when you're doing pointer arithmetic.
*/
printf("%p %p\n", (void*)(&array + 1), (void*)(array + 1));
return 0;
}
Output:
40 4
0xbfbf2ca4 0xbfbf2c80
In order to assign arrays you will have to assign the values inside the array.
ie. x=y is equivalent to
for(int i = 0; i < 10 < ++i)
{
x[i] = y[i];
}
In an attempt to complement Blank's answer, I devised the following program:
localhost:~ david$ cat test.c
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char * argv [])
{
struct data {
int c [2];
} x, y;
x.c[0] = x.c[1] = 0;
y.c[0] = y.c[1] = 1;
printf("x.c %p %i %i\n", x.c, x.c[0], x.c[1]);
printf("y.c %p %i %i\n", y.c, y.c[0], y.c[1]);
x = y;
printf("x.c %p %i %i\n", x.c, x.c[0], x.c[1]);
printf("y.c %p %i %i\n", y.c, y.c[0], y.c[1]);
return 0;
}
When executed, the following is output:
x.c 0x7fff5fbff870 0 0
y.c 0x7fff5fbff860 1 1
x.c 0x7fff5fbff870 1 1
y.c 0x7fff5fbff860 1 1
The point is to illustrate how the copy of structures' values occurs.
When saying "int x[10]" is saying, "reserve some room for 10 integers and pass me a pointer to the location". So for the copy to make sense you'd need to operate on the memory pointed by, rather than 'the name of the memory location'.
So for copying here you'd use a for loop or memcpy().
I've used C compilers where that would compile just fine...and when run the code would make x point to y's array.
You see, in C the name of an array is a pointer that points to the start of the array. In fact, arrays and pointers are essentially interchangable. You can take any pointer and index it like an array.
Back when C was being developed in the early 70's, it was meant for relatively small programs that were barely above assembly language in abstraction. In that environment, it was damn handy to be able to easily go back and forth between array indexing and pointer math. Copying whole arrays of data, on the other hand, was a very expensive thing do do, and hardly something to be encouraged or abstracted away from the user.
Yes, in these modern times it would make way more sense to have the name of the array be shorthand for "the whole array", rather than for "a ponter to the front of the array". However, C wasn't designed in these modern times. If you want a language that was, try Ada. x := y there does exactly what you would expect; it copies one array's contents to the other.

Resources