2D Array and pointer to a pointer - c

Question from a past exam paper:
"Which of the following:
int a[4][4], (*b)[4], *c[4], **d;
Could you pass into a function expecting a pointer to a pointer to an int
ie
int funct(int **);
Explain your answer."
The answer is c and d i believe?
I am just struggling to understand why the rest arn't allowed?
Any help would be appreciated.

funct expects an int ** - that is, a pointer-to-a-pointer-to-an-int. d is literally that, so no problem. c works too, since it's an array of pointers-to-int, which will therefore decay into a pointer-to-a-pointer-to-an-int when used in a function call context.
a and b won't work, since they're not compatible types. a is an array-of-arrays-of-int, and b is a a pointer-to-array-of-int. a will decay into a pointer-to-array-of-int when passed as a parameter.

in general if you pass an array to a function it is passed as pointer to first element of the array...
int a[4][4] to a function i.e. fun(a); it is passed as int (*p)[4] so fun parameter must be fun(int (*p)[])
here first element itself is an array of 4 integers
fun(a) ---> fun(int (*p)[])
int (*b)[4] is a pointer to array of 4 integers so calling fun(b) requires parameter must be fun(int (*pt)[])
fun(b) ---> fun(int (*pt)[])
int *c[4] is an array of 4 integer pointers ..so calling fun(c) requires parameter must
be pointer to first element of array. here first element is itself an int pointer..so fun(int **p)
fun(c) ---> fun(int **p)
int **d is double pointer to an int..so calling fun(d) requires parameter must be
fun(int **p)
fun(d) ---> fun(int **p)

If I can add some information on the difference between the above answers.
This - [] has higher precedence than this * when declaring an array. That combined with the assumption that arrays and pointers are always interchangeable (they are not) catches a lot of people out.
Naively one would assume that int *arr[] would be a pointer to an array because read from left to right this is a natural assumption.
However it is actually an array of integer pointers. You want a pointer to an array? Tell C so:
int (*arr)[array_size];
by setting your own precedence.
As Carl has explained only answers c and d are applicable because in the d case you already have a pointer to a pointer and in the c case the array of pointers will decay to a pointer to a pointer when passed as an argument to a function.
If you want a function that will read a and b, the signature needs to change to the following:
int funct(int (*array_name)[array_size]);
Note that in the above here you will need to specify the size of the array that the pointer will point to.
Some good answers on two dimensional arrays and pointers to pointers here and here.

Related

Ways to represent function with multi-dimensional array parameters

I'm currently learning function that work with multi-dimensional array in C.
Let's say I have
short myArray[10][30].
I have declared following function prototype to work with myArray.
void first(int n, short ar[][30]);
void second(int n, short ar[30]);
void third(int n, short (*ar)[30]);
My understanding is that the ar parameter in both first and third function are equivalent. short ar[][30] in first function is equivalent to the short (*ar)[30] in third function because they are both pointer to array of 30 short.
The ar in second function is different because in short ar[30], ar is a pointer to short, not a pointer to array of 30 short.
Is my understanding correct?
Yes your understanding is correct. 1 and 3 are equivalent. And 2 is also right (But not for passing 2d array - it is correct for passing 1D array). But will clarify a bit the second case.
And the second one that 30 inside of third brackets are not considered by the compiler. You can omit it still the compiler won't complain. Actually here you have passed an 1D array of short that decayed into pointer to the first element (First element being short it is short*). So the second one you can also write as short *ar.
void second(int n, short ar[]);
void second(int n, short* ar );
These two works and they are equivalent in this context. The second one is for passing 1D array something like
second(n, myArray[5]);
The thing is, most of the time array decays into pointer (exception is sizeof operator or Alignof etc). Passing an array to a function is a case where the array decays.
Also you are passing int arrays so it is wrong to write short.(int and short may have same size but it is guaranteed that size of int would be larger than or equal to the size of short). If you used short and then wrote int in the declaration that would have worked.
Edit: The second one is not for passing 2d array. Let's be clear on that. You can't pass 2d array to a function with the prototype declared as the second one. For pointers there are 2 things to consider - it's type and it's value. If you tried to pass a 2d array to the same function that would be illegal. 2d array decays into int (*)[30] which is not in anyway same as int * or int[].
1 and 3 are indeed the same, as would be
void fourth(int n, short ar[10][30]);
because when you pass an array as function parameter, it decays to a pointer to its first parameter, so the compiler sees 1 and 4 as 3.
That explains why this would also be correct:
void fifth(int n, short arr[15][30]);
As it decays to a pointer, the declared size of the first dimension is not used. You are supposed to give the actual size in another way.
But this one is different:
void second(int n, short ar[30]);
and your compiler should raise a warning there because the expected paramater is a pointer to short, when you pass a pointer to an array of 30 short. Of course the pointers will have same value (same address), and common compilers will give expected results, but aliasing a pointer to array and a pointer to element is not allowed by the standard. So please avoid it.
With such a declaration, second should be called as
cr = second(n, arr[0]);
because arr[0] is a short array and will correctly decay to a short *.

Differences when using ** in C

I started learning C recently, and I'm having a problem understanding pointer syntax, for example when I write the following line:
int ** arr = NULL;
How can I know if:
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
Isn't it all the same with int ** ?
Another question for the same problem:
If I have a function that receives char ** s as a parameter, I want to refer to it as a pointer to an array of strings, meaning a pointer to an array of pointers to an array of chars, but is it also a pointer to a pointer to a char?
Isn't it all the same with int **?
You've just discovered what may be considered a flaw in the type system. Every option you specified can be true. It's essentially derived from a flat view of a programs memory, where a single address can be used to reference various logical memory layouts.
The way C programmers have been dealing with this since C's inception, is by putting a convention in place. Such as demanding size parameter(s) for functions that accept such pointers, and documenting their assumptions about the memory layout. Or demanding that arrays be terminated with a special value, thus allowing "jagged" buffers of pointers to buffers.
I feel a certain amount of clarification is in order. As you'd see when consulting the other very good answers here, arrays are most definitely not pointers. They do however decay into ones in enough contexts to warrant a decades long error in teaching about them (but I digress).
What I originally wrote refers to code as follows:
void func(int **p_buff)
{
}
//...
int a = 0, *pa = &a;
func(&pa);
//...
int a[3][10];
int *a_pts[3] = { a[0], a[1], a[2] };
func(a_pts);
//...
int **a = malloc(10 * sizeof *a);
for(int i = 0; i < 10; ++i)
a[i] = malloc(i * sizeof *a[i]);
func(a);
Assume func and each code snippet is compiled in a separate translation unit. Each example (barring any typos by me) is valid C. The arrays will decay into a "pointer-to-a-pointer" when passed as arguments. How is the definition of func to know what exactly it was passed from the type of its parameter alone!? The answer is that it cannot. The static type of p_buff is int**, but it still allows func to indirectly access (parts of) objects with vastly different effective types.
The declaration int **arr says: "declare arr as a pointer to a pointer to an integer". It (if valid) points to a single pointer that points (if valid) to a single integer object. As it is possible to use pointer arithmetic with either level of indirection (i.e. *arr is the same as arr[0] and **arr is the same as arr[0][0]) , the object can be used for accessing any of the 3 from your question (that is, for second, access an array of pointers to integers, and for third, access an array of pointers to first elements of integer arrays), provided that the pointers point to the first elements of the arrays...
Yet, arr is still declared as a pointer to a single pointer to a single integer object. It is also possible to declare a pointer to an array of defined dimensions. Here a is declared as a pointer to 10-element array of pointers to arrays of 10 integers:
cdecl> declare a as pointer to array 10 of pointer to array 10 of int;
int (*(*a)[10])[10]
In practice array pointers are most used for passing in multidimensional arrays of constant dimensions into functions, and for passing in variable-length arrays. The syntax to declare a variable as a pointer to an array is seldom seen, as whenever they're passed into a function, it is somewhat easier to use parameters of type "array of undefined size" instead, so instead of declaring
void func(int (*a)[10]);
one could use
void func(int a[][10])
to pass in a a multidimensional array of arrays of 10 integers. Alternatively, a typedef can be used to lessen the headache.
How can I know if :
arr is a pointer to a pointer of an integer
It is always a pointer to pointer to integer.
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
It can never be that. A pointer to an array of pointers to integers would be declared like this:
int* (*arr)[n]
It sounds as if you have been tricked to use int** by poor teachers/books/tutorials. It is almost always incorrect practice, as explained here and here and (
with detailed explanation about array pointers) here.
EDIT
Finally got around to writing a detailed post explaining what arrays are, what look-up tables are, why the latter are bad and what you should use instead: Correctly allocating multi-dimensional arrays.
Having solely the declaration of the variable, you cannot distinguish the three cases. One can still discuss if one should not use something like int *x[10] to express an array of 10 pointers to ints or something else; but int **x can - due to pointer arithmetics, be used in the three different ways, each way assuming a different memory layout with the (good) chance to make the wrong assumption.
Consider the following example, where an int ** is used in three different ways, i.e. p2p2i_v1 as a pointer to a pointer to a (single) int, p2p2i_v2 as a pointer to an array of pointers to int, and p2p2i_v3 as a pointer to a pointer to an array of ints. Note that you cannot distinguish these three meanings solely by the type, which is int** for all three. But with different initialisations, accessing each of them in the wrong way yields something unpredictable, except accessing the very first elements:
int i1=1,i2=2,i3=3,i4=4;
int *p2i = &i1;
int **p2p2i_v1 = &p2i; // pointer to a pointer to a single int
int *arrayOfp2i[4] = { &i1, &i2, &i3, &i4 };
int **p2p2i_v2 = arrayOfp2i; // pointer to an array of pointers to int
int arrayOfI[4] = { 5,6,7,8 };
int *p2arrayOfi = arrayOfI;
int **p2p2i_v3 = &p2arrayOfi; // pointer to a pointer to an array of ints
// assuming a pointer to a pointer to a single int:
int derefi1_v1 = *p2p2i_v1[0]; // correct; yields 1
int derefi1_v2 = *p2p2i_v2[0]; // correct; yields 1
int derefi1_v3 = *p2p2i_v3[0]; // correct; yields 5
// assuming a pointer to an array of pointers to int's
int derefi1_v1_at1 = *p2p2i_v1[1]; // incorrect, yields ? or seg fault
int derefi1_v2_at1 = *p2p2i_v2[1]; // correct; yields 2
int derefi1_v3_at1 = *p2p2i_v3[1]; // incorrect, yields ? or seg fault
// assuming a pointer to an array of pointers to an array of int's
int derefarray_at1_v1 = (*p2p2i_v1)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v2 = (*p2p2i_v2)[1]; // incorrect; yields ? or seg fault;
int derefarray_at1_v3 = (*p2p2i_v3)[1]; // correct; yields 6;
How can I know if :
arr is a pointer to a pointer of an integer
arr is a pointer to an array of pointers to integers
arr is a pointer to an array of pointers to arrays of integers
You cannot. It can be any of those. What it ends up being depends on how you allocate / use it.
So if you write code using these, document what you're doing with them, pass size parameters to the functions using them, and generally be sure about what you allocated before using it.
Pointers do not keep the information whether they point to a single object or an object that is an element of an array. Moreover for the pointer arithmetic single objects are considered like arrays consisting from one element.
Consider these declarations
int a;
int a1[1];
int a2[10];
int *p;
p = &a;
//...
p = a1;
//...
p = a2;
In this example the pointer p deals with addresses. It does not know whether the address it stores points to a single object like a or to the first element of the array a1 that has only one element or to the first element of the array a2 that has ten elements.
The type of
int ** arr;
only have one valid interpretation. It is:
arr is a pointer to a pointer to an integer
If you have no more information than the declaration above, that is all you can know about it, i.e. if arr is probably initialized, it points to another pointer, which - if probably initialized - points to an integer.
Assuming proper initialization, the only guaranteed valid way to use it is:
**arr = 42;
int a = **arr;
However, C allows you to use it in multiple ways.
• arr can be used as a pointer to a pointer to an integer (i.e. the basic case)
int a = **arr;
• arr can be used as a pointer to a pointer to an an array of integer
int a = (*arr)[4];
• arr can be used as a pointer to an array of pointers to integers
int a = *(arr[4]);
• arr can be used as a pointer to an array of pointers to arrays of integers
int a = arr[4][4];
In the last three cases it may look as if you have an array. However, the type is not an array. The type is always just a pointer to a pointer to an integer - the dereferencing is pointer arithmetic. It is nothing like a 2D array.
To know which is valid for the program at hand, you need to look at the code initializing arr.
Update
For the updated part of the question:
If you have:
void foo(char** x) { .... };
the only thing that you know for sure is that **x will give a char and *x will give you a char pointer (in both cases proper initialization of x is assumed).
If you want to use x in another way, e.g. x[2] to get the third char pointer, it requires that the caller has initialized x so that it points to a memory area that has at least 3 consecutive char pointers. This can be described as a contract for calling foo.
C syntax is logical. As an asterisk before the identifier in the declaration means pointer to the type of the variable, two asterisks mean pointer to a pointer to the type of the variable.
In this case arr is a pointer to a pointer to integer.
There are several usages of double pointers. For instance you could represent a matrix with a pointer to a vector of pointers. Each pointer in this vector points to the row of the matrix itself.
One can also create a two dimensional array using it,like this
int **arr=(int**)malloc(row*(sizeof(int*)));
for(i=0;i<row;i++) {
*(arr+i)=(int*)malloc(sizeof(int)*col); //You can use this also. Meaning of both is same. //
arr[i]=(int*)malloc(sizeof(int)*col); }
There is one trick when using pointers, read it from right hand side to the left hand side:
int** arr = NULL;
What do you get: arr, *, *, int, so array is a pointer to a pointer to an integer.
And int **arr; is the same as int** arr;.
int ** arr = NULL;
It's tell the compiler, arr is a double pointer of an integer and assigned NULL value.
There are already good answers here, but I want to mention my "goto" site for complicated declarations: http://cdecl.org/
Visit the site, paste your declaration and it will translate it to English.
For int ** arr;, it says declare arr as pointer to pointer to int.
The site also shows examples. Test yourself on them, then hover your cursor to see the answer.
(double (^)(int , long long ))foo
cast foo into block(int, long long) returning double
int (*(*foo)(void ))[3]
declare foo as pointer to function (void) returning pointer to array 3 of int
It will also translate English into C declarations, which is prety neat - if you get the description correct.

How does passing an array to another C function work?

This is causing me a great deal of confusion.
If I have the following array:
int arr[6];
// I then fill indices 0-5 with ints
And I want to pass that to a function that uses the array as a parameter, what does the function header look like?
Would it be void saveArray(int *arr) or void saveArray (int arr)? And then how would I call the function? saveArray(arr) or saveArray(&arr)?
As I understand it, while that initial array is not a pointer, it effectively acts as one as it decays into a pointer to the first element. So my intuition it that I should pass it like saveArray(arr) and the header should be void saveArray(int *arr). Would that be right?
Why do I want a pointer to the initial array and not just the array itself? What does &arr even represent?
In C, parameters passed in functions can only be passed by value.
In addition to that, in C you can't pass an array as a parameter to a function. However, you can pass by value a pointer to the first cell of the array.
Thus, your function's prototype would be:
void saveArray(int *arr)
which you'd call by
saveArray(arr);
Why do I want a pointer to the initial array and not just the array
itself?
That's because you cannot pass an array to a function. An array is not a first-class object in C unlike int, float, struct etc. This means an array is not copied to the function parameter. What actually gets passed is a pointer to the first element of the array. Therefore, the function parameter should be a pointer to the array element type. Also, you have to pass the length of the array to function as well since that information cannot be had in the function from the pointer that is passed to it.
An array is a different type than a pointer. There are some cases when it decays or is implicitly converted to a pointer to its first element. Therefore, your function should have the prototype
void saveArray(int *arr, int len);
// or
void saveArray(int arr[], int len);
// in main, for example
int arr[6];
saveArray(arr, sizeof arr);
// equivalent to
saveArray(&arr[0], sizeof arr);
What does &arr even represent?
The address of operator & evaluates the address of its operand which must be an lvalue. Here arr is of type int[6], i.e., an array of 6 integers. Therefore &arr is of type int (*)[6], i.e., a pointer to an array of 6 integers. Please note that the value &arr is equal to the base address of the array but its type is not int *. It is a different type and has different pointer arithmetic. This is, in fact, one of the cases where an array does not decay into a pointer to its first element.
Yes
void saveArray(int *arr)
But for it to be useful, pass the array length too.
void saveArray(int *arr, int len)
Otherwise how will you know how long it is?
Call then like so:
saveArray(arr, 6);
The question "Would it be void saveArray(int *arr) or void saveArray (int arr)?" has already been answered. I am going to answer the question "What does &arr even represent?"
In your case, &arr has the same numerical value as &arr[0]. However, if you did something a bit different,
int* arr = malloc(sizeof(int)*6);
Then the numerical value of &arr will be different than that of &arr[0] even though you will be able to call saveArray(arr) without any difference in meaning for both cases.
In the first case, both &arr and &arr[0] are addresses on the stack.
In the second case, &arr is an address on the stack while &arr[0] is an address in the heap.
Hope that helps.
If you use this prototype:
void saveArray(int *arr)
you loose information about the array length (e.g. number of elements).
Unless your function is supposed to operate on arrays with fixed length (e.g. some functions doing 3D math calculations may just consider 3D vectors, with fixed size of 3 double elements), you should specify the array length (e.g. element count) as an additional parameter:
void saveArray(int * arr, int count);
If your function just observes the content of the input array and does not modify it, you can use const to make your code const-correct and more precise:
void saveArray(const int * arr, int count);
Sometimes size_t is used as a type to specify length/count parameters:
void saveArray(const int * arr, size_t count);
About the other option you listed in your question:
void saveArray(int arr)
That is wrong, since in this case arr is just a single integer (not an array).
Instead, in the first (correct) case of passing [const] int*, you passed the address of the first item in the array, and since the array elements are stored in contiguous memory locations, just the address of the first item and the item count define the whole array.
At the call site, you can call your function like this:
int arr[<<some size here>>];
...
saveArray(arr, <<same size as above>>);
Or if you already have a pointer (e.g. since you allocated the array using malloc()), you can just specify the pointer itself:
int* arr;
arr = malloc( numberOfElements * sizeof(int) );
...
saveArray(arr, numberOfElements);

Setup pointer to 2D array, then passing that pointer into a function

G'day all,
I know this has been discussed a lot, but I still cant find what I need. I am pretty new to C and still am getting my head around pointers, namely, pointers to multi-dimensional arrays.
I have looked at examples such as int a[2][3]; int (*p) = a when a is a 2D array, but what does the brackets do?
I am creating a program which has a 2D array as a variable and it needs to pass that array onto an external function to modify it.
My array is initilised like this:
unsigned int node[3][2]={ {PINB,PINC}, {0,0}, {0,0} };
I believe the best way to do this is through pointers but I don't know how to setup the prototype for my function that takes in the 2D array.
This is the function im passing it to and how I call it:
NodeToMIDI(node, i, pMIDIdata);
And this is its prototype: //where "node_pointer" is the 2D array arg.
void NodeToMIDI(unsigned int node_pointer, unsigned int node_select, unsigned int * MidiPacket);
Can someone please explain the syntax and logic behind how to do this. Some of the other threads I have looked at have syntax that is unknown to me. Such as int ** a for example.
Thank-you for any help!
Andrew.
You can pass the array to function naturally only if you know (at compilation-time) the size of the inner array.
The examples you saw, are probably int a[2][3]; int (*p)[3] = a. The brackets means that p is pointer to array of 3 ints, not array of 3 pointers to int. Since you can dereference pointers like arrays, you can use p as if it was an array of arrays of 3 ints (which a is).
In the same way, you can write a prototype like void myfunc(int (*arr)[3]); - If you pass a to this function, it's exactly the same thing like pass array to function that gets pointer.
There is another way to write this prototype: void myfunc(int arr[][3]); - The compiler will understand it in the same way, and some people find this writing more understandable.
The signature you are looking for is:
void NodeToMIDI(unsigned node_pointer[][2], unsigned node_select, unsigned * MidiPacket);
which you would call
NodeToMIDI(node, /*something*/, /*something else*/);
Some background information:
An array behaves a bit like a pointer. if you have char* name = {"John"}; you can access the characters with name[2] = h for example.
Also name[0] (the first element) is the same like you use the pointer name directly. The pointer name refers to the adress of the first element in the array.
So an array of on array is... a pointer to a pointer. This looks like that what you described.
int ** a;
So this is an int pointer which referes to another int pointer which refers to a specific adress.
So you can take unsigned int** arrayOfArray as a function parameter.
Then you can access the element like you know it from arrays.
arrayOfArray[0][2] = 42;

Passing in array to a function

int main(){
int right[2][3] = {
{1,4,6}, {2,7,5}
}
....
calc(right);
}
int calc(int ** right){
printf("%i", right[0][0]);
}
I calc function that calculate some numbers based on a matrix, but I dont' know why i get seg fault when I access the variable right within the calc function. does any body know the solution?
edit:
right now that is all it's doing at calc function. I have some calc stuff but it's all commented out trying to figure out how to access this variable.
Two-dimensional arrays in C don't work the way you think they do. (Don't worry, you're not alone -- this is a common misconception.)
The assumption implicit in the code is that right is an array of int * pointers, each of which points to an array of int. It could be done this way -- and, confusingly, the syntax for accessing such an array would be the same, which is probably what causes this misconception.
What C actually does is to make right an array of 12 ints, layed out contiguously in memory. An array access like this
a=right[i][j];
is effectively equivalent to this:
int *right_one_dimensional=(int *)right;
a=right[i*3 + j];
To pass your array to the calc function, you need to do this:
int calc(int *right, size_t d){
// For example
a=right[i*d + j];
}
and then call it like this:
int right[2][3] = {
{1,4,6}, {2,7,5}
};
calc(&right[0][0], 3);
Edit: For more background on this, the question linked to in Binary Worrier's comment is definitely worth looking at.
Although a one-dimensional array is automatically converted to a pointer, the same does not hold for a multi-dimensional array and multi-level pointers.
If you change the order of the calc and main functions (or if you provide a prototype for calc before main), you will get a complaint from the compiler that it can convert right to the type int**.
The reason is that right is declared as an "array of 4 arrays of 3 int". This can be automatically converted to "pointer to array of 3 int" (int (*)[3]), but that is where the conversions stop.
calc on the other hand expects a "pointer to a pointer to int", which is a completely different beast from a "pointer to array of 3 int".
There are two possible solutions:
Change calc to accept a pointer to an array (or array of arrays):
int calc(int right[][3])
Change right to be a pointer to a pointer:
int temp_array[4][3];
int* temp_array2[4] = { temp_array[0], temp_array[1], temp_array[2], temp_array[3] };
int** right = temp_array2;

Resources