After a lot of fight I figured out in a declaration like int A[2][3], A is of a type compatible with int(*)[3] . My understanding is A can be used to point to the first three elements and A + 1 to the next three.
Is there any way I can declare an array of pointers to array.
ptr_array
+----+ +----+----+----+
| | ----> | | | |
| | | 24 | 25 | 26 |
+----+ +----+----+----+
| | | 44 | 45 | 46 |
| | ----> | | | |
+----+ +----+----+----+
Array of pointers two dimensional array of three integers
to array of 3
How do I declare ptr_array, so that
ptr_array[0] = A;
and
ptr_array[1] = A + 1;
Multidimensional arrays in C are arrays of arrays. The elements of an n-dimensional array are (n-1) dimensional arrays. A[0], for example, is an int [3].
A: |24|25|26|44|45|46|
A[0]: |24|25|26|
A[1]: |44|45|46|
In certain contexts, an array is converted to a pointer to the first element of the array, but the array is not itself a pointer.
From the C standard, § 6.5.2.1-3:
3 Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n≥2) with dimensions i× j×...×k, then E (used as other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with dimensions j × . . . × k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the pointed-to (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).
4 EXAMPLE Consider the array object defined by the declaration
int x[3][5];
Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an array of five ints. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually entails multiplying i by the size of the object to which the pointer points, namely an array of five int objects. The results are added and indirection is applied to yield an array of five ints. When used in the expression x[i][j], that array is in turn converted to a pointer to the first of the ints, so x[i][j] yields an int.
To create a ptr_array as diagrammed:
int (*ptr_array[2])[3]
ptr_array[0] = A;
ptr_array[1] = A+1;
// or:
ptr_array[0] = &A[0];
ptr_array[1] = &A[1];
// or even:
ptr_array[0] = (int(*)[3])A[0];
ptr_array[1] = (int(*)[3])A[1];
// though this last shouldn't be used in production code
Here's how to work out the declaration. From the diagram, ptr_array is an array of size 2.
... ptr_array[2] ...
The elements of the array are pointers
*ptr_array[2]
to arrays of size 3
(*ptr_array[2])[3]
of ints
int (*ptr_array[2])[3]
If you're ever not certain how to declare something like this, you can use cdecl:
cdecl> declare ptr_array as array 2 of pointer to array 3 of int
int (*ptr_array[2])[3]
You can install a command line version of cdecl (if not already installed) on your development computer. The exact method depends on the platform. Check the documentation and web at large.
In a declaration like int A[2][3], A is of a pointer to an array of 3 which means A is of type int(*)[3]
No. A is an array, not a pointer. It is of type int [2][3].
How do I declare ptr_array, so that
ptr_array[0] = A;
and
ptr_array[1] = A + 1;
If by A+1 you mean "the second length-3 array", then you simply need to do this:
int (*ptr_array)[3] = A;
An array decays to become a pointer to its first element in most situations. I suggest reading the C FAQ on arrays and pointers: http://c-faq.com/aryptr/index.html.
Yes. You can declare an array to be of anything you like.
Your declaration
int A[2][3];
defines a two-dimensional array of ints, of size 2x3. A[0] is a pointer to the start of an array of 3 ints, as is A[1]. A[0][0] is the first element in the first array. A[1][2] is the last element of the last array.
A[2][3] is more an array than a pointer. There are only some cases you can consider array as pointers. A is an array to 6 integers. A is of type integer array.
You can declare ptr_array[0] as A[0] and ptr_array as A[1].
Related
Say I have the following code:
// x = whatever number
int *arr_of_ptr[x];
int (*ptr_to_arr)[x]
int **p1 = arr_of_ptr;
int **p2 = ptr_to_arr;
My understanding of arr_of_ptr is that "dereferencing an element of arr_of_ptr results in an int" - therefore the elements of arr_of_ptr are pointers to integers. On the other hand, dereferencing ptr_to_arr results in an array that I can then nab integers from, hence ptr_to_arr points to an array.
I also have a rough understanding that arrays themselves are pointers, and that arr[p] evaluates to (arr + p * sizeof(data_type_of_arr)) where the name arr decays to the pointer to the first element of arr.
So that's all well and good, but is there any way for me to tell whether p1 and p2 are pointers to arrays or arrays of pointers without prior information?
My confusion mostly stems from the fact that (I think) we can evaluate int **p two ways:
*(p + n * size) is what's giving me an int
(*p + n * size) is what's giving me an int
In hindsight this question might be poorly worded because I'm confusing myself a bit just looking back on it, but I really don't know how to articulate myself better. Sorry.
The main difference is that this is legal:
int **p1 = arr_of_ptr;
While this is not:
int **p2 = ptr_to_arr;
Because arr_of_ptr is an array, it can (in most contexts) decay to a pointer to its first element. So because the elements of arr_of_ptr are of type int *, a pointer to an element has type int ** so you can assign it to p1.
ptr_to_arr however is not an array but a pointer, so there's no decaying happening. You're attempting to assign an expression of type int (*)[x] to an expression of type int **. Those types are incompatible, and if you attempt to use p2 you won't get what you expect.
First,
I also have a rough understanding that arrays themselves are pointers, and that arr[p] evaluates to (arr + p * sizeof(data_type_of_arr)) where the name arr decays to the pointer to the first element of arr.
This isn't strictly correct. Arrays are not pointers. Under most circumstances, expressions of array type will be converted ("decay") to expressions of pointer type and the value of the expression will be the address of the first element of the array. That pointer value is computed as necessary and isn't stored anywhere.
Exceptions to the decay rule occur when the array expression is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal used to initialize a character array in a declaration.
Having said all that, ptr_to_arr has pointer type, not array type - it will not "decay" to int **.
Given the declaration
T arr[N];
the following are true:
Expression Type Decays to Equivalent expression
---------- ---- --------- ---------------------
arr T [N] T * &arr[0]
*arr T n/a arr[0]
arr[i] T n/a n/a
&arr T (*)[N] n/a n/a
The expressions arr, &arr[0], and &arr all yield the same value (modulo any differences in representation between types). arr and &arr[0] have the same type, "pointer to T" (T *), while &arr has type "pointer to N-element array of T" (T (*)[N]).
If you replace T with pointer type P *, such that the declaration is now
P *arr[N];
you get the following:
Expression Type Decays to Equivalent expression
---------- ---- --------- ---------------------
arr P *[N] P ** &arr[0]
*arr P * n/a arr[0]
arr[i] P * n/a n/a
&arr P *(*)[N] n/a n/a
So given your declarations, it would be more correct to write something like this:
int arr[x];
int *p1 = arr; // the expression arr "decays" to int *
int *arr_of_ptr[x];
int **p2 = arr_of_ptr; // the expression arr_of_ptr "decays" to int **
/**
* In the following declarations, the array expressions are operands
* of the unary & operator, so the decay rule doesn't apply.
*/
int (*ptr_to_arr)[x] = &arr;
int *(*ptr_to_arr_of_ptr)[x] = &arr_of_ptr;
Again, ptr_to_arr and ptr_to_arr_of_ptr are pointers, not arrays, and do not decay to a different pointer type.
EDIT
From the comments:
Can I just hand-wavily explain it as: an array of pointers has a name that can decay to a pointer,
Yeah, -ish, just be aware that it is hand-wavey and not really accurate (which is shown by example below). If you are a first-year student, your institution isn't doing you any favors by making you deal with C this early. While it is the substrate upon which most of the modern computing ecosystem is built, it is an awful teaching language. Awful. Yes, it's a small language, but aspects of it are deeply unintuitive and confusing, and the interplay between arrays and pointers is one of those aspects.
an array of pointers has a name that can decay to a pointer, but a pointer to an array, even when dereferenced, does not give a give me something that decays to a pointer?
Actually...
If ptr_to_arr has type int (*)[x], then the expression *ptr_to_arr would have type int [x], which would decay to int *. The expression *ptr_to_arr_of_ptr would have type int *[x], which would decay to int **. This is why I keep using the term "expression of array type" when talking about the decay rule, rather than just the name of the array.
Something I have left out of my explanations until now - why do array expressions decay to pointers? What's the reason for this incredibly confusing behavior?
C didn't spring fully-formed from the brain of Dennis Ritchie - it was derived from an earlier language named B (which was derived from BCPL, which was derived from CPL, etc.)1. B was a "typeless" language, where data was simply a sequence of words or "cells". Memory was modeled as a linear array of "cells". When you declared an N-element array in B, such as
auto arr[N];
the compiler would set aside all the cells necessary for the array elements, plus an extra cell that would store the numerical offset (basically, a pointer) to the first element of the array, and that cell would be bound to the variable arr:
+---+
arr: | +-+-----------+
+---+ |
... |
+---+ |
| | arr[0] <--+
+---+
| | arr[1]
+---+
...
+---+
| | arr[N-1]
+---+
To index into the array, you'd offset i cells from the location stored in arr and dereference the result. IOW, a[i] was exactly equivalent to *(a + i).
When Ritchie was developing the C language, he wanted to keep B's array semantics (a[i] is still exactly equivalent to *(a + i)), but for various reasons he didn't want to store that pointer to the first element. So, he got rid of it entirely. Now, when you declare an array in C, such as
int arr[N];
the only storage set aside is for the array elements themselves:
+---+
| | arr[0]
+---+
| | arr[1]
+---+
...
+---+
| | arr[N-1]
+---+
There is no separate object arr which stores a pointer to the first element (which is part of why array expressions cannot be the target of an assignment - there's nothing to assign to). Instead, that pointer value is computed as necessary when you need to subscript into the array.
This same principal holds for multi-dimensional arrays as well. Assume the following:
int a[2][2] = { { 1, 2 }, { 3, 4 } };
What you get in memory is the following:
Viewed as int Viewed as int [2]
+---+ +---+
a: | 1 | a[0][0] a:| 1 | a[0]
+---+ + - +
| 2 | a[0][1] | 2 |
+---+ +---+
| 3 | a[1][0] | 3 | a[1]
+---+ + - +
| 4 | a[1][1] | 4 |
+---+ +---+
On the left we view it as a sequence of int, while on the right we view it as a sequence of int [2].
Each a[i] has type int [2], which decays to int *. The expression a itself decays from type int [2][2] to int (*)[2] (not int **).
The expression a[i][j] is exactly equivalent to *(a[i] + j), which is equivalent to *( *(a + i) + j ).
As detailed in The Development of the C Language
#include <stdio.h>
int main(void) {
// your code goes here
int arr[] = {1,2,3};
int *p1 = &arr[0];
int *p2 = &arr[1];
int *p3 = &arr[2];
int* arr2[3];
arr2[0] = p1;
arr2[1] = p2;
arr2[2] = p3;
int *p4 = &arr;
printf("%d\n", sizeof(p4));
printf("%d\n", sizeof(arr2));
printf("%d\n", *p4); // not **p4
printf("%d\n", **arr2);
return 0;
}
In the above code arr is a normal integer array with 3 elements.
p1, p2, and p3 are normal pointers to these elements.
arr2 is an array of pointers storing p1, p2, and p3.
p4 is a pointer to array pointing to array arr
According to your question, you need to differentiate between p4 and arr2
Since, p4 is a pointer, its size is fixed (8 bytes) while size of arr2 vaires on how many elements it contains (8x3=24).
Also, to print value contained in p4 use use single dereferencing (*p4) not **p4 (illegal), while to print value contained in arr2 use use double dereferencing (**arr2).
The output of above code is :
8
24
1
1
Here is a sample code. I believe array is an address while *array is the value
int array[7][7];
array == *array
But I found out array same as *array. How is it?
Here
int arr[7][7];
arr is two dimensional array containing 7 one dimensional array & each one dimensional array contains 7 elements. It looks like
arr[0][0] arr[0][1] arr[0][2] arr[0][3] arr[0][4] arr[0][5] arr[0][6] arr[0][7]
| | | | | | | | | ....|
---------------------------------------------------------------------- -----
(0x100) | |
arr[0] (0x100) arr[1] ... arr[6]
| |
-----------------------------------------------
|
arr(0x100) -assume base address is 0x100
arr, arr[0] and address of arr[0][0] all results in same i.e arr and *arr results in same address.
You can't have a value without a type.
123456789 just like that is nothing; you need to know if it's an integer, a double, a pointer, ...
So, I like to think of it as the pair (value, type).
And that value could be (123456789, int), or (123456789, double), or (123456789, char*), ... which are all different pairs (with the same value).
In your case you have (<address>, char(*)[7]) not the same as (<address>, char*)
An element of a multidimensional array is an array, which in many cases decays to a pointer to its first element.
So, in both cases you have a pointer to the same location in memory.
As of C, they aren't technically the same, because they point to differents objects, but because those objects have the same address, and because most implementations store all pointers in the same format, they happen to evaluate equal.
Going through some C interview questions, I've found a question stating "How to find the size of an array in C without using the sizeof operator?", with the following solution. It works, but I cannot understand why.
#include <stdio.h>
int main() {
int a[] = {100, 200, 300, 400, 500};
int size = 0;
size = *(&a + 1) - a;
printf("%d\n", size);
return 0;
}
As expected, it returns 5.
edit: people pointed out this answer, but the syntax does differ a bit, i.e. the indexing method
size = (&arr)[1] - arr;
so I believe both questions are valid and have a slightly different approach to the problem. Thank you all for the immense help and thorough explanation!
When you add 1 to a pointer, the result is the location of the next object in a sequence of objects of the pointed-to type (i.e., an array). If p points to an int object, then p + 1 will point to the next int in a sequence. If p points to a 5-element array of int (in this case, the expression &a), then p + 1 will point to the next 5-element array of int in a sequence.
Subtracting two pointers (provided they both point into the same array object, or one is pointing one past the last element of the array) yields the number of objects (array elements) between those two pointers.
The expression &a yields the address of a, and has the type int (*)[5] (pointer to 5-element array of int). The expression &a + 1 yields the address of the next 5-element array of int following a, and also has the type int (*)[5]. The expression *(&a + 1) dereferences the result of &a + 1, such that it yields the address of the first int following the last element of a, and has type int [5], which in this context "decays" to an expression of type int *.
Similarly, the expression a "decays" to a pointer to the first element of the array and has type int *.
A picture may help:
int [5] int (*)[5] int int *
+---+ +---+
| | <- &a | | <- a
| - | +---+
| | | | <- a + 1
| - | +---+
| | | |
| - | +---+
| | | |
| - | +---+
| | | |
+---+ +---+
| | <- &a + 1 | | <- *(&a + 1)
| - | +---+
| | | |
| - | +---+
| | | |
| - | +---+
| | | |
| - | +---+
| | | |
+---+ +---+
This is two views of the same storage - on the left, we're viewing it as a sequence of 5-element arrays of int, while on the right, we're viewing it as a sequence of int. I also show the various expressions and their types.
Be aware, the expression *(&a + 1) results in undefined behavior:
...
If the result points one past the last element of the array object, it
shall not be used as the operand of a unary * operator that is evaluated.
C 2011 Online Draft, 6.5.6/9
This line is of most importance:
size = *(&a + 1) - a;
As you can see, it first takes the address of a and adds one to it. Then, it dereferences that pointer and subtracts the original value of a from it.
Pointer arithmetic in C causes this to return the number of elements in the array, or 5. Adding one and &a is a pointer to the next array of 5 ints after a. After that, this code dereferences the resulting pointer and subtracts a (an array type that has decayed to a pointer) from that, giving the number of elements in the array.
Details on how pointer arithmetic works:
Say you have a pointer xyz that points to an int type and contains the value (int *)160. When you subtract any number from xyz, C specifies that the actual amount subtracted from xyz is that number times the size of the type that it points to. For example, if you subtracted 5 from xyz, the value of xyz resulting would be xyz - (sizeof(*xyz) * 5) if pointer arithmetic didn't apply.
As a is an array of 5 int types, the resulting value will be 5. However, this will not work with a pointer, only with an array. If you try this with a pointer, the result will always be 1.
Here's a little example that shows the addresses and how this is undefined. The the left-hand side shows the addresses:
a + 0 | [a[0]] | &a points to this
a + 1 | [a[1]]
a + 2 | [a[2]]
a + 3 | [a[3]]
a + 4 | [a[4]] | end of array
a + 5 | [a[5]] | &a+1 points to this; accessing past array when dereferenced
This means that the code is subtracting a from &a[5] (or a+5), giving 5.
Note that this is undefined behavior, and should not be used under any circumstances. Do not expect the behavior of this to be consistent across all platforms, and do not use it in production programs.
Hmm, I suspect this is something that would not have worked back in the early days of C. It is clever though.
Taking the steps one at a time:
&a gets a pointer to an object of type int[5]
+1 gets the next such object assuming there is an array of those
* effectively converts that address into type pointer to int
-a subtracts the two int pointers, returning the count of int instances between them.
I'm not sure it is completely legal (in this I mean language-lawyer legal - not will it work in practice), given some of the type operations going on. For example you are only "allowed" to subtract two pointers when they point to elements in the same array. *(&a+1) was synthesised by accessing another array, albeit a parent array, so is not actually a pointer into the same array as a.
Also, while you are allowed to synthesise a pointer past the last element of an array, and you can treat any object as an array of 1 element, the operation of dereferencing (*) is not "allowed" on this synthesised pointer, even though it has no behaviour in this case!
I suspect that in the early days of C (K&R syntax, anyone?), an array decayed into a pointer much more quickly, so the *(&a+1) might only return the address of the next pointer of type int**. The more rigorous definitions of modern C++ definitely allow the pointer to array type to exist and know the array size, and probably the C standards have followed suit. All C function code only takes pointers as arguments, so the technical visible difference is minimal. But I am only guessing here.
This sort of detailed legality question usually applies to a C interpreter, or a lint type tool, rather than the compiled code. An interpretter might implement a 2D array as an array of pointers to arrays, because there is one less runtime feature to implement, in which case dereferencing the +1 would be fatal, and even if it worked would give the wrong answer.
Another possible weakness may be that the C compiler might align the outer array. Imagine if this was an array of 5 chars (char arr[5]), when the program performs &a+1 it is invoking "array of array" behaviour. The compiler might decide that an array of array of 5 chars (char arr[][5]) is actually generated as an array of array of 8 chars (char arr[][8]), so that the outer array aligns nicely. The code we are discussing would now report the array size as 8, not 5. I'm not saying a particular compiler would definitely do this, but it might.
I have the following C program:
#include <stdio.h>
int main(){
int a[2][2] = {1, 2, 3, 4};
printf("a:%p, &a:%p, *a:%p \n", a, &a, *a);
printf("a[0]:%p, &a[0]:%p \n", a[0], &a[0]);
printf("&a[0][0]:%p \n", &a[0][0]);
return 0;
}
It gives the following output:
a:0028FEAC, &a:0028FEAC, *a:0028FEAC
a[0]:0028FEAC, &a[0]:0028FEAC
&a[0][0]:0028FEAC
I am not able to understand why are &a, a, *a - all identical. The same for a[0], &a[0] and &a[0][0].
EDIT:
Thanks to the answers, I've understood the reason why these values are coming out to be equal. This line from the book by Kernighan & Ritchie turned out to be the key to my question:
the name of an array is a synonym for the location of the initial element.
So, by this, we get
a = &a[0], and
a[0] = &a[0][0] (considering a as an array of arrays)
Intuitively, now the reason is clear behind the output. But, considering how pointers are implemented in C, I can't understand how a and &a are equal. I am assuming that there is a variable a in memory which points to the array(and the starting address of this array-memory-block would be the value of this variable a).
But, when we do &a, doesn't that mean taking the address of the memory location where the variable a was stored? Why are these values equal then?
They're not identical pointers. They're pointers of distinct types that all point to the same memory location. Same value (sort of), different types.
A 2-dimensional array in C is nothing more or less than an array of arrays.
The object a is of type int[2][2], or 2-element array of 2-element array of int.
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 expression a, unless it's the operand of unary & or sizeof, is of type int(*)[2], and is equivalent to &a[0] (or &(a[0]) 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 value (or equivalently an address), not a pointer object; there is no pointer object here unless you explicitly create one.
So looking at the several expressions you asked about:
&a is the address of the entire array object; it's a pointer expression of type int(*)[2][2].
a 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 int(*)[2].
*a dereferences the pointer expression a. Since a (after it decays) is a pointer to an array of 2 ints, *a is an array of 2 ints. 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 int*. *a is equivalent to &a[0][0].
&a[0] is the address of the first (0th) row of the array object. It's of type int(*)[2]. a[0] is an array object; it doesn't decay to a pointer because it's the direct operand of unary &.
&a[0][0] is the address of element 0 of row 0 of the array object. It's of type int*.
All of these pointer expressions refer to the same location in memory. That location is the beginning of the array object a; it's also the beginning of the array object a[0] and of the int object a[0][0].
The correct way to print a pointer value is to use the "%p" format and to convert the pointer value to void*:
printf("&a = %p\n", (void*)&a);
printf("a = %p\n", (void*)a);
printf("*a = %p\n", (void*)*a);
/* and so forth */
This conversion to void* 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 void* yields the same value.
(I've glossed over the inner workings of the [] indexing operator. The expression x[y] is by definition equivalent to *(x+y), where x is a pointer (possibly the result of the implicit conversion of an array) and y is an integer. Or vice versa, but that's ugly; arr[0] and 0[arr] 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 a[0][0] means, and this answer is probably already too long.)
For the sake of completeness the three contexts in which an expression of array type is not implicitly converted to a pointer to the array's first element are:
When it's the operand of unary &, so &arr yields the address of the entire array object;
When it's the operand of sizeof, so sizeof arr yields the size in bytes of the array object, not the size of a pointer; and
When it's a string literal in an initializer used to initialize an array (sub-)object, so char s[6] = "hello"; copies the array value into s rather than nonsensically initializing an array object with a pointer value. This last exception doesn't apply to the code you're asking about.
(The N1570 draft of the 2011 ISO C standard incorrectly states that _Alignof is a fourth exception; this is incorrect, since _Alignof can only be applied to a parenthesized type name, not to a expression. The error is corrected in the final C11 standard.)
Recommended reading: Section 6 of the comp.lang.c FAQ.
Because all expressions are pointing to the beginning of the array:
a = {{a00},{a01},{a10},{a11}}
a points to the array, just because it is an array, so a == &a[0]
and &a[0][0] is positioned at the first cell of the 2D array.
+------------------------------+
| a[0][0] <-- a[0] <-- a | // <--&a, a,*a, &a[0],&a[0][0]
|_a[0][1]_ |
| a[1][0] <-- a[1] |
| a[1][1] |
+------------------------------+
It is printing out the same values because they all are pointing to the same location.
Having said that,
&a[i][i] is of type int * which is a pointer to an integer.
a and &a[0] have the type int(*)[2] which indicates a pointer to an array of 2 ints.
&a has the type of int(*)[2][2] which indicates a pointer to a 2-D array or a pointer to an array of two elements in which each element is an array of 2-ints.
So, all of them are of different type and behave differently if you start doing pointer arithmetic on them.
(&a[0][1] + 1) points to the next integer element in the 2-D array i.e. to a[0][1]
&a[0] + 1 points to the next array of integers i.e. to a[1][0]
&a + 1 points to the next 2-D array which is non-existent in this case, but would be a[2][0] if present.
You know that a is the address of the first element of your array and according to the C standard, a[X] is equal to *(a + X).
So:
&a[0] == a because &a[0] is the same as &(*(a + 0)) = &(*a) = a.
&a[0][0] == a because &a[0][0] is the same as &(*(*(a + 0) + 0))) = &(*a) = a
A 2D array in C is treated as a 1D array whose elements are 1D arrays (the rows).
For example, a 4x3 array of T (where "T" is some data type) may
be declared by: T a[4][3], and described by the following
scheme:
+-----+-----+-----+
a == a[0] ---> | a00 | a01 | a02 |
+-----+-----+-----+
+-----+-----+-----+
a[1] ---> | a10 | a11 | a12 |
+-----+-----+-----+
+-----+-----+-----+
a[2] ---> | a20 | a21 | a22 |
+-----+-----+-----+
+-----+-----+-----+
a[3] ---> | a30 | a31 | a32 |
+-----+-----+-----+
Also the array elements are stored in memory row after row.
Prepending the T and appending the [3] to a we have an array of 3 elements of type T. But, the name a[4] is itself an array indicating that there are 4 elements each being an array of 3 elements. Hence we have an array of 4 arrays of 3 elements each.
Now it is clear that a points to the first element (a[0]) of a[4] . On the Other hand &a[0] will give the address of first element (a[0]) of a[4] and &a[0][0] will give the address of 0th row (a00 | a01 | a02) of array a[4][3]. &a will give the address of 2D array a[3][4]. *a decays to pointers to a[0][0].
Note that a is not a pointer to a[0][0]; instead it is a pointer to a[0].
Hence
G1: a and &a[0] are equivalent.
G2: *a, a[0]and &a[0][0] are equivalent.
G3: &a (gives the address of 2D array a[3][4]).
But group G1, G2 and G3 are not identical although they are giving the same result (and I explained above why it is giving same result).
This also means that in C arrays have no overhead. In some other languages the structure of arrays is
&a --> overhead
more overhead
&a[0] --> element 0
element 1
element 2
...
and &a != &a[0]
Intuitively, now the reason is clear behind the output. But, considering how pointers are implemented in C, I can't understand how a and &a are equal. I am assuming that there is a variable a in memory which points to the array(and the starting address of this array-memory-block would be the value of this variable a).
Well, no. There is no such thing as an address stored anywhere in memory. There is only memory allocated for the raw data, and that's it. What happens is, when you use a naked a, it immediately decays into a pointer to the first element, giving the impression that the 'value' of a were the address, but the only value of a is the raw array storage.
As a matter of fact, a and &a are different, but only in type, not in value. Let's make it a bit easier by using 1D arrays to clarify this point:
bool foo(int (*a)[2]) { //a function expecting a pointer to an array of two elements
return (*a)[0] == (*a)[1]; //a pointer to an array needs to be dereferenced to access its elements
}
bool bar(int (*a)[3]); //a function expecting a pointer to an array of three elements
bool baz(int *a) { //a function expecting a pointer to an integer, which is typically used to access arrays.
return a[0] == a[1]; //this uses pointer arithmetic to access the elements
}
int z[2];
assert((size_t)z == (size_t)&z); //the value of both is the address of the first element.
foo(&z); //This works, we pass a pointer to an array of two elements.
//bar(&z); //Error, bar expects a pointer to an array of three elements.
//baz(&z); //Error, baz expects a pointer to an int
//foo(z); //Error, foo expects a pointer to an array
//bar(z); //Error, bar expects a pointer to an array
baz(z); //Ok, the name of an array easily decays into a pointer to its first element.
As you see, a and &a behave very differently, even though they share the same value.
I can declare:
int (*ap)[N];
So ap is pointer to int array of size N. Why is this ever useful? If I pass it to function, what useful thing it can do with it that it could not do with just a normal pointer to the array's contents?
C FAQ say:
2.12: How do I declare a pointer to an array?
Usually, you don't want to.
A pointer to an array can be used to dynamically allocate a multi-dimensional array N, where N-1 dimensions are known. Below creates a Nx3 array.
int (*ap)[3];
ap = malloc(N * sizeof(*ap));
/* can now access ap[0][0] - ap[N-1][2] */
#Adam E/Cruachan, This is not the same thing as a pointer to a pointer. ap is a single pointer to a block of memory containing three consecutive integers. ap++ will advance the pointer address to the next block of three integers. for int **pp;, pp points to an integer pointer, each of which can point to an integer anywhere in memory.
+-----+ +------+ +-----+
ap ---> | int | vs. pp ---> | int* | -> | int |
| int | +------+ +-----+
| int | pp+1 -> | int* | -\
+-----+ +------+ \ +-----+
ap+1 -> | int | : : -> | int |
| int | +-----+
| int |
+-----+
: :
If you increment the pointer, it will then point to the start of the next group of N elements.
This is not a big deal and it's use is up to the developer.
Generally, the only time you'll see a pointer to an array (T (*a)[N]) is as a function parameter, where a is meant to be a 2d array:
void foo(int (*a)[N], size_t count)
{
size_t i;
for (i = 0; i < count; i++)
a[i][j] = ...;
...
}
void bar(void)
{
int arr[M][N];
foo(arr, M);
}
Note that for a function parameter declaration, int a[][N] is equivalent to int (*a)[N], but this is only true for function parameter declarations:
void foo (int a[][N], size_t count) {...}
Pointers to arrays are generally not as useful as pointers to the base type, since you need to know the array size to properly declare a pointer to it (a pointer to a 10-element array of int is a different type from a pointer to a 20-element array of int). Personally, I haven't found much use for them in 20-some-odd years of programming.
Remember that in most contexts, an array expression (such as arr above) will have its type implicitly converted from "N-element array of T" to "pointer to T" (except when the array expression is an operand of sizeof or &, or the array is a string literal being used as an initializer in a declaration). In this case, the type of arr in the call to foo is implicitly converted from "M-element array of N-element array of int" to "pointer to N-element array of int".
Given the declaration T a[M][N], all of the following expressions will evaluate to the same location (the address of the first element in the array), but the types will be different as shown below:
Expression Type Implicitly converted to
---------- ---- -----------------------
a T [M][N] T (*)[N]
a[0] T [N] T *
&a T (*)[M][N]
&a[0] T (*)[N]
&a[0][0] T *
It's not useful, really. But sometimes pointers to arrays are used e.g. in Microsoft Windows API - I've seen a lot of this stuff there.
There are situations where you want to pass the memory location across programs. e.g a windows API might expect you to pass a pointer to data structure or an array where as you are programming in some other language, say c#. Windows API does not care how the target language handles array's, for windows API it is just a stream of bytes in memory and it will fill it, send it back to you. to avoid cross language type missmatch in some cases we use pointer to array rather than implicit array name as pointer. More over it is not guaranteed that the implicit array name is a long pointer, some compilers might optimize it to be a relative value withing segment. a pointer to an array guarantees that it is of the order of machine register size and you can point to a location anywhere in the available RAM.
This will probably careen off into subjective/argumentative, but...
In my opinion, pointers to arrays are in the language because they fell into the language. There are pointers to every other declarable data type, so these are here too. I've never seen anyone get really useful work out of them. Hypothetically, they allow a prototype that demands an array and not a pointer to the element, but ...
It seems pretty useless to me to do a pointer to an array. In C, an array is already a pointer to a block of that data type.
int (*ap)[N];
int **ipp;
are both the same data type (a pointer to a pointer to an Integer). The only difference there is that there is space for N integers allotted for ap.
There's no need to pass an array by a pointer to a function, like, for the purpose of changing the contents of the array within that function because it's already a pointer. As a general rule, I'd say it's unnecessary and just creates an additional need to dereference the pointer to get at the data in the array. But, I'm sure there's a program or algorithm somewhere that could find a legitimate use for it.
Following code is a part of my article : Pointers and Arrays in C C++
You can check it out # http://pointersandarrays.blogspot.com/
Pointers and 2D Arrays
Following code snippet illustrates how to declare and access a 2D array. Underneath 2D Array lies a single dimensional array. You will get be sure of this after playing with the following piece of code.
Code Snippet #4
#include<iostream&rt;
using namespace std;
int main()
{
cout<< "Understanding Pointers and 2 D Arrays"<<endl;
cout<< "----------------------\n"<<endl;
//Declaration of a 2D Array.
int tab[3][5];
//Total space required : 3*5 * sizeof(int) = 15 * sizeof(int)
//Funda : Since the amount of required space is known by compiler, contiguous 15 memory cells are allocated here.
//Hence the case is similar to a 1 D Array of size 15. Lets try this out!
//Array initialization using array name
for(int i=0; i<3;i++)
for(int j=0; j<5;j++)
tab[i][j]=i+2*j;
//Print array using array name
cout << "\nPrint array using array name ..."<<endl;
for(int i=0; i<3;i++)
{
for(int j=0; j<5;j++)
printf("%2d ",tab[i][j] );
printf("\n");
}
//Print array using a pointer. Proof of 1 D array being allocated
cout << "\nPrint array using a pointer. Proof of 1 D array being allocated ..." << endl;
int *tptr;
tptr = &tab[0][0]; // pointer tptr points at first element of the array.
for(int i=0; i<15;i++)
printf("%d ",*(tptr+i) );
tptr = &tab[0][0];
cout << "\nNotice that array is printed row by row in a linear fashion."<<endl;
return 0;
}
Output #4:
Understanding Pointers and 2D Arrays
Print array using array name ...
0 2 4 6 8
1 3 5 7 9
2 4 6 8 10
Print array using a pointer. Proof of 1 D array being allocated ...
0 2 4 6 8 1 3 5 7 9 2 4 6 8 10
Notice that array is printed row by row in a linear fashion.
I think the conclusion from this whole discussion is never. Nobody here really demonstrated a use for this construct where something else wouldn't work in a more comprehensible way.