2

I'm a student learning C, trying to wrap my head around something.

Let's say you have some multidimensional array int multi[2][2]. The value of multi will be a pointer to the address of multi[0]. For simplicity, let's say that address is 1000. Dereferencing multi[0] extracts another address, this address the address of multi[0][0]. Dereferencing that, in turn, gets us the value (or returns the address for assignment if on the left side.)

Now, multi + 1 returns the address of the second pointer. Let's say that we have 4 byte ints (of which there are two per nested array), so the address returned by multi + 1 will be 1008. This address will contain the address of multi[1][0], which will be 1008.

So here I see a pattern: doesn't this mean that the address in multi[0], multi[1], and so forth, contains a pointer to its own address?

2
  • 1
    Why don't you take the reference &multi[0] and see with your own eyes ? Commented Oct 15, 2014 at 2:14
  • "the address in multi[0], multi[1]" -- there aren't any addresses in those, there are arrays in them. And those arrays contain ints. The only addresses to be found here are the ones produced by the compiler when you use an array in an expression ... the array is converted to a pointer because in C, arrays aren't first class objects. Commented Oct 15, 2014 at 2:38

2 Answers 2

7

Arrays and pointers are different. This topic is often presented poorly in books.

In the case of int multi[2][2], this is a block of4 contiguous ints. There are no pointers involved. C's type system divides this block up into two sub-arrays, each containing 2 ints.

These expressions: multi, multi[0] denote arrays. When you use an expression that denotes an array, in a context other than sizeof or & , then a conversion is performed, and the result of that conversion is a pointer to the first element of the array.

This pointer is an rvalue, i.e. it has the same sort of status as x + y : it's a value you can work with, but it doesn't consume any storage (at least, it's not stored as part of the array); and you can't use the & operator on it.

Sign up to request clarification or add additional context in comments.

Comments

3

The value of multi will be a pointer to the address of multi[0]

If multi, which is an array, is used in an expression, it is converted to a pointer to multi[0], the value of which is the address of multi[0]. An array, when used in an expression, is always converted to a pointer to its first element ... thus arrays in C aren't first class objects and cannot be passed to functions (only their addresses can) or assigned (memcpy is used to copy arrays).

Dereferencing multi[0] extracts another address, this address the address of multi[0][0]

There's no "extraction". dereferencing multi[0] yields an array, which is converted to a pointer to its first element. The value of this pointer is the address of multi[0][0]. All of these addresses have the same value, because they point to exactly the same place in memory ... the first of four ints.

Now, multi + 1 returns the address of the second pointer.

Again, there is no pointer in memory. multi + 1 refers to an array ... the second of two arrays of two ints. Using that array in an expression converts it to a pointer to its first element, multi[1][0].

Let's say that we have 4 byte ints (of which there are three per nested array), so the address returned by multi + 1 will be 1012.

Er, you declared int multi[2][2], which is two arrays each of which contains two arrays. So multi + 1 is 1008.

This address will contain the address of multi[1][0], which will be 1012.

It makes no sense to talk about addresses containing addresses. pointers contain addresses, but we have no pointers in memory here, we only have ints. multi[1][0] is an int and its address is 1008. multi[1] is an array of ints and its address is also 1008 ... of course, because its address is the same as the address of its first element.

So here I see a pattern: doesn't this mean that the address in multi[0], multi[1], and so forth, contains a pointer to its own address?

There are no addresses in multi[0] and multi[1], there are arrays (of ints). arrays have addresses, but in this case they don't contain addresses. The way to "see a pattern" is to think in terms of what's in memory. Here, you simply have a block of 4 ints -- two arrays of two ints each; arrays have no overhead or other extraneous content in C, they just have the data ... what you declare is what you get. The array is an abstraction, a grouping of items determined by its type and size, which exist only at compile-time and in the mind of the programmer. Thus, multi[0] contains an array, in the abstract model of a C program, but all there is in memory is four ints, the first two of which comprise that array.

The situation would be different with

int* multi[2]; 

There you have an array of two pointers to int; each pointer will point to an array of ints (once you set it to the address of an array of ints, usually obtained from malloc). Once you allocate memory for the subarrays and assign the two pointers, you can use this multi much the way you use the multi above, but the type, size, and memory layout of multi[0] and multi[1] are quite different in the two cases.

1 Comment

Wow, I was reading this answer and really appreciating the care and meticulous detail (although I thought it was a little redundant), and went to upvote it but I couldn't ... because I'm the one who wrote it. I've become a lot less patient in the years since.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.