Question:
In C language array is actually pointer to a memory location, so what do the following terms mean?
雲の守護者
2012-06-27 13:09:56 UTC
define ROWS 5
#define COLS 5

int my_array[ROWS][COLS] = { {1, 2, 3, 4,5}, {6, 7, 8, 9, 0}, {10, 11, 12, 13, 14}, {15, 16, 17, 18, 19}, {20, 21, 22, 23, 24}, };

Now what do the following mean?
my_array
&my_array
*my_array
my_array[0]

I wrote a program and they all have the same value which is 144 on this machine!? It looks like address but don't know why it does not look like any of the entries in the array itself.

Than *(my_array +1) gives same value as my_array +1, but **(my_array +1) with double * gives the result 6. WHY?
I have come very close to subduing this pointer concept now.
Four answers:
Jonathan
2012-06-28 00:46:44 UTC
You are asking good questions about C. I'm happy, in fact, to see them. Most folks just "move on" and get on with things that seem to work and never do "dig in" when their mental models are at question. You SHOULD ask. Others SHOULD ask. First off, take a look at the link below. Part of what you are asking is handled there. Part is handled by "thinking like a compiler."



When you write:



    #define ROWS 5

    #define COLS 5

    int my_array[ROWS][COLS];



What happens?



The C compiler generates instructions to the linker to allocate a consecutive region able to hold 25 integer values and tells the linker to give that region a symbolic name of "my_array." my_array is then just a linker variable and once the linker figures out the address, everywhere the linker sees 'my_array' in the compiler output it stuffs that address value there, instead.



Before I go further, what does the C compiler do when you write:



    my_array[3][2]



So the C compiler sees 'my_array' as a "pointer to an array of COLS integers." Or "int (*)[COLS]" in C-speak. When you pass this as a parameter to printf(), you won't get any errors since printf() parameters can have any type at all. What C will do is write out 'my_array' in the object file so that once the linker figures out where the array is at it can stuff that address there. You write 'my_array' and C emits "when you get an address for my_array, put the value here" to the linker. So the linker does.



The C compiler sees '&my_array' as a "pointer to an array of ROWS arrays of COLS integers." Or "int (*)[ROWS][COLS]" in C-speak. Different type. But that's okay. When you put that in a parameter to printf(), the C compiler emits "when you get an address for my_array, put the value here" to the linker. So the linker does. And you get the same value, too. Why? Because the linker doesn't know any better. The C compiler told it to put down whatever my_array's value is. And the C compiler doesn't know any better, either, because prinft() accepts anything. So the C compiler can't even flag an error.



The compiler sees '*my_array' as a "pointer to an integer." Or "int (*)" in C-speak. Remember, 'my_array' is "int (*)[COLS]" in C-speak. Dereferencing that means "int (*)". Do you see a pattern now?



    my_array         int (*)[COLS]

    &my_array       int (*)[ROWS][COLS]

    *my_array        int (*)



But every one of them still a pointer. So we could now guess that:



    **my_array      int



And you'd be right.



Array syntax is really just a convenience for pointer syntax. I think that is the bottom line. Arrays are kind of "pasted on" afterwards and not designed in at the beginning so much. Pointers are real meat and potatoes, arrays are just sugar.



Say I had this:



    int a[10];



When I write a[3] the C compiler immediately turns that into (*((3)+(a))) without missing a heartbeat. It never even sees the brackets. It's all over before it starts.



So when you write my_array[3][2], the C compiler immediately asks itself "What type is my_array?" And gets "int (*)[COLS]" as the answer. The following [3] then tells the C compiler to use the 4th array of COLS integers, so the C compiler generates:



1.      (*(((3)*COLS)+(my_array)))



But also notices that because of the dereference that the type is now "int (*)". Still a pointer. So now it encounters the [2] and says:



2.      (*((2)+(*(((3)*COLS)+(my_array)))))



And now that is an integer! No longer a pointer.



So what happens when the compiler sees my_array[0]? Well, just what I wrote in (1) above, except that the 3 is replaced with 0:



3.      (*(((0)*COLS)+(my_array)))



What's the type? Just as I wrote before: "int (*)". So it is still a pointer to memory. Yup. The C compiler sticks 'my_array' there for the linker to stuff with the address, once again. So you get to see the same thing printed out, again. Because the type was still a pointer. A different type of pointer, true. But a pointer, still.



So all were still just pointers.



By the way, just to really make the point that arrays are just sugar and pointers are the real deal, look at this. If I defined:



4.      int a[10];



Then,



5.      5[a]



is perfectly legal and says the same thing as a[5].



Think about it and why.



EDIT: I said that &my_array is "int (*)[ROWS][COLS]". How might you use that thing? Well, you could write,



6.      int j= (&my_array)[2][3][4];



It means you want the 3rd matrix, the 4th row, and the 5th column.



It's a pointer to an array of 2D integer matrices. my_array is a pointer to an array of integer vectors (1D). and *my_array is a pointer to a single vector of integers. And finally **my_array is an integer.
Leon
2012-06-27 20:25:17 UTC
my_array is the memory address of the first element of the array.

&my_array returns a reference to the memory address of the first element of the array.

*my_array dereferences the first element of the array, and gives you the actual value stored in that memory address.

my_array[0] is the same as *my_array.



*(my_array+1) = my_array[1].



Let's take apart *(my_array+1).



my_array is the address of the first element, so my_array + 1 is the address of the second element. Look up pointer arithmetic to get a better understanding of this.

Therefore, *(my_array + 1) would be dereferencing the second element of the array.



Why does a double array give a different value? Doubles are larger than ints, which mean that a double array takes up more memory addresses per element. As every element is accessed by adding 1, each successive addition goes over a given number of addresses according to the type.



Hope this clears everything up.
godfatherofsoul
2012-06-27 20:36:07 UTC
my_array is a pointer to a pointer; in this case the address of a memory location containing more memory addresses; i.e. a 2D array



&my_array is a pointer to a pointer to a pointer; i.e. a pointer to a 2D array



*my_array is a pointer; i.e. the first row in your 2D array



my_array[0] is also a pointer; also the first row in your 2D array



*my_array and my_array[0] are equivalent



Pointers support overloaded operators so you can do math with a pointer. That's why you can add and subtract. If you're seeing the same value for first 2, that's probably because your IDE is returning the underlying address of the 2D array. I bet if you add any number of & in front of my_array, it'll remain the same.



This is validated by the fact that *(my_array+1) displays the same value as my_array+1. You're advancing the pointer to the 2nd row in your 2D array. Now, whether you dereference the pointer or not (the other use of the '*' operator), the underlying memory address is the same.



For **(my_array+1), first you resolve my_array+1. That means move the 2D array pointer to the second element (the 2nd row). You can think of it as a pointer to the pointer after the first pointer.



Each asterisk dereferences a pointer (meaning, returns the underlying value. So, the first dereference returns the pointer to the 2nd row. The 2nd dereference returns the 1st element in that row (an int which is 6).



If it's not clear by now, pointers suck. They're horribly error prone even if they are more efficient. It's very easy to lose you mental train of thought and screw something up which will create very difficult to diagnose errors. The worst part of pointers is that the terminology and symbols are overloaded; meaning they have different meanings in different contexts. In C++ & is a reference-type and also returns a pointer. The '*' is a pointer indicator and also used to dereference a pointer.
Cubbi
2012-06-28 02:51:19 UTC
> In C language array is actually pointer to a memory location,

nonsense. That's how it was in the long extinct B language. In C language, array and pointer are two completely different things, although pointers to elements of an array have a few special properties.



"my_array" is the array itself. It is a chunk of memory that holds 25 ints back to back (100 bytes on most systems), and which is assigned a type int[5][5], that is, an array of five arrays of five ints each.



"&my_array" is an expression that evaluates to a pointer to the array. That pointer holds the address of the array. It is a fairly small object, 8 bytes on 64-bit systems, 4 bytes on 32-bit systems



"*my_array" is an expression that first constructs a pointer to the first element of the array (that is, to the first five-int row), and then dereferences it, resulting in the first row of your array. That is, a chunk of memory that holds 5 ints side by side and is assigned the type int[5]



"my_array[0]" is also the first element of the array, that is the first row (a chunk of memory that holds 5 ints side-by-side and has the type int[5])



If you want to see practical difference, print their sizes:





printf("%zu %zu %zu %zu", sizeof my_array, sizeof &my_array, sizeof *my_array, sizeof my_array[0]);



I get:



100 8 20 20



online demo: http://ideone.com/hwv2c (ideone is apparently a 32-bit system, it prints 100 4 20 20)


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...