The correct answer is:
int* arr[MAX];
int* (*pArr)[MAX] = &arr;
Or just:
int* arr [MAX];
typedef int* arr_t[MAX];
arr_t* pArr = &arr;
The last part reads as "pArr is a pointer to array of MAX elements of type pointer to int".
In C the size of array is stored in the type, not in the value. If you want this pointer to correctly handle pointer arithmetic on the arrays (in case you'd want to make a 2-D array out of those and use this pointer to iterate over it), you - often unfortunately - need to have the array size embedded in the pointer type.
Luckily, since C99 and VLAs (maybe even earlier than C99?) MAX can be specified in run-time, not compile time.
Answer from Kos on Stack OverflowThe correct answer is:
int* arr[MAX];
int* (*pArr)[MAX] = &arr;
Or just:
int* arr [MAX];
typedef int* arr_t[MAX];
arr_t* pArr = &arr;
The last part reads as "pArr is a pointer to array of MAX elements of type pointer to int".
In C the size of array is stored in the type, not in the value. If you want this pointer to correctly handle pointer arithmetic on the arrays (in case you'd want to make a 2-D array out of those and use this pointer to iterate over it), you - often unfortunately - need to have the array size embedded in the pointer type.
Luckily, since C99 and VLAs (maybe even earlier than C99?) MAX can be specified in run-time, not compile time.
Should just be:
int* array[SIZE];
int** val = array;
There's no need to use an address-of operator on array since arrays decay into implicit pointers on the right-hand side of the assignment operator.
I've been reading K&R and the syntax that differentiates an array of pointers vs a pointer to an array is confusing me. They say that
int *array[100];
is an array of 100 pointers to integers. On the other hand,
int (*array)[100];
is a pointer to an array of 100 integers.
Can someone elaborate on why this is the case?
It seems to me that it should be the other way around, since *(array[100]) reads like a pointer to an array with 100 elements, while (*array)[100] looks very much like it should be an array of 100 pointers.
What am I missing here?
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
The third one is same as the first.
The general rule is operator precedence. It can get even much more complex as function pointers come into the picture.
Use the cdecl program, as suggested by K&R.
$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
It works the other way too.
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
void f(int *a) {
void *p = &a;
***(int*(*)[])p = 1;
}This code is from a tweet. It's probably something simple, but I don't understand what's going on.
I tried finding it on the web, no luck. I don't see any special behaviour for casting to an array in the C89 standard draft either.
Can anyone explain me what's going on? It seems to set *a to 1.
Thanks in advance!
Edit: this is the tweet I'm talking about.
Allocated Array
With an allocated array it's straightforward enough to follow.
Declare your array of pointers. Each element in this array points to a struct Test:
struct Test *array[50];
Then allocate and assign the pointers to the structures however you want. Using a loop would be simple:
array[n] = malloc(sizeof(struct Test));
Then declare a pointer to this array:
// an explicit pointer to an array
struct Test *(*p)[] = &array; // of pointers to structs
This allows you to use (*p)[n]->data; to reference the nth member.
Don't worry if this stuff is confusing. It's probably the most difficult aspect of C.
Dynamic Linear Array
If you just want to allocate a block of structs (effectively an array of structs, not pointers to structs), and have a pointer to the block, you can do it more easily:
struct Test *p = malloc(100 * sizeof(struct Test)); // allocates 100 linear
// structs
You can then point to this pointer:
struct Test **pp = &p
You don't have an array of pointers to structs any more, but it simplifies the whole thing considerably.
Dynamic Array of Dynamically Allocated Structs
The most flexible, but not often needed. It's very similar to the first example, but requires an extra allocation. I've written a complete program to demonstrate this that should compile fine.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Test {
int data;
};
int main(int argc, char **argv)
{
srand(time(NULL));
// allocate 100 pointers, effectively an array
struct Test **t_array = malloc(100 * sizeof(struct Test *));
// allocate 100 structs and have the array point to them
for (int i = 0; i < 100; i++) {
t_array[i] = malloc(sizeof(struct Test));
}
// lets fill each Test.data with a random number!
for (int i = 0; i < 100; i++) {
t_array[i]->data = rand() % 100;
}
// now define a pointer to the array
struct Test ***p = &t_array;
printf("p points to an array of pointers.\n"
"The third element of the array points to a structure,\n"
"and the data member of that structure is: %d\n", (*p)[2]->data);
return 0;
}
Output:
> p points to an array of pointers.
> The third element of the array points to a structure,
> and the data member of that structure is: 49
Or the whole set:
for (int i = 0; i < 100; i++) {
if (i % 10 == 0)
printf("\n");
printf("%3d ", (*p)[i]->data);
}
35 66 40 24 32 27 39 64 65 26
32 30 72 84 85 95 14 25 11 40
30 16 47 21 80 57 25 34 47 19
56 82 38 96 6 22 76 97 87 93
75 19 24 47 55 9 43 69 86 6
61 17 23 8 38 55 65 16 90 12
87 46 46 25 42 4 48 70 53 35
64 29 6 40 76 13 1 71 82 88
78 44 57 53 4 47 8 70 63 98
34 51 44 33 28 39 37 76 9 91
Dynamic Pointer Array of Single-Dynamic Allocated Structs
This last example is rather specific. It is a dynamic array of pointers as we've seen in previous examples, but unlike those, the elements are all allocated in a single allocation. This has its uses, most notable for sorting data in different configurations while leaving the original allocation undisturbed.
We start by allocating a single block of elements as we do in the most basic single-block allocation:
struct Test *arr = malloc(N*sizeof(*arr));
Now we allocate a separate block of pointers:
struct Test **ptrs = malloc(N*sizeof(*ptrs));
We then populate each slot in our pointer list with the address of one of our original array. Since pointer arithmetic allows us to move from element to element address, this is straight-forward:
for (int i=0;i<N;++i)
ptrs[i] = arr+i;
At this point the following both refer to the same element field
arr[1].data = 1;
ptrs[1]->data = 1;
And after review the above, I hope it is clear why.
When we're done with the pointer array and the original block array they are freed as:
free(ptrs);
free(arr);
Note: we do NOT free each item in the ptrs[] array individually. That is not how they were allocated. They were allocated as a single block (pointed to by arr), and that is how they should be freed.
So why would someone want to do this? Several reasons.
First, it radically reduces the number of memory allocation calls. Rather then N+1 (one for the pointer array, N for individual structures) you now have only two: one for the array block, and one for the pointer array. Memory allocations are one of the most expensive operations a program can request, and where possible, it is desirable to minimize them (note: file IO is another, fyi).
Another reason: Multiple representations of the same base array of data. Suppose you wanted to sort the data both ascending and descending, and have both sorted representations available at the same time. You could duplicate the data array, but that would require a lot of copying and eat significant memory usage. Instead, just allocate an extra pointer array and fill it with addresses from the base array, then sort that pointer array. This has especially significant benefits when the data being sorted is large (perhaps kilobytes, or even larger, per item) The original items remain in their original locations in the base array, but now you have a very efficient mechanism in which you can sort them without having to actually move them. You sort the array of pointers to items; the items don't get moved at all.
I realize this is an awful lot to take in, but pointer usage is critical to understanding the many powerful things you can do with the C language, so hit the books and keep refreshing your memory. It will come back.
It may be better to declare an actual array, as others have suggested, but your question seems to be more about memory management so I'll discuss that.
struct Test **array1;
This is a pointer to the address of a struct Test. (Not a pointer to the struct itself; it's a pointer to a memory location that holds the address of the struct.) The declaration allocates memory for the pointer, but not for the items it points to. Since an array can be accessed via pointers, you can work with *array1 as a pointer to an array whose elements are of type struct Test. But there is not yet an actual array for it to point to.
array1 = malloc(MAX * sizeof(struct Test *));
This allocates memory to hold MAX pointers to items of type struct Test. Again, it does not allocate memory for the structs themselves; only for a list of pointers. But now you can treat array as a pointer to an allocated array of pointers.
In order to use array1, you need to create the actual structs. You can do this by simply declaring each struct with
struct Test testStruct0; // Declare a struct.
struct Test testStruct1;
array1[0] = &testStruct0; // Point to the struct.
array1[1] = &testStruct1;
You can also allocate the structs on the heap:
for (int i=0; i<MAX; ++i) {
array1[i] = malloc(sizeof(struct Test));
}
Once you've allocated memory, you can create a new variable that points to the same list of structs:
struct Test **array2 = array1;
You don't need to allocate any additional memory, because array2 points to the same memory you've allocated to array1.
Sometimes you want to have a pointer to a list of pointers, but unless you're doing something fancy, you may be able to use
struct Test *array1 = malloc(MAX * sizeof(struct Test)); // Pointer to MAX structs
This declares the pointer array1, allocated enough memory for MAX structures, and points array1 to that memory. Now you can access the structs like this:
struct Test testStruct0 = array1[0]; // Copies the 0th struct.
struct Test testStruct0a= *array1; // Copies the 0th struct, as above.
struct Test *ptrStruct0 = array1; // Points to the 0th struct.
struct Test testStruct1 = array1[1]; // Copies the 1st struct.
struct Test testStruct1a= *(array1 + 1); // Copies the 1st struct, as above.
struct Test *ptrStruct1 = array1 + 1; // Points to the 1st struct.
struct Test *ptrStruct1 = &array1[1]; // Points to the 1st struct, as above.
So what's the difference? A few things. Clearly, the first method requires you to allocate memory for the pointers, and then allocate additional space for the structs themselves; the second lets you get away with one malloc() call. What does the extra work buy you?
Since the first method gives you an actual array of pointers to Test structs, each pointer can point to any Test struct, anywhere in memory; they needn't be contiguous. Moreover, you can allocate and free the memory for each actual Test struct as necessary, and you can reassign the pointers. So, for example, you can swap two structures by simply exchanging their pointers:
struct Test *tmp = array1[2]; // Save the pointer to one struct.
array1[2] = array1[5]; // Aim the pointer at a different struct.
array1[5] = tmp; // Aim the other pointer at the original struct.
On the other hand, the second method allocates a single contiguous block of memory for all of the Test structs and partitions it into MAX items. And each element in the array resides at a fixed position; the only way to swap two structures is to copy them.
Pointers are one of the most useful constructs in C, but they can also be among the most difficult to understand. If you plan to continue using C, it'll probably be a worthwhile investment to spend some time playing with pointers, arrays, and a debugger until you're comfortable with them.
Good luck!
Pointer to an array
int a[10];
int (*ptr)[10];
Here ptr is an pointer to an array of 10 integers.
ptr = &a;
Now ptr is pointing to array of 10 integers.
You need to parenthesis ptr in order to access elements of array as (*ptr)[i] cosider following example:
Sample code
#include<stdio.h>
int main(){
int b[2] = {1, 2};
int i;
int (*c)[2] = &b;
for(i = 0; i < 2; i++){
printf(" b[%d] = (*c)[%d] = %d\n", i, i, (*c)[i]);
}
return 1;
}
Output:
b[0] = (*c)[0] = 1
b[1] = (*c)[1] = 2
Array of pointers
int *ptr[10];
Here ptr[0],ptr[1]....ptr[9] are pointers and can be used to store address of a variable.
Example:
main()
{
int a=10,b=20,c=30,d=40;
int *ptr[4];
ptr[0] = &a;
ptr[1] = &b;
ptr[2] = &c;
ptr[3] = &d;
printf("a = %d, b = %d, c = %d, d = %d\n",*ptr[0],*ptr[1],*ptr[2],*ptr[3]);
}
Output: a = 10, b = 20, c = 30, d = 40
Background
Think of pointers as just a separate data type. They have their own storage requirements -- such as their size -- they occupy 8 bytes on a x86_64 platform. This is the case of void pointers void*.
In those 8 bytes the information stored is the memory address of another piece of data.
The thing about pointers is that since they "point" to another piece of data, it's useful to know what type that data is too so you can correctly handle it (know its size, and structure).
In stead of having their own data type name such as pointer they compose their name based on the data type they refer to such as int* a pointer to an integer. If you want a plain pointer without type information attached to it you have the option of using void*.
So basically each pointer (to int, to char, to double) is just a void* (same size, same use) but the compiler knows the data being pointed to is of type int and allows you to handle it accordingly.
/**
* Create a new pointer to an unknown type.
*/
void* data;
/**
* Allocate some memory for it using malloc
* and tell your pointer to point to this new
* memory address (because malloc returns void*).
* I've allocated 8 bytes (char is one byte).
*/
data = malloc(sizeof(char)*8);
/**
* Use the pointer as a double by casting it
* and passing it to functions.
*/
double* p = (double* )data;
p = 20.5;
pow((double* )data, 2);
Pointer to array
If you have an array of values (let's say integers) somewhere in memory, a pointer to it is one variable containing its address.
You can access this array of values by first dereferencing the pointer and then operating some work on the array and its values.
/**
* Create an array containing integers.
*/
int array[30];
array[0] = 0;
array[1] = 1;
...
array[29] = 29;
/**
* Create a pointer to an array.
*/
int (*pointer)[30];
/**
* Tell the pointer where the data is.
*/
pointer = &array;
/**
* Access the data through the pointer.
*/
(*pointer)[1] = 999;
/**
* Print the data through the array.
* ...and notice the output.
*/
printf("%d", array[1]);
Array of pointers
If you have an array of pointers to values, the entire array of pointers is one variable and each pointer in the array refers to somewhere else in the memory where a value is located.
You can access this array and the pointers inside it without dereferencing it but in order to reach a certain value from it you will have to dereference one of the pointers inside the array.
/**
* Create an array containing pointers to integers.
*/
int *array_of_pointers[30];
array_of_pointers[0] = 0;
array_of_pointers[1] = 1;
...
array_of_pointers[29] = 29;