What does `double (* data)[5];` mean? - c

I understand that double * price[5]; is an array of pointers. What does double (* data)[5] mean? Where is it used for?

It's a pointer to an array of 5 doubles. Rarely used.
cdecl.org is useful to answer these kinds of questions for yourself:
declare data as pointer to array 5 of double

It's a pointer to array or array pointer. Think of it as a pointer that can point at the array as whole rather than just at the first item of the array.
These are mainly there to keep the language type system consistent. If you have an array double price[5], then &price gives the address of that array, which needs a corresponding pointer type double (*) [5]. This type can only be used to point at an array of 5 double, unlike a double* which can be used to point at the first item of any array of double. So it is less generic but more type safe.
One of the main uses for array pointers is dynamic allocation of multi-dimensional arrays. These should be allocated with a single statement like this:
int (*array) [x][y][z] = malloc( sizeof(int[x][y][z]) );
or equivalent
int (*array) [x][y][z] = malloc( sizeof *array );
That way we get a true "3D array" with all memory allocated adjacently, no heap fragmentation etc. The problem is however that array pointers are cumbersome: to use the pointer in the example above, we would have to de-reference it (like any pointer): (*array)[i][j][k] = ....
To avoid that burdensome syntax, we can instead create an pointer to the first element, which is an array of type int [y][z]:
int (*array)[y][z] = malloc( sizeof(int[x][y][z]) );
...
array[i][j][k] = ... ;
where the array[i] is pointer arithmetic referring to array number i of type int[y][z], [j] refers to an array of type int [z] and [k] refers to an int.
Other uses of array pointers is increasing type safety of arrays passed to functions, or returning a pointer to an array from a function.

Related

Can someone please clarify what this is asking me to do?

I understand the creation of the array (int** intptrArray[5]) and the rand() number part. However, I don't understand the sentence in the middle - I know I need to allocate the array first and then allocate each pointer in the array to an int but I'm not sure how to go about it and I've been stuck for hours on this. Do I need to use malloc here and how would I do that?
The requirement
create an array of int * (i.e., int **)
is a contradiction. A object can be a array or a pointer, a array of pointers, a pointer to a array or some combination of it. But a pointer is not the same as a array and a array is not a pointer and a pointer is not an array. Arrays do often decay to pointers when you access them but there are still 2 different concepts.
An array can have the type int *intptrArray[], the type int **intptrPtr is a pointer to pointer to int, this includes the possibility of a pointer to an array of pointers to int, a pointer to a pointer to an array of int or a pointer to an array of pointers to arrays of int.
The requirement
of size 5
is misleading. According to the C standard, the size of an object is measured in bytes. Creating an array of size 5 with int * is often not possible because a pointer has the size of 4 or 8 bytes on many platforms. C standard does not limit the possible size of a pointer, so 5 is a possibility but i never saw a machine that supports this. I think he meant the length of the array.
I think it is best to ask the guy that gave you this requirement for clarification.
It seems you need to declare in the file scope a variable of the pointer type int ** like
int **intptrArray;
then in a function (for example in main) you need to allocate an array of 5 elements of the type int * like
intptrArray = malloc( 5 * sizeof( int * ) );
Then in a loop each element of the array should be initialized by a pointer to dynamically allocate memory for one object of the type int.
And then using the function rand you need to assign values to these integers.
For example
for ( size_t i = 0; i < 5; i++ )
{
intptrArray[i] = malloc( sizeof( int ) );
*intptrArray[i] = rand();
}

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.

Doesn't a 2D array decay to pointer to pointer

Up till now I was pretty much sure that
int arr[4][5];
Then arr will decay to pointer to pointer.
But this link proves me wrong.
I am not sure how did I get about arr being pointer to pointer but it seemed pretty obvious to me. Because arr[i] would be a pointer, and hence arr should be a pointer to pointer.
Am I missing out on something.
Yep you are missing out on a lot :)
To avoid another wall of text I'll link to an answer I wrote earlier today explaining multi-dimensional arrays.
With that in mind, arr is a 1-D array with 4 elements, each of which is an array of 5 ints.
When used in an expression other than &arr or sizeof arr, this decays to &arr[0]. But what is &arr[0]? It is a pointer, and importantly, an rvalue.
Since &arr[0] is a pointer, it can't decay further. (Arrays decay, pointers don't). Furthermore, it's an rvalue. Even if it could decay into a pointer, where would that pointer point? You can't point at an rvalue. (What is &(x+y) ? )
Another way of looking at it is to remember that int arr[4][5]; is a contiguous bloc of 20 ints, grouped into 4 lots of 5 within the compiler's mind, but with no special marking in memory at runtime.
If there were "double decay" then what would the int ** point to? It must point to an int * by definition. But where in memory is that int * ? There are certainly not a bunch of pointers hanging around in memory just in case this situation occurs.
A simple rule is:
A reference to an object of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element; the type of the resultant pointer is pointer-to-T.
When you deal with 1D array, array name converts to pointer to first element when passed to a function.
A 2D array can be think as of an array of arrays. In this case int arr[4][5];, you can think arr[] as an array name and when passed to a function then converts to a pointer to the first element of array arr. Since first element of arr is an array, arr[i] is a pointer to ith row of the array and is of type pointer to array of 5 ints.
In general, a 2-dim array is implemented as an array of pointers (which, in a sense, is a pointer to a pointer... a pointer to the first element (i.e., pointer) in the array) When you specify the first index (i.e., arr[x]), it indexes into the array of pointers and gives the pointer to the x-th row. The the second index (i.e., arr[x][y]) gives the y-th int in that row.
In the case of a static declared array (as in your example), the actual storage is allocated as a single block ... in your example, as a single contiguous block of 20 integers (80 bytes, on most platforms). In this case, there IS no array of pointers, the compiler just does the appropriate arithmetic to address the correct element of the array. Specifically, arr[x][y] is equivalent to *(arr + x * 5 + y). This automatically-adjusted-arithmetic only happens in the original scope of the array... if you pass the array to a function, the dimension information is lost (just as the dimension is lost for a 1-dim array), and you have to do the array-indexing calculations explicitly.
To avoid this, do NOT declare the array as static, but as an array of pointers, with each pointer pointed to a 1-dim array, such as in this example:
int arr0[5];
int arr1[5];
int arr2[5];
int arr3[5];
int* arr[4] = { arr0, arr1, arr2, arr3 };
Then, when you pass arr to a function, you can address it as a 2-dim array within the function as well.

How to pass "pointer to a pointer" to a function that expects "pointer to array"

Consider this piece of code:
#define MAX 4
............
............
int** ptr = (int**)malloc(sizeof(int*)*MAX);
*ptr = (int*)malloc(sizeof(int)*MAX);
// Assigned values to the pointer successfully
How foo() can be invoked with ptr as parameter ? foo()'s prototype has been declared as below:
void foo(int arr[][MAX]);
You can't pass ptr as parameter to that foo function.
The memory layout of a 2-dimensional array (array of arrays) is quite different from that of an array of pointers to arrays.
Either change the function signature to accept a int** (and probably also size information), or define ptr to be a 2-dimensional array of the appropriate size.
I am going to assume the function foo in your example actually wants a 2-D array of int, with MAX columns and an unspecified number of rows. This works in C and C++ because of how the rows lay out in memory. All the elements in row N+1 appear contiguously after all the elements in row N.
The syntax int arr[][MAX] asks for a pointer to the first element of such a 2-D array, not an array of pointers to rows. I'll assume you want the 2-D array, and not an array of pointers.
First, you need to correctly allocate your elements. You haven't specified what the leftmost dimension of arr[][MAX] is, or where it comes from. I'll assume it's in the variable dim here:
int (*ptr)[MAX]; /* pointer first element of an int[][MAX] array */
/* Allocate a 2-D array of dim * MAX ints */
ptr = (int (*)[MAX]) malloc( dim * MAX * sizeof(int) );
Then, to call your function, just do foo( ptr ) and it'll work without errors or warnings.
To make your code cleaner (especially if you're using many of these 2-D arrays), you might consider wrapping the pointer type in a typedef, and writing a small function to allocate these arrays.
typedef int (*int_array_2d)[MAX];
int_array_2d alloc_int_array_2d( int dim1 )
{
return (int_array_2d) malloc( dim1 * MAX * sizeof(int) );
}
That way, elsewhere in your code, you can say something much simpler and cleaner:
int_array_2d ptr = alloc_int_array_2d( dim );
Use the type system to your advantage. The C and C++ syntax for the type and the typecast are ugly, and unfamiliar to most people. They look strange due to the precedence of * vs. []. If you hide it in a typedef though, it can help keep you focused on what you're trying to do, rather than understanding C/C++'s weird precedence issues that arise when you mix arrays and pointers.

Pointers equivalent to Arrays

I know that If i define an array like
int a [10];
I can use a pointer notation, to access it's address using a+<corresponding_item_in_array>
and it's value using, *(a+<corresponding_item_in_array>) .
Now I wanted to reverse things, I used malloc to allocate a memory to a integer pointer, and tried to represent the pointer in subscript notation but it didn't work
int *output_array;
output_array = (int *) (malloc(2*2*2*sizeof(int))); //i.e, space for 3d array
output_array[0][0][1] = 25;
// ^ produces error: subscripted value is neither array nor pointer
I may have used an pointer expression using Storage Mapping, but ain't the simpler method available? and Why?
The int* type is not an equivalent of the 3D array type; it is an equivalent of a 1D array type:
int *output_array;
output_array = (int *) (malloc(8*sizeof(int))); //i.e, space for array of 8 ints
output_array[5] = 25; // This will work
The problem with arrays of higher ranks is that in order to index into a 2D, 3D, etc. array the compiler must know the size of each dimension except the first one in order to calculate the offsets from the indexes correctly. To deal with 3D arrays, define a 2D element, like this:
typedef int element2d[2][2];
Now you can do this:
element2d *output_array;
output_array = (element2d*) (malloc(2*sizeof(element2d)));
output_array[0][0][1] = 25; // This will work now
Demo on ideone.
What's the type of output_array? int *.
What's the type of *(output_array+n) or output[n]? int.
Is subscript permitted on int? Both subscripts (eg. *(output_array+n) and output[n]) are pointer operations, and int is not a pointer. This explains the error you recieved.
You can declare a pointer to int[x][y] like this: int (*array)[x][y];
You can allocate storage that's a suitable alternative to a 3D array to array using: array = malloc(42 * x * y);. This would be the equivalent to int array[42][x][y];, except that arrays aren't modifiable lvalues, the alignof, sizeof and address-of operators work differently and the storage duration is different.
Because compiler doesn't have any idea about the size of each dimension, so it's not able to find out where output_array[0][0][1] should be.
You could try this
typedef int (* array3d)[2][2];
array3d output_array;
output_array = (array3d) malloc(2 * 2 * 2 * sizeof(int));
output_array[0][0][1] = 25;
printf("%d\n", output_array[0][0][1]);

Resources