15 ms·
Are pointers and arrays equivalent in C? (2009)
- sago 12y agoExcellent. Years ago (15-20?) I wrote a program with the bug he mentions at the end. Way before Stack Overflow was a Google away. I could not work out why it crashed. I ended up rewriting it and it worked, but never understood what the bug was (in my mind it has been logged as 'don't extern arrays' ever since). I just read that and ah-ha!
- kazinator 12y agoAh Betteridge's law of headlines at work! Arrays are aggregates of contiguously allocated objects. Pointers are values indicating the storage locations of objects. Thus, not equivalent. Pointers are involved when you access an array. That doesn't make it an array. Just like scanning written text on a piece of paper using your index finger does not mean that "paper" and "your index finger" are equivalent. That's true even if you always instantiate an index finger before evaluating a piece of paper: co-ocurrence is not equivalence.
- TeMPOraL 12y agoThe key part of the headline here is "in C". In C, it's known that "name of the array is the address to its first element" which is one of the things that lead people into thinking that pointers and arrays are equivalent - in C.
- kazinator 12y agoNo, the name of an array is not the address to its first element. For instance, this equivalence is not required: (sizeof array) == (sizeof &array[0]) though it could be true by coincidence. If array were the address of the first element, then it would always have the same size. Be careful with words like "is". Oh, the above is "in C", by the way. We wouldn't want not to satisfy your key point!
- MaulingMonkey 12y agoQuite right. A set of interesting equalities: (void*)&array == (void*)&array[0] // likely true (void*)&pointer == (void*)&pointer[0] // likely false (although it could be true by coincidence) A pointer to an array is the address of the first element. The name of an array can be trivially and implicitly converted to the address to it's first element, but this conversion creates a (temporary) pointer, it does not make the array itself a pointer! The array (nor it name) is not in and of itself storage for any such address, it is no pointer, and as a result &array won't give you back a pointer-to-pointer because there's no underlying 4-8 byte storage for the underlying pointer - there's no permanent pointer to point to.
- kazinator 12y agoSure: (void*)&array == (void*)&array[0] // likely true That is true by definition. The address of the first element is the same as that of the array, period. They cannot convert to different void pointers.
- pqomdv 12y agoWhich definition is that? You probably though of: array == &array[0] which is always true. This: (void*)&array == (void*)&array[0] which simplifies to: (void*)&array == (void*)array is not. C doesn't guarantee that the values of &array and array are the same. The types T( * )[ * ] and T* are not even compatible and those two pointers are allowed to have different sizes and representation.
- kazinator 12y agoThe first element of an array is located at the address of an array. Even if the pointer-to-array and pointer-to-element types have different size and representation, they point to the same place. The resulting pointer-to-void converted values must point to that place, and have the same type. This relationship is also true between a pointer to a struct and a pointer to the first element. And also among pointers to the elements of a union.
- EpicEng 12y ago...and another one bites the dust...
- gnuvince 12y agoWhy is this comment being downvoted? The explanation is correct and the analogy quite good too!
- DanBC 12y agoI suspect it's downvoted for the mention of Betteridges Law of Headlines, which (rightly) earns downvotes whenever it's mentioned.
- kazinator 12y agoLook, it even worked for your comment! Must be true.
- kazinator 12y agoBecause the number of people who believe that arrays are pointers vastly outnumbers those who don't, and many of those clueless n00bs have karma >= 500 on HN, or whatever the level is to be able to downvote. Judging by one answer, some people don't believe that the comment could even be about C, so wrong it must be! Nope; I simply refuse to delete a comment that is civil and correct just because of some fluffy downvotes. It stays and that's that.
- tomku 12y agoBecause it's explaining the wrong confusion. People who are confused about pointers and arrays in C don't think that the concept of a pointer is the same as the concept of an array - they think that in C, the two have the same semantics. That explanation and analogy do nothing to explain the semantic difference, and honestly come off as a pretty condescending by essentially saying "Well they're different things, of course they're different!" The poster probably did not help matters after that by calling the downvoters "clueless n00bs" or making a self-righteous statement about how they won't delete the comment just because of downvotes. That kind of toxic behavior just ensures that you'll get more downvotes.
- deleted 12y ago[deleted]
- justinmk 12y agoThis is a well-presented version of http://c-faq.com/aryptr/ http://c-faq.com/aryptr/.
- krylon 12y agoWhen I was first learning C, pointers scared the crap out of me, and it took me longer to understand them than I am comfortable admitting to. Then I got pointers and this big "NOW I get it"-moment and felt really clever. And then came the moment I had a problem with pointers and arrays being interchangeable most of the time and became very confused about when they were not equivalent. People who like C (which I do, too) will often point out C's perceived simplicity when compared with, say, C++, but C definitely does have its murky corners, and the need for backward compatibility with existing code will most likely prevent them from getting cleaned up.
- lfowles 12y agoMuch of my initial confusion with C style pointers was using & to show pass-by-reference and to get the address of a variable. It still doesn't make sense, but at least I've got it deeply ingrained now :\
- pikachu_is_cool 12y agoC doesn't have pass by reference.
- krylon 12y agoNo, it does not. That is why pointers are so important in C. But to a newbie, the difference between a local variable and a pointer to it can be rather confusing, and the fact that with arrays this difference becomes rather blurry unless one has a good mental model of what the compiler turns your code into, makes it even more confusing. Given that some data structure such as linked lists are highly inconvenient or even impossible to implement without dynamic memory management, one is pretty much bound to writing code that is either primitive (not always a bad thing) or horrible to look at (and maintain) until one understands pointers.
- ArkyBeagle 12y agoIt has "pass a pointer by value", which works out conceptually to the same thing, only with slightly different syntax.
- userbinator 12y agoI like to think of them as being different and the equivalence - in some cases - only comes from what is known as the "array-pointer-decay" semantic: http://www.lysator.liu.se/c/c-faq/c-2.html http://www.lysator.liu.se/c/c-faq/c-2.html This is why &a+n is not equivalent to a+n, something that a surprisingly large number of "C pointer tutorials" seem to get wrong.
- mpweiher 12y agoAlso sizeof is different. char a[20]; char *b; sizeof a -> the size of the array (20) sizeof b -> the size of the pointer (8 on my machine)
- syncsynchalt 12y agoYes, to me this is the largest difference, since it will cause runtime errors instead of compile problems.
- armada651 12y agoI was really surprised that it wasn't mentioned since it is the most important difference and a cause of frustration for programmers just beginning to learn C.
- wbsun 12y agoAren't everything equivalent in C?
- wbsun 12y agoWhy down vote? I don't think anyone who disagrees with this really knows C, or more accurately, how most computers work. Can down voters name something that can't be converted to any others? Unless you are using a Harvard architecture, anything in memory are equivalent.
- Ono-Sendai 12y agoC has types. Variables of different types generally aren't equivalent.
- SamReidHughes 12y agoYou can't just freely reinterpret memory in C without following certain rules, or you get undefined behavior. Also, types have sizes, and alignment restrictions, and on some systems, trap representations.
- peterfirefly 12y agohttp://blog.regehr.org/archives/213 http://blog.regehr.org/archives/213 I would downvote you, too, if I could.
- wbsun 12y agoHmm, I am glad to know so many people stop at the boundary of compiler's restrictions and abstractions. btw, please do not misuse and misinterpret John's blog sooo, he is one of my most respected professors.
- je-so 12y agoAnother interesting thing to know about pointer and arrays is: #include <stdio.h> typedef int a_t[100]; int main(void) { int a[100]; a_t* p = &a; // all printed pointer values are equal printf("%p %p %p %p\n", (void*)a, (void*)&a, (void*)p, (void*)*p); return 0; }
- golergka 12y agoWill I be correct if I say that in the end, the difference is that arrays are immutable (in the address that they point to) and pointers are not?
- krylon 12y agoIn part. Pointers can be made constant in two ways, a) constant in that they cannot be used to change the memory they point to, and b) in that one cannot change what memory they point to. char const * ptr_a; /* You cannot write to the memory pointed to by ptr */ char * const ptr_b; /* You cannot change what ptr_b points to */ char const * const ptr_ab; /* You neither change what ptr_ab points to nor the memory it points to - at least not through this pointer */
- noselasd 12y agoWell, there's some other important differences sizeof somearray vs sizeof somepointer are naturally different. &somearray vs &somepointer are very different types. Which also means that somearray + 10 vs somepointer + 10 yields very different results.
- Peaker 12y agoNo. An array has size (N * sizeof(element)). Arrays are immutable in their address in the same sense that any lvalue is immutable in its address. int x; int y[2]; The two declarations above are similar, one happens to be an (int). The other an (int[2]). The difference is that when you take the rvalue of an int, say x, you get an rvalue int. When you take the rvalue of an int[2], you get a degraded (int *) rvalue that points to its first element. Until you convert the array object to an rvalue, it is no more related to an (immutable) pointer than the above int. Both have an immutable address, like all lvalues do.
- wsxcde 12y agoOne other difference on modern compilers relating specifically to character arrays: This will work fine: char arr[] = "stuff"; printf("arr:%s\n", arr); arr[0] = 'b'; arr[1] = 'l'; printf("arr:%s\n", arr); arr is allocated on the stack (not heap, sorry about the mistake) and is mutable. But the following will segfault: char* ptr = "stuff"; printf("ptr:%s\n", ptr); ptr[0] = 'b'; ptr[1] = '1'; printf("ptr:%s\n", ptr); Strings are allocated in the read-only data segment. Technically you can only write const char* ptr = "stuff", but due to wanting to remain backward compatibile, gcc will let you write the above and not even warn you unless you use -Wall or similar.
- deanstag 12y agoYeah. I was exploring exactly this problem when i came across this original article. Later i saw that "char arr[] = "stuff" " actually inserts assembly code that puts the value stuff into the stack. That was interesting news to me. stackoverflow.com/questions/29184100/char-array-and-pointer-initialization-semantics/29184190#29184190
- halayli 12y agoThis is straight from Expert C Programming book, including the diagrams. It's dishonest to recycle and present it as if it's yours with a reference mention at the very bottom. This is not a reference, it's a copy.
- dmunoz 12y agoWhat was copied? I flipped through my copy of Expert C Programming and didn't see either of the diagrams. If instead by "straight from" you mean "similar to", well, there is only a handful of ways to explain this material so of course they are going to be similar. Please don't throw around accusations of copying lightly. I would like to see more material like this shared, not less.
- logicallee 12y agoI agree with the other poster. I was going to upvote you earlier, and torrented the book you refer to for verification (ironically because I don't believe material should be stolen like this), but apparently I never got around to it because I was able to downvote you just now. The reason I never finished upvoting you was that I didn't think I found the right book: Expert C Programming doesn't match your description (of not being a reference, but rather the article being a copy of it). I didn't find the diagrams, and the text was very different. So it sounds like your accusation is way off-base, and you should specify that you were wrong. Maybe you were just reminded of that other book but didn't verify that the article was a copy of it?
- signa11 12y ago> straight from Expert C Programming book, including the diagrams no it is not. in fact, this article cites the book that you mention as one of the references.
- deleted 12y ago[deleted]
- Peaker 12y agoArrays are not necessarily located at compile-time-known positions. The compiler translates all symbolic names to addresses, regardless of whether it is an array or not.
- Animats 12y agoYou can actually pass an array as an array in C99: #include <stdlib.h> void f(size_t m, size_t n, float a[m][n]) { for (size_t i = 0; i < m; i++) { for (size_t j=0; j < n; j++) { a[i][j] = 0; } } } int main(int argc, char* argv[]) { float a[10][20]; f(10,20,a); } This "conformant array" feature was supported in C99. GCC supports it. Microsoft didn't like it, though, and didn't implement it, so nobody uses it, and it was made optional in later versions of the C standard. It doesn't do what it looks like it does. The last subscript is totally ignored by the compiler. For 1D arrays, it's not only ignored, the object is still passed as a pointer to the element type. I once proposed making arrays in C size-safe by taking conformant arrays seriously and adding some features to make them more useful.[1] After much discussion, the idea was considered sound, but not popular enough. So buffer overflows in C continue. I have great hopes for Rust. [1] http://animats.com/papers/languages/safearraysforc43.pdf http://animats.com/papers/languages/safearraysforc43.pdf
- Peaker 12y agoThat's ordinary C89 behavior, not a C99 feature, and I'm pretty sure Microsoft supports it too. The C99 feature here is VLA (variable-length array), arrays whose length is a runtime value. If you change m and n to be constants, it works with C89. The rule is simple (yet confusing!): In a function prototype, if the parameter (top-level) type is an array, it is de-sugared to be an element-pointer instead. Thus, the code you wrote with constants instead: #define M 10 #define N 20 void f(size_t m, size_t n, float a[M][N]) De-sugars, as per C89 ordinary rules, to: void f(size_t m, size_t n, float (*a)[N]) And it is an ordinary array degradation to a pointer, except instead of pointing to a float, it happens to point at a float[N].
- Animats 12y agoVariable length arrays are a different feature. They are local temporary arrays of variable size: int f(size_t n) { int temp[n]; /* local array of size n */ ... } Someone once used that feature in the Linux kernel to get temp space for a string. It was taken out, because those arrays went on the stack and thus allowed large kernel stack growth based on data from outside the kernel. Nobody uses that feature either.
- eliben 12y agoFunny how old articles resurface suddenly :-) It's great that HN still likes technical content, though. FWIW I also wrote a (shorter) follow-up post a few months later about multi-dimensional arrays and their relation to pointers-to-pointers: http://eli.thegreenplace.net/2010/04/06/pointers-vs-arrays-in-c-part-2d http://eli.thegreenplace.net/2010/04/06/pointers-vs-arrays-i...