Regarding stack arrays, while the compiler certainly knows how large an array is (of course it has to, you're using the length in the code it parses), it will almost certainly not write code or immediates that hold the size anywhere to the resultant binary. If you allocate three arrays, each of 12 doubles, a compiler can simply emit "sub esp, 288" and be done with it. It also won't stop you from referencing memory at an unreasonable offset from any of those arrays. (Compilers can warn you though.)
Passing the array along with its size further goes to prove the original statement, not refute it. If you have to do something manually, it strongly implies that the language/runtime isn't doing it for you.
Regarding arrays on the heap, the runtime even then does not require you to place a size anywhere. What likely happens is the right cell from a bucket of the closest size to the allocation you need is returned to you and marked in use. It will be as large as the size you're allocating, or larger. The only artifact of its original size is which span of memory it's located at. When you free() that allocation, that block simply gets marked as free, no size needed.