Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>They're not <em>identical</em> pointers. They're pointers of distinct types that all point to the same memory location. Same value (sort of), different types.</p> <p>A 2-dimensional array in C is nothing more or less than an array of arrays.</p> <p>The object <code>a</code> is of type <code>int[2][2]</code>, or 2-element array of 2-element array of <code>int</code>.</p> <p>Any expression of array type is, in most but not all contexts, implicitly converted to ("decays" to) a pointer to the array object's first element. So the <em>expression</em> <code>a</code>, unless it's the operand of unary <code>&amp;</code> or <code>sizeof</code>, is of type <code>int(*)[2]</code>, and is equivalent to <code>&amp;a[0]</code> (or <code>&amp;(a[0])</code> if that's clearer). It becomes a pointer to row 0 of the 2-dimensional array. It's important to remember that this is a pointer <em>value</em> (or equivalently an <em>address</em>), not a pointer <em>object</em>; there is no pointer object here unless you explicitly create one.</p> <p>So looking at the several expressions you asked about:</p> <ul> <li><code>&amp;a</code> is the address of the entire array object; it's a pointer expression of type <code>int(*)[2][2]</code>.</li> <li><code>a</code> is the name of the array. As discussed above, it "decays" to a pointer to the first element (row) of the array object. It's a pointer expression of type <code>int(*)[2]</code>.</li> <li><code>*a</code> <em>dereferences</em> the pointer expression <code>a</code>. Since <code>a</code> (after it decays) is a pointer to an array of 2 <code>int</code>s, <code>*a</code> is an array of 2 <code>int</code>s. Since that's an array type, it decays (in most but not all contexts) to a pointer to the first element of the array object. So it's of type <code>int*</code>. <code>*a</code> is equivalent to <code>&amp;a[0][0]</code>.</li> <li><code>&amp;a[0]</code> is the address of the first (0th) row of the array object. It's of type <code>int(*)[2]</code>. <code>a[0]</code> is an array object; it doesn't decay to a pointer because it's the direct operand of unary <code>&amp;</code>.</li> <li><code>&amp;a[0][0]</code> is the address of element 0 of row 0 of the array object. It's of type <code>int*</code>.</li> </ul> <p>All of these pointer expressions refer to the same location in memory. That location is the beginning of the array object <code>a</code>; it's also the beginning of the array object <code>a[0]</code> and of the <code>int</code> object <code>a[0][0]</code>.</p> <p>The correct way to print a pointer value is to use the <code>"%p"</code> format <em>and</em> to convert the pointer value to <code>void*</code>:</p> <pre><code>printf("&amp;a = %p\n", (void*)&amp;a); printf("a = %p\n", (void*)a); printf("*a = %p\n", (void*)*a); /* and so forth */ </code></pre> <p>This conversion to <code>void*</code> yields a "raw" address that specifies only a location in memory, not what type of object is at that location. So if you have multiple pointers of different types that point to objects that begin at the same memory location, converting them all to <code>void*</code> yields the same value.</p> <p>(I've glossed over the inner workings of the <code>[]</code> indexing operator. The expression <code>x[y]</code> is by definition equivalent to <code>*(x+y)</code>, where <code>x</code> is a pointer (possibly the result of the implicit conversion of an array) and <code>y</code> is an integer. Or vice versa, but that's ugly; <code>arr[0]</code> and <code>0[arr]</code> are equivalent, but that's useful only if you're writing deliberately obfuscated code. If we account for that equivalence, it takes a paragraph or so to describe what <code>a[0][0]</code> means, and this answer is probably already too long.)</p> <p>For the sake of completeness the three contexts in which an expression of array type is <em>not</em> implicitly converted to a pointer to the array's first element are:</p> <ul> <li>When it's the operand of unary <code>&amp;</code>, so <code>&amp;arr</code> yields the address of the entire array object;</li> <li>When it's the operand of <code>sizeof</code>, so <code>sizeof arr</code> yields the size in bytes of the array object, not the size of a pointer; and</li> <li>When it's a string literal in an initializer used to initialize an array (sub-)object, so <code>char s[6] = "hello";</code> copies the array value into <code>s</code> rather than nonsensically initializing an array object with a pointer value. This last exception doesn't apply to the code you're asking about.</li> </ul> <p>(The <a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf" rel="nofollow noreferrer">N1570</a> draft of the 2011 ISO C standard incorrectly states that <code>_Alignof</code> is a fourth exception; this is incorrect, since <code>_Alignof</code> can only be applied to a parenthesized type name, not to a expression. The error is corrected in the final C11 standard.)</p> <p>Recommended reading: Section 6 of the <a href="http://www.c-faq.com/" rel="nofollow noreferrer">comp.lang.c FAQ</a>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload