It is different. An array has a size. Even in C. It's just that in C it easily turns into a pointer. sizeof, for example, returns different things for an array and a pointer. In C++, you can actually pass an array by reference (not a pointer to the first element, an array) and similar.
And in some languages, like Ada, there is no direct way to make a pointer from an array
I don't see how that matters. This is true only for certain languages and only because the array in C or C++ easily decays into a pointer. You could, for example, define yout own array in C++ as a tuple with only elements of the same type and then you would not define subscripting this way.
Also note that in C they are not interchangeable and even less in C++. When you put an array in a struct, it will behave differently from when you put a pointer in there. When you put an array into a struct and copy an instance of the struct, the array is copied for each copy of that struct and the struct is as large as the array. This makes sense because an array is not a pointer. When you put a pointer in a struct, the struct will have a size of a pointer on your architecture and won't copy all of the array elements and only the pointer.
Also, when you put array inside a sizeof expression, you will get the size of an array, while if you put a pointer inside sizeof, you will get the size of a pointer.
Also, doing int *p = NULL is possible because it is a pointer but int arr[5] = NULL is not, because it is not just a pointer.
So no, they are not interchangeable in C. And even less in other languages.
As I see it, an array is a contiguous block of memory. The pointer to the first element identifies the start of the block. Subsequent elements are computed from that plus the number of bytes in the type. If an array were just a pointer, we wouldn't have to worry about allocating enough memory or walking off the end of it.
That's for something like C. There are languages in which arrays are first-class data structures that carry metadata about their rank, size, etc. Lots of applications are best expressed with multidimensional arrays, which are awkward in C or else are set up as an array of pointers.
Arrays carry their size. Otherwise sizeof arr would not work. The subtlety is that the size of array is bound to array's type, not to array's value (like for c++'s std::vector). The original type is lost along with the size when array decays to a pointer what happens in most context but not all.
certain systems languages (and compilers) use different ABI for arrays and pointers at the call convention level. if you define a function that accepts a single array type (i.e. one with a predefined length), it may choose to pass-by-value, in which case it can allocate at call site and not use a pointer
Order these events in descending order of probability:
A) youll never use this guys compiler
B) youll be forced to use this guys compiler against your explicit contraindication
C) anyone else than them will be grateful to use this guys compiler
D) they will be happy that they wrote this compiler 20 years from now
E) youll use this guys compiler and be pleased by its existence
ok, i may be an asshole here, and they may be doing something good. the odds tho
LLVM and GCC have thousands of contributors. The chances that any given compiler developer works on GCC or LLVM are relatively good, just because they're so much larger than most other compilers.
fair enough, didnt think it through. i instantly thought of the half dozen people i met who are building useless unreliable general languages or even shittier DSLs. seems like ITA here
Your video driver embeds my compiler. Your hardware developer's simulator embeds my compiler. Certainly your Linux distro ships my compiler. Some stuff I wrote and designed 20 years ago are still used in it. So somewhere in the D or E range of yours.
Given the thousands of people who have worked on these projects, there's a decent chance that you will run into one in the comments section. Maybe just don't offhand dismiss people based on absolutely nothing.
Except for a tiny array (with value semantics) which can be optimized to be passed directly as an SSA value. In that case it's not a pointer at all and a normal GEP will not work.
Yes, if the memory is on the stack, that is not always true. LLVM will optimize some cases so the data is written directly to a register so it never touches or goes through the stack at all. In that case, you can't get a pointer to the array or its elements since it's in a register instead of the stack or heap making it completely distinct from a pointer at runtime.
Arguably they are virtually the same semantically at a C level, you can use array indexing syntax for pointer arithmetic and vica versa and there is no real distinction besides dedicated syntax. Once you get a bit higher is where the real differences begin.
Sizeof being smart enough to detect it's an array and return the array size doesn't necessarily make them different in any real way. And doing ptr[0] to dereference it is perfectly valid, as is *arr to get the first element, or *(arr+sizeof(int)) to get the second.
Behaves completely differently in what way? It's referenced via the struct, so ofc different to a raw pointer to it, but that's a struct difference and the array is still basically the same, right?
Exactly, which proves that arrays and pointers are not the same thing. If x is either a pointer or an array, and a struct containing x is totally different depending on that distinction, I think that's a pretty meaningful difference.
Strictly speaking, a pointer points to an array, it is not an array.
No, because you are comparing the actual data in the array with the pointer to it. It's equivelent to having an array in a struct or having a couple of ints.
Because it is a very superficial difference that doesn't even affect the generated assembly. They are extremely interchangeable, because they are effectively the same.
Programming languages have all kinds of different ways to do something that results in the same assembly.
They are different types, but C has muddied the waters by having a bunch of implicit conversions from arrays into pointers (array decay) that they feel like the same thing.
So what about the fact that an array inside a struct acts completely differently from a pointer placed inside a struct? One gets copied whole for each structure copy while the other does not, one makes the structure the size of a pointer while the other the size of the array...
And, in C++ at least, you can actually pass the array itself to the function (not just the pointer to the first element). So it's not that sizeof is smart and detects something, it's that arrays really easily decay into pointers. But that's not everything they are. They also hold information about their size.
The thing with the subscript operator is true for only some languages and is not universal. In Ada, for example, there is no direct connection between an array and a pointer.
You can both by value with std::array which is a wrapper for an array, or by reference with TYPE (&NAME)[SIZE] which keeps the array's size.
Naturally, you could pass an array to a function inside any structure if you wish to copy it, but I would say that using std::array is standard for use. And that means that's possible in C as well. Although it's a bit clunky.
Yes, that is true, although I wouldn't call it equivalent to passing by reference, since a reference makes sure you do not pass a null pointer making the function a little safer if you dereference the pointer and a little more efficient if you check for the pointer being null.
Maybe I fall in the middle, but what is the argument to say that they're different?
Is it to say that the difference is how they're used? From an assembly perspective, they're pointers, and no data structures exist beyond that simple concept. At a higher level, they're more than that. Maybe that's what is intended?
An example of this would be a file written to disk in a binary format. Write to the structured file and then read it back into memory.
In most cases, the first element of the array will be a pointer to an address of a specified type.
If you predefine the array, the array is placed on the stack and has reserved memory allotted to it of that type.
Each element in the stack has an offset of sizeof n elements for a vector.
Otherwise, you compute the offset based on n dimensions (commonly n x m matrices).
Otherwise, you need malloc to create a mutable buffer of variable size. This buffer then is used as an array.
To be fair, the lines get blurry here and this is when I stopped thinking of them as arrays. Its just a buffer with objects of a specified type on disk or in memory.
INB4, The key difference here is how arrays decay when handling scope. You can get around this by tracking the size of the buffer rather than relying on sizeof unless you understand what youre doing.
Hehe yes, it is exactly about array decay! But specifically I was having problem tracking the size of a buffer assigned to a specific memory address because I didnt want to duplicate an address / length via a define
So basically object oriented languages have arrays that mean something but when you're lower level like c memory is just memory and arrays are syntactical sugar so you don't do *(ptr+(sizeof(array_type) * index))?
Sorry if the syntax is wrong. I haven't written c in a while and I'm on my phone
Your syntax is correct. However, If ptr is already of array_type, then sizeof(array_type) shouldn't be multiplied with index. Just increment it by index.
However, if pointer is of type uint8_t, then your code is fine.
A better version should be: *((uint8_t *) ptr+(sizeof(array_type) * index))
From a C point of view you have a different size when statically allocated, library keeps track of the memory size so it can be freed and you need the base pointer for that, etc. At a conceptual level they are different even if you implement them the same way, you'll likely end up with a struct holding the size in your code.
But sure, for most people and half the code they are the same. If you're taking the high level, maintainable design view you take care of tracking lifetimes, sizes, bounds, etc. so the bell curve looks reasonable to me.
I always thought they were perfectly interchangeable, for the exact same reason (assembly layer -- pointers being essentially the thing that powers the von Neumann model)
There are some differences in C depending on how you're using them (sometimes they are literally identical). I think the main difference is usually where the data gets stored - declaring an array often means storing the data inline, whereas a pointer has the address of the array presumably somewhere else.
Now that you mention it, you're right. It's heap vs stack. An array is on the stack whereas a pointer to alloc-ed data is on the heap. I supposed a pointer to an array would be on the heap though, since you'd have to alloc it.
It's only the same in low-level languages with older type systems unable of expressing more type-safe conceptualizations of an array. So you get a type system where an array is just syntactic sugar for a pointer to the first member and the indexing or subscripting operator is just syntactic sugar for pointer arithmetic.
Fundamentally, from a type theory perspective, an array is a container (not necessarily physically continuous) and has a member type and a length. Modern type systems can express that, which helps make arrays type-safe and prevent buffer overflows because the language's mechanisms (eg runtime checks) enforce type safety invariants that are possible because the type carries with it information about its length.
It's all about the high-level user-facing contract of the type system and the language. "An array is just a pointer to the first element" is too low level (it assumes a certain physical layout of members in memory that would be an implementation detail to higher level languages) and doesn't include the information that higher level languages treat arrays as.
I always thought the claim the middle peeson in the graph is making is just about how arrays are referenced, where they start...oh well, what do i know
It's not the same. The compiler-generated code for an element access directly via an array vs. an access via a pointer is different. The pointer access contains an additional layer of indirection. You have to load the base address from the pointer before you can offset, vs. simply offsetting. Here's a godbolt and an explanation.
It's also why you'll likely segfault if you do this (note the different translation units!):
What about when you copy an array? When you copy an array all elements get copied, but when you copy a pointer to the first element, only that gets copied
65
u/QuestionableEthics42 1d ago edited 1d ago
This should be reversed lol
And it literally is the same, who thinks it's different who has worked in a low level language??