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.
Related
From what I remember arrays are always passed as pointers. For instance, the declaration:
void foo(int array[2][5]);
means for compiler exactly the same thing as:
void foo(int (*array)[5]);
You can say that these both forms are equivalent. Now, I wonder, why it is allowed then to declare it as:
void foo(int (*array)[]);
while not as:
void foo(int array[][]);
Take an example:
#include <stdio.h>
void foo(int (*p)[3]);
void bar(int (*p)[]);
int main(void)
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
foo(a);
bar(a);
return 0;
}
// The same as int p[][3] or int p[N][3] where N is a constant expression
void foo(int (*p)[3])
{
}
// Would it the same as int p[][] or int p[N][] (by analogy)?
void bar(int (*p)[])
{
}
It compiles fine and without warnings, but if I change bar's declaration to:
void bar(int p[][]);
then it's an error.
Why C allows such "obscure" way to pass an array?
Arrays are not pointers, if you declare an array of pointers with unspecified size it's ok because it will store the addresses stored in the poitners contigously and the size of each element is known, but p[][] would require the arrays to be contigous not their addresses and the size of the array is unknown so that's the problem.
To make it clear if you say int p[][] the you don't know how far is p[0] from p[1] whereas in int (*p)[] you know that the distance is the size of a pointer.
Arrays are converted to pointers but the are not pointers.
Arrays are usable as pointers, but they're more than pointers; they point to a number of things which have a size. That way, you can tell the compiler you're interested in the third or fifth element of your array, and it will calculate the location of that element by multiplying the size of one element by three or five to find an offset, and adding that offset to the address of the array.
C doesn't actually have multidimensional arrays. What it does have is arrays of arrays, which is pretty much the same thing. Say you have this:
int a[4][5];
In memory, this would look like this:
[0] |[1] |[2] |[3]
+-------------------|-------------------|-------------------|-------------------+
a | | | | | | | | | | | | | X | | | | | | | |
+-------------------|-------------------|-------------------|-------------------+
0 1 2 3 4 | 0 1 2 3 4 | 0 1 2 3 4 | 0 1 2 3 4 |
and you then try to access the element at index [2][2], then the system needs to perform the following calculation (conceptually):
Take the size of an int, and multiply that by five to get the size of the inner array
Take the size of that inner array, and multiply by two to get the offset of the second element in the outer array
Take the size of an int again, and multiply that by two to get the offset of the second element in the inner array
Add the two offsets; that's your memory address
In this case, the calculation is *(a + (2 * 5 * sizeof(int)) + (2 * sizeof(int))), giving *(a + 12*sizeof(int)), which is indeed the correct offset from the starting pointer.
All that means is that the size of the inner array needs to be defined in order for the compiler to be able to do that calculation. If you don't define the size of any dimension (but the leftmost one) of your multidimensional array, you don't have a defined size, and the compiler will balk.
You're tripping over the C language support for arrays of 'unspecified' size, which you can declare, but can't generally use directly unless you give it a more specific size somewhere.
In your example, if you actually try to do anything with the array in bar, you'll get an error:
void bar(int (*p)[])
{
printf("%d\n", p[1][1]);
}
% gcc -Wall t.c
t.c: In function ‘bar’:
t.c:23:5: error: invalid use of array with unspecified bounds
printf("%d\n", p[1][1]);
^
The only thing you can do with p in bar is cast it to some type with an explicit size, or pass it to some other function that takes a pointer to an array (of specified or unspecified size), and if you use the wrong explicit size to try access the array, you get undefined behavior with no warning.
Kinda of a noob so don't kill me here.
What's the difference between the following codes?
int *p; //As i understand, it creates a pointer to an variable of size int.
int *p[100]; //Don't really know what this is.
int (*p)[100]; // I have come to understand that this is a pointer to an array.
This is a pointer to an int:
int *p;
┌────┐
│int*│
└────┘
It should point at an int, something like this:
┌────┐
│int*│
└─┃──┘
▼
┌───┐
│int│
└───┘
This is an array of 100 pointers to int:
int *p[100];
That is, it gives you 100 pointers.
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└────┴────┴────┴────┴────┴────┴┄
Each pointer should point an int, perhaps like this:
┌────┬────┬────┬────┬────┬────┬┄
│int*│int*│int*│int*│int*│int*│
└─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴┄
▼ ▼ ▼ ▼ ▼ ▼
┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌┄
│int││int││int││int││int││int││
└───┘└───┘└───┘└───┘└───┘└───┘└┄
Of course, there's no reason they can't all point at the same int, or whatever.
You may want to use an array of pointers if you want many pointers that you can easily
iterate over. You may, for example, dynamically allocate objects and have each pointer point at a different object:
p[0] = new int(0);
p[1] = new int(0);
// ...
Perhaps dynamically allocating ints isn't the best example, but I think the point is clear.
This is a pointer to an array of 100 int:
int (*p)[100];
That is, it gives you just 1 pointer:
┌───────────┐
│int(*)[100]│
└───────────┘
It should point at an array that contains 100 ints:
┌───────────┐
│int(*)[100]│
└─┃─────────┘
▼
┌───┬───┬───┬───┬───┬───┬┄
│int│int│int│int│int│int│
└───┴───┴───┴───┴───┴───┴┄
You will get a pointer to an array when you use the address-of operator (&) on the name of an array. For example:
int arr[100] = { /* some initial values */ };
int (*p)[100] = &arr;
Here, I've taken the address of the arr array, which gives me a pointer to that array. If you then want to access an element of the array, you have to dereference the pointer first: (*p)[3] will access element 3.
Side note:
Always remember that arrays are not pointers. As we have just seen, we can take the address of an array to get a pointer to it, just like any other (non-temporary) object in C++. The only special connection between arrays and pointers is that the name of an array can be implicitly converted to a pointer to the array's first element. That means the following is valid:
int arr[100] = { /* some initial values */ };
int* p = arr;
The pointer p will point at the first element in arr. Note that p is not a pointer to the array, but a pointer to an element of the array.
(Also note that there is no such thing as an array type function argument. If you write something like int p[] as a function argument, it is transformed by the compiler to be a int*.)
Sounds like you could use an introduction to the Spiral Rule.
Start at the variable and "spiral" your way around right to left:
+-------+
| +--+ | // So we have:
| | | | p // p
int * p | | * p // p is a pointer
^ ^ | | int * p // p is a pointer to an int
| +----+ |
+----------+
Next one:
+--------+
| +--+ | p // p
| | V | p[100] // p is an array of 100
int * p[100] | * p[100] // p is an array of 100 pointers
^ ^ | | int * p[100] // p is an array of 100 pointers to ints
| +----+ |
+-----------+
Finally, a new part of the rule, do anything in parenthesis first:
+-----+
| +-+ |
| ^ | | ( p) // p
int (* p) [100]; (*p) // p is a pointer
^ ^ | | (*p)[100] // p is a pointer to an array of 100
| +---+ | int (*p)[100] // p is a pointer to an array of 100 ints
+---------+
If you're online/have access to a computer, it's always usefule to use the cdecl.org site, but it's important to be able to read code offline as well, and this rule will let you do just that.
Kinda of a noob so don't kill me here
Working out what a type means in C can be tricky even for experts. No worries.
What's the difference between the following codes?
The other answers are good and I have no intention of contradicting them. Rather, here's yet another way to think about it. We need to define three things:
A variable is a thing that supports three operations. The fetch operation takes a variable and produces its current value. The fetch operation has no notation; you simply use the variable. The store operation takes a variable and a value, and stores the value in the variable. The address operation takes a variable and produces a pointer.
A pointer is a thing that supports one operation. The dereference operation, written as prefix *pointer, takes a pointer and produces a variable. (Pointers support other operations such as arithmetic and indexing -- which is a form of arithmetic -- but let's not go there.)
An array is a thing that supports one operation. The index operation takes an array and an integer and produces a variable. It's syntax is postfix: array[index]
OK, so now we come to your question. What does the declaration
int p;
mean? That the expression p is a variable of type int. Note that this is a variable; you can store things to p. What does the declaration
int *p;
mean? That the expression *p is a variable of type int. Now that we know that we can deduce what p is. Since *p is a dereference and produces a variable, p must be a pointer to int. What does the declaration
int *p[100];
mean? It means that *the expression *p[i] is a variable of type int provided that i is an integer value from 0 to 99. We got a variable out, but we could have gotten there from either the pointer or the array, so we have to figure out which. We consult the operator precedence table and discover that the indexing operator binds "tighter" than the dereferencing operator. That is:
*p[i]
is the same thing as
*(p[i])
and remember, that thing is a variable of type int. The contents of the parens are dereferenced to produce a variable of type int so the contents of the parens must be a pointer to int. Therefore
p[i]
is a pointer to int. How is that possible? This must be a fetch of a variable of type pointer-to-int! So p[i] is a variable of type pointer to int. Since this is an index operation, p must be an array of pointers to int.
Now you do the next one.
int (*p)[100];
means what?
int *p; --> Declares a pointer to an integer type.
int *p[100]; -->Declares an array of 100 pointers to integer type.
int (*p)[100]; --> Declares a pointer to an array of 100 integers.
Use cdecl for translating such types.
Why can't my parameter be
void example(int Array[][]){ /*statements*/}
Why do I need to specify the column size of the array? Say for example, 3
void example(int Array[][3]){/*statements*/}
My professor said its mandatory, but I was coding before school started and I remembered that there was no syntactical or semantic error when I made this my parameter? Or did I miss something?
When it comes to describing parameters, arrays always decay into pointers to their first element.
When you pass an array declared as int Array[3] to the function void foo(int array[]), it decays into a pointer to the beginning of the array i.e. int *Array;. Btw, you can describe a parameter as int array[3] or int array[6] or even int *array - all these will be equivalent and you can pass any integer array without problems.
In case of arrays of arrays (2D arrays), it decays to a pointer to its first element as well, which happens to be a single dimensional array i.e. we get int (*Array)[3].
Specifying the size here is important. If it were not mandatory, there won't be any way for compiler to know how to deal with expression Array[2][1], for example.
To dereference that a compiler needs to compute the offset of the item we need in a contiguous block of memory (int Array[2][3] is a contiguous block of integers), which should be easy for pointers. If a is a pointer, then a[N] is expanded as start_address_in_a + N * size_of_item_being_pointed_by_a. In case of expression Array[2][1] inside a function (we want to access this element) the Array is a pointer to a single dimensional array and the same formula applies. The number of bytes in the last square bracket is required to find size_of_item_being_pointed_by_a. If we had just Array[][] it would be impossible to find it out and hence impossible to dereference an array element we need.
Without the size, pointers arithmetics wouldn't work for arrays of arrays. What address would Array + 2 produce: advance the address in Array 2 bytes ahead (wrong) or advance the pointer 3* sizeof(int) * 2 bytes ahead?
In C/C++, even 2-D arrays are stored sequentially, one row after another in memory. So, when you have (in a single function):
int a[5][3];
int *head;
head = &a[0][0];
a[2][1] = 2; // <--
The element you are actually accessing with a[2][1] is *(head + 2*3 + 1), cause sequentially, that element is after 3 elements of the 0 row, and 3 elements of the 1 row, and then one more index further.
If you declare a function like:
void some_function(int array[][]) {...}
syntactically, it should not be an error. But, when you try to access array[2][3] now, you can't tell which element is supposed to be accessed. On the other hand, when you have:
void some_function(int array[][5]) {...}
you know that with array[2][3], it can be determined that you are actually accessing element at the memory address *(&array[0][0] + 2*5 + 3) because the function knows the size of the second dimension.
There is one other option, as previously suggested, you can declare a function like:
void some_function(int *array, int cols) { ... }
because this way, you are calling the function with the same "information" as before -- the number of columns. You access the array elements a bit differently then: you have to write *(array + i*cols + j) where you would usually write array[i][j], cause array is now a pointer to integer (not to a pointer).
When you declare a function like this, you have to be careful to call it with the number of columns that are actually declared for the array, not only used. So, for example:
int main(){
int a[5][5];
int i, j;
for (i = 0; i < 3; ++i){
for (int j=0; j < 3; ++j){
scanf("%d", &a[i][j]);
}
}
some_function(&a[i][j], 5); // <- correct
some_function(&a[i][j], 3); // <- wrong
return 0;
}
C 2018 6.7.6.2 specifies the semantics of array declarators, and paragraph 1 gives constraints for them, including:
The element type shall not be an incomplete or function type.
In a function declaration such as void example(int Array[][]), Array[] is an array declarator. So it must satisfy the constraint that its element type must not be incomplete. Its element type in that declaration is int [], which is incomplete since the size is not specified.
There is no fundamental reason the C standard could not remove that constraint for parameters that are about to be adjusted to pointers. The resulting type int (*Array)[] is a legal declaration, is accepted by compilers, and can be used in the form (*Array)[j].
However, the declaration int Array[][] suggests that Array is at least associated with a two-dimensional array, and hence is to be used in the form Array[i][j]. Even if the declaration int Array[][] were accepted and were adjusted to int (*Array)[], using it as Array[i][j] would not be possible because the subscript operator requires that its pointer operand be a pointer to a complete type, and this requirement is not avoidable as it is needed to calculate the address of the element. Thus, keeping the constraint on the array declarator makes sense, as it is consistent with the intended expression that the argument will be a two-dimensional array, not just a pointer to one one-dimensional array.
Actually whether it is a 2d array or a 1d array, it is stored in the memory in a single line.So to say the compiler where should it break the row indicating the next numbers to be in the next rows we are supposed to provide the column size. And breaking the rows appropriately will give the size of the rows.
Let's see an example:
int a[][3]={ 1,2,3,4,5,6,7,8,9,0 };
This array a is stored in the memory as:
1 2 3 4 5 6 7 8 9 0
But since we have specified the column size as 3 the memory splits after every 3 numbers.
#include<stdio.h>
int main() {
int a[][3]={1,2,3,4,5,6},i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
OUTPUT:
1 2 3
4 5 6
In the other case,
int a[3][]={1,2,3,4,5,6,7,8,9,0};
The compiler only knows that there are 3 rows but it doesn't know the number of elements in each row so it cannot allocate memory and will show an error.
#include<stdio.h>
int main() {
int a[3][]={1,2,3,4,5,6},i,j;
for(i=0;i<3;i++)
{
for(j=0;j<2;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
OUTPUT:
c: In function 'main':
c:4:8: error: array type has incomplete element type 'int[]'
int a[3][]={1,2,3,4,5,6},i,j;
^
As we know, we can pass a variable as an argument(s) in a function. Similarly, we can pass two-dimensional arrays in C++.
C++ does not allow us to pass an entire array as an argument to a function. However, we can pass a pointer to an array by specifying the array's name without an index.
We can pass a 2D array to a function by specifying the size of the columns of a 2D array. One of the important things to remember here is that the size of rows is optional but the size of the column should not be left empty else the compiler will show an error. A 2D array is stored in the memory in a single line. So, to say the compiler where should it break the row indicating the following numbers to be in the next rows we are supposed to provide the column size. And breaking the rows appropriately will automatically give the size of the rows.
source: https://www.scaler.com/topics/two-dimensional-array-in-cpp/
There is a similar post regarding this. You can refer below link.
Creating Array in C and passing pointer to said array to function
Hope it helps.
On the other hand, compiler needs to the second dimension so that it can move "Array" from one pointer to next since the whole memory is arranged in a linear fashion
I thought this was a cool approach. If you take this as the formula to calculate the address of an element in the array:
a[i][j] = baseArrayAddress + (i + (colSize + elementSize)) + (j * (elementSize))
Then you can see that the only thing the compiler needs to know (which it can't otherwise infer) is the size of the column, thus you need to provide it as the programmer so the algorithm can run to calculate the offset.
The row number only acts as a multiplier and is provided by the programmer when trying to dereference an array location.
When you create a 2D array, anytype a[3][4], in memory what you actually create is 3 contiguous blocks of 4 anytype objects.
a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]
Now the next question is, why is that so? Because, keeping with the spec and structure of the language, anytype a[3][4] actually expands out into anytype (*a)[4], because arrays decay into pointers. And in fact that also expands out into anytype (*(*a)), however, you've now completely lost the size of the 2D array. So, you must help the compiler out a bit.
If you ask the program for a[2], the program can follow the exact same steps that it does for 1D arrays. It simply can return the 3rd element of sizeof(object pointed to), the object pointed to here is of size 4 anytype objects.
Im quite confused that what is difference between these two initializations:
int (*p)[10];
and
int *p[10]
I know they both can point to 2D array whose element count in row is 10....
The first is a pointer to array, the second is an array of pointers.
To elaborate a bit on the correct answers here already:
The first line:
int (*p)[10];
declares that "p" is a pointer to the memory address of an array with the capacity of 10 ints. It can be read in English as: "integer-pointer 'p' points to 10 sequential ints in memory".
The second line:
int *p[10]
Declares that "p[]" is an array of 10 pointers to integers. This is an array of memory addresses that point to integers. In this case, "p" is a sequence of 10 pointers in memory (which happen to be the memory addresses of other ints).
int (*p)[10];
+------+ +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
| p | =========================>|(*p)[0]|(*p)[1]|(*p)[2]|(*p)[3]|(*p)[4]|(*p)[5]|(*p)[6]|(*p)[7]|(*p)[8]|(*p)[9]|
+------+ +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
sizeof p will return sizeof (void *) (4 on 32 bit systems, 8 on 64 bit systems)
sizeof *p will return 10*sizeof (int) (40 on most systems)
int *p[10]; is the same as int* (p[10]);
p
+------+------+------+------+------+------+------+------+------+------+
| p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7] | p[8] | p[9] |
+------+------+------+------+------+------+------+------+------+------+
sizeof p will return 10*sizeof (void *) (40 on 32 bit systems, 80 on 64 bit systems)
sizeof *p will return sizeof (int *) (4 on 32 bit systems, 8 on 64 bit systems)
In your first example, p is pointer to array of 10 integers. In the second example, p is an array of 10 pointers.
You can dynamically allocate an object of type "pointer to array of ten int" as follows.
int (**ptr)[10] = new (int (*)[10]);
Note, no space for any ints is allocated; only the pointer itself.
You can allocate an array of 10 ints as follows:
int *ptr = new int[10];
What you can't do (without explicit casting) is assign a pointer to a dynamically allocated array of 10 int to a pointer of type int (*)[10]. Whenever you allocate an array via new, even if you use a typedef, the type of the new expression is a pointer to the first element of the array; the size of the array is not retained in the type of the new expression.
This is because new[] expressions can allocate arrays where the size of the array is chosen at runtime so would not always be possible (or even desirable) to encode the array size into the type of the new expression.
As has been suggested, you can dynamically allocate an array of one array of 10 int. The size of the first array is lost from the type information and what you get is a pointer to the first element of the array (of size 1) of the arrays of four int.
int (*p)[10] = new int[1][10];
Even though it is an array of just 1 (arrays of 10 int), you still need to use delete[] to deallocate p.
delete[] p;
Of course one should never actually be a position to need to call delete manually.
In the first definition (not initialization), p is a pointer; in the second, p is an array of 10 pointers.
As others have pointed out, int (*p)[10] declares p as a pointer to a 10-element array of int, whereas int *p[10] declares p as a 10-element array of pointer to int.
In C, declarations are built around the types of expressions, not objects. The idea is that the form of the declaration should match the form of the expression as it's used in the code.
Suppose that p is an array of pointers to int (the second case). To access a particular integer value, you'd subscript into the array and dereference the result, as in
x = *p[i];
Postfix operators like [] and () have higher precedence than unary operators like *, so the above statement is parsed as *(p[i]) (IOW, the * is applied to the expression p[i]).
The type of the expression *p[i] is int, so the corresponding declaration of p is int *p[10];.
Now let's suppose that p is a pointer to an array of int (the first case). To access a particular integer value, you'd dereference the pointer and then subscript the result, as in
x = (*p)[i];
Again, because [] has higher precedence than *, we need to use parentheses to explicitly associate the * with just p, not p[i]. The type of the expression (*p)[i] is int, so the declaration of p is int (*p)[10];.
In C, I know I can dynamically allocate a two-dimensional array on the heap using the following code:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Clearly, this actually creates a one-dimensional array of pointers to a bunch of separate one-dimensional arrays of integers, and "The System" can figure out what I mean when I ask for:
someNumbers[4][2];
But when I statically declare a 2D array, as in the following line...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
...does a similar structure get created on the stack, or is it of another form completely? (i.e. is it a 1D array of pointers? If not, what is it, and how do references to it get figured out?)
Also, when I said, "The System," what is actually responsible for figuring that out? The kernel? Or does the C compiler sort it out while compiling?
A static two-dimensional array looks like an array of arrays - it's just laid out contiguously in memory. Arrays are not the same thing as pointers, but because you can often use them pretty much interchangeably it can get confusing sometimes. The compiler keeps track properly, though, which makes everything line up nicely. You do have to be careful with static 2D arrays like you mention, since if you try to pass one to a function taking an int ** parameter, bad things are going to happen. Here's a quick example:
int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};
In memory looks like this:
0 1 2 3 4 5
exactly the same as:
int array2[6] = { 0, 1, 2, 3, 4, 5 };
But if you try to pass array1 to this function:
void function1(int **a);
you'll get a warning (and the app will fail to access the array correctly):
warning: passing argument 1 of ‘function1’ from incompatible pointer type
Because a 2D array is not the same as int **. The automatic decaying of an array into a pointer only goes "one level deep" so to speak. You need to declare the function as:
void function2(int a[][2]);
or
void function2(int a[3][2]);
To make everything happy.
This same concept extends to n-dimensional arrays. Taking advantage of this kind of funny business in your application generally only makes it harder to understand, though. So be careful out there.
The answer is based on the idea that C doesn't really have 2D arrays - it has arrays-of-arrays. When you declare this:
int someNumbers[4][2];
You are asking for someNumbers to be an array of 4 elements, where each element of that array is of type int [2] (which is itself an array of 2 ints).
The other part of the puzzle is that arrays are always laid out contiguously in memory. If you ask for:
sometype_t array[4];
then that will always look like this:
| sometype_t | sometype_t | sometype_t | sometype_t |
(4 sometype_t objects laid out next to each other, with no spaces in between). So in your someNumbers array-of-arrays, it'll look like this:
| int [2] | int [2] | int [2] | int [2] |
And each int [2] element is itself an array, that looks like this:
| int | int |
So overall, you get this:
| int | int | int | int | int | int | int | int |
unsigned char MultiArray[5][2]={{0,1},{2,3},{4,5},{6,7},{8,9}};
in memory is equal to:
unsigned char SingleArray[10]={0,1,2,3,4,5,6,7,8,9};
In answer to your also: Both, though the compiler is doing most of the heavy lifting.
In the case of statically allocated arrays, "The System" will be the compiler. It will reserve the memory like it would for any stack variable.
In the case of the malloc'd array, "The System" will be the implementer of malloc (the kernel usually). All the compiler will allocate is the base pointer.
The compiler is always going to handle the type as what they are declared to be except in the example Carl gave where it can figure out interchangeable usage. This is why if you pass in a [][] to a function it must assume that it is a statically allocated flat, where ** is assumed to be pointer to pointer.
Suppose, we have a1 and a2 defined and initialized like below (c99):
int a1[2][2] = {{142,143}, {144,145}};
int **a2 = (int* []){ (int []){242,243}, (int []){244,245} };
a1 is a homogeneous 2D array with plain continuous layout in memory and expression (int*)a1 is evaluated to a pointer to its first element:
a1 --> 142 143 144 145
a2 is initialized from a heterogeneous 2D array and is a pointer to a value of type int*, i.e. dereference expression *a2 evaluates into a value of type int*, memory layout does not have to be continuous:
a2 --> p1 p2
...
p1 --> 242 243
...
p2 --> 244 245
Despite totally different memory layout and access semantics, C-language grammar for array-access expressions looks exactly the same for both homogeneous and heterogeneous 2D array:
expression a1[1][0] will fetch value 144 out of a1 array
expression a2[1][0] will fetch value 244 out of a2 array
Compiler knows that the access-expression for a1 operates on type int[2][2], when the access-expression for a2 operates on type int**. The generated assembly code will follow the homogeneous or heterogeneous access semantics.
The code usually crashes at run-time when array of type int[N][M] is type-casted and then accessed as type int**, for example:
((int**)a1)[1][0] //crash on dereference of a value of type 'int'
To access a particular 2D array consider the memory map for an array declaration as shown in code below:
0 1
a[0]0 1
a[1]2 3
To access each element, its sufficient to just pass which array you are interested in as parameters to the function. Then use offset for column to access each element individually.
int a[2][2] ={{0,1},{2,3}};
void f1(int *ptr);
void f1(int *ptr)
{
int a=0;
int b=0;
a=ptr[0];
b=ptr[1];
printf("%d\n",a);
printf("%d\n",b);
}
int main()
{
f1(a[0]);
f1(a[1]);
return 0;
}