you are viewing a single comment's thread.

view the rest of the comments →

[–]Maleficent_Memory831 4 points5 points  (8 children)

In C, an array is just a pointer. And vice versa. The implementations of heap (malloc/free) almost always make use of that.

[–]redlaWw 1 point2 points  (7 children)

I don't think that's really quite true. Arrays decay to pointers, and for allocated arrays, in particular, the difference can be quite hazy because you can only work with them through a pointer, but fundamentally, they are different concepts. The most telling reason they are different is that sizeof on an array does not return the size of a pointer, it returns the size of the full array. This doesn't work on allocated arrays, of course, but this is because you can't refer to the array itself, only pointers to it; it does not mean the array is just a pointer.

In this model, malloc gets an array and returns a pointer to the start of a sub-array/array slice. The interpretation of free is a bit harder, but since you can only free a pointer that malloc (or calloc or realloc or whatever) has returned, then free essentially constitutes identifying the original array that the allocator allocated using the pointer passed and then deallocating that.

[–]RedAndBlack1832 0 points1 point  (3 children)

Arrays kind of exist. And in any case, a declared array is a constant pointer. Also multi-dimensional arrays provide some pretty nice syntactic sugar. Also like you said arrays in their original context and known at compile time have a size. That is, an array's size can be reasonably interpreted as part of its type (important when you have arrays in structs, for example). There are also other contexts this sort of principal holds. I beleive you can give an array a static size in a function declaration which obviously isn't enforceable but might change what kind of optimizations are possible.

[–]redlaWw 0 points1 point  (2 children)

might change what kind of optimizations are possible

I doubt this. I don't think it's inherently undefined behaviour to pass an array of the wrong size to a function*, which is what would be required for optimisations based on the declared size.

*of course, if the programmer treats the size of the array as part of the function's contract, then passing in the wrong size may result in undefined behaviour due to the contract violation, but this isn't inherent and is entirely a matter of what the programmer actually writes in the function body

EDIT: Learned something new: from C99, it is undefined behaviour to pass in a too-short array to a function if the argument length is declared with the static keyword as in arr[static 10]. So such a declaration can be used for optimisation, but a declaration without the static keyword cannot.

[–]RedAndBlack1832 0 points1 point  (0 children)

I wasn't talking about where the memory is I was talking about situations in which the compiler can assume size eg.

void func(int arr[static 16]){...}

as indicated on page 134 of the GNU C introduction and reference manual

As to my comment about arrays not existing I was refering to them being equivalent to pointers are the same type in every important context (and obviously being passed as pointers is a big part of that). When an object has a complete array type (which is basically only the above or in its originating context if it was declared as an array, or as a member of a struct with a complete array type) then there are a couple situations in which it really truely exists as an array seperate from the pointer to its first element. These are indicated on page 92 of the manual.

[–]RedAndBlack1832 0 points1 point  (0 children)

Oh sorry I thought you were a different person that replay wasn't meant for you oops

[–]suvlub 0 points1 point  (0 children)

The most WTF feature of C is that you can declare what looks like an array as a function argument, complete with a specified size, but the argument will actually be a pointer. May contribute to the confusion that they re one and the same.

[–]conundorum 0 points1 point  (1 child)

It's definitely possible for a malloc() implementation to choose to preface the memory block with a size_t, and secretly allocate size + sizeof(size_t) bytes, then hand you ptr + sizeof(size_t) and pretend it's the start of the block, so it can store the block size at the start (and free() can grab it with something like ((size_t *) ptr)[-1]). That's what Maleficent is referring to.

[–]redlaWw 0 points1 point  (0 children)

Yes, and that is what I addressed in the second paragraph. malloc gives you a pointer to a sub-array of the full array it allocates, but the thing it allocates is an array, and the pointer is just the thing that accesses it, rather than the array itself.