How do you create an array of pointers in C?
To create an array of pointers in C, you have one option, you declare:
type *array[CONST]; /* create CONST number of pointers to type */
With C99+ you can create a Variable Length Array (VLA) of pointers, e.g.
type *array[var]; /* create var number of pointers to type */
The standard defines both in C11 Standard - 6.7.6.2 Array declarators and discusses subscripting in C11 Standard - 6.5.2.1 Array subscripting.
A short example using an array of pointers, assigning a pointer to each row in a 2D array to an array of pointers to int, e.g.
#include <stdio.h>
#include <stdlib.h>
#define COL 3
#define MAX 5
int main (void) {
int arr2d[MAX][COL] = {{ 0 }}, /* simple 2D array */
*arr[MAX] = { NULL }, /* 5 pointers to int */
i, j, v = 0;
for (i = 0; i < MAX; i++) { /* fill 2D array */
for (j = 0; j < COL; j++)
arr2d[i][j] = v++;
arr[i] = arr2d[i]; /* assing row-pointer to arr */
}
for (i = 0; i < MAX; i++) { /* for each pointer */
for (j = 0; j < COL; j++) /* output COL ints */
printf (" %4d", arr[i][j]);
putchar ('\n');
}
}
Example Use/Output
$ ./bin/array_ptr2int_vla
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
Another fundamental of C is the pointer-to-pointer, but it is not an "Array", though it is routinely called a "dynamic array" and can be allocated and indexed simulating an array. The distinction between an "Array" and a collection of pointers is that with an Array, all values are guaranteed to be sequential in memory -- there is no such guarantee with a collection of pointers and the memory locations they reference.
So What Does int **arr[CONST] Declare?
In your question you posit a declaration of int** arr[5] = {0xbfjeabfbfe,0x...};, so what does that declare? You are declaring Five of something, but what? You are declaring five pointer-to-pointer-to-int. Can you do that? Sure.
So what do you do with a pointer-to-pointer-to-something? The pointer-to-poitner forms the backbone of dynamically allocated and reallocated collection of types. They are commonly termed "dynamically allocated arrays", but that is somewhat a misnomer, because there is no guarantee that all values will be sequential in memory. You will declare a given number of pointers to each int** in the array. You do not have to allocate an equal number of pointers.
(note: there is no guarantee that the memory pointed to by the pointers will even be sequential, though the pointers themselves will be -- make sure you understand this distinction and what an "Array" guarantees and what pointers don't)
int** arr[5] declares five int**. You are then free to assign any address to you like to each of the five pointers, as long as the type is int**. For example, you will allocate for your pointers with something similar to:
arr[i] = calloc (ROW, sizeof *arr[i]); /* allocates ROW number of pointers */
Then you are free to allocate any number of int and assign that address to each pointer, e.g.
arr[i][j] = calloc (COL, sizeof *arr[i][j]); /* allocates COL ints */
You can then loop over the integers assigning values:
arr[i][j][k] = v++;
A short example using your int** arr[5] type allocation could be similar to:
#include <stdio.h>
#include <stdlib.h>
#define ROW 3
#define COL ROW
#define MAX 5
int main (void) {
int **arr[MAX] = { NULL }, /* 5 pointer-to-pointer-to-int */
i, j, k, v = 0;
for (i = 0; i < MAX; i++) { /* allocate ROW pointers to each */
if ((arr[i] = calloc (ROW, sizeof *arr[i])) == NULL) {
perror ("calloc - pointers");
return 1;
}
for (j = 0; j < ROW; j++) { /* allocate COL ints each pointer */
if ((arr[i][j] = calloc (COL, sizeof *arr[i][j])) == NULL) {
perror ("calloc - integers");
return 1;
}
for (k = 0; k < COL; k++) /* assign values to ints */
arr[i][j][k] = v++;
}
}
for (i = 0; i < MAX; i++) { /* output each pointer-to-pointer to int */
printf ("pointer-to-pointer-to-int: %d\n\n", i);
for (j = 0; j < ROW; j++) { /* for each allocated pointer */
for (k = 0; k < COL; k++) /* output COL ints */
printf (" %4d", arr[i][j][k]);
free (arr[i][j]); /* free the ints */
putchar ('\n');
}
free (arr[i]); /* free the pointer */
putchar ('\n');
}
return 0;
}
You have allocated for five simulated 2D arrays assigning the pointer to each to your array of int **arr[5], the output would be:
Example Use/Output
$ ./bin/array_ptr2ptr2int
pointer-to-pointer-to-int: 0
0 1 2
3 4 5
6 7 8
pointer-to-pointer-to-int: 1
9 10 11
12 13 14
15 16 17
pointer-to-pointer-to-int: 2
18 19 20
21 22 23
24 25 26
pointer-to-pointer-to-int: 3
27 28 29
30 31 32
33 34 35
pointer-to-pointer-to-int: 4
36 37 38
39 40 41
42 43 44
Hopefully this has helped with the distinction between an array of pointers, and an array of pointers-to-pointer and shown how to declare and use each. If you have any further questions, don't hesitate to ask.
Answer from David C. Rankin on Stack OverflowHow do you create an array of pointers in C?
To create an array of pointers in C, you have one option, you declare:
type *array[CONST]; /* create CONST number of pointers to type */
With C99+ you can create a Variable Length Array (VLA) of pointers, e.g.
type *array[var]; /* create var number of pointers to type */
The standard defines both in C11 Standard - 6.7.6.2 Array declarators and discusses subscripting in C11 Standard - 6.5.2.1 Array subscripting.
A short example using an array of pointers, assigning a pointer to each row in a 2D array to an array of pointers to int, e.g.
#include <stdio.h>
#include <stdlib.h>
#define COL 3
#define MAX 5
int main (void) {
int arr2d[MAX][COL] = {{ 0 }}, /* simple 2D array */
*arr[MAX] = { NULL }, /* 5 pointers to int */
i, j, v = 0;
for (i = 0; i < MAX; i++) { /* fill 2D array */
for (j = 0; j < COL; j++)
arr2d[i][j] = v++;
arr[i] = arr2d[i]; /* assing row-pointer to arr */
}
for (i = 0; i < MAX; i++) { /* for each pointer */
for (j = 0; j < COL; j++) /* output COL ints */
printf (" %4d", arr[i][j]);
putchar ('\n');
}
}
Example Use/Output
$ ./bin/array_ptr2int_vla
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
Another fundamental of C is the pointer-to-pointer, but it is not an "Array", though it is routinely called a "dynamic array" and can be allocated and indexed simulating an array. The distinction between an "Array" and a collection of pointers is that with an Array, all values are guaranteed to be sequential in memory -- there is no such guarantee with a collection of pointers and the memory locations they reference.
So What Does int **arr[CONST] Declare?
In your question you posit a declaration of int** arr[5] = {0xbfjeabfbfe,0x...};, so what does that declare? You are declaring Five of something, but what? You are declaring five pointer-to-pointer-to-int. Can you do that? Sure.
So what do you do with a pointer-to-pointer-to-something? The pointer-to-poitner forms the backbone of dynamically allocated and reallocated collection of types. They are commonly termed "dynamically allocated arrays", but that is somewhat a misnomer, because there is no guarantee that all values will be sequential in memory. You will declare a given number of pointers to each int** in the array. You do not have to allocate an equal number of pointers.
(note: there is no guarantee that the memory pointed to by the pointers will even be sequential, though the pointers themselves will be -- make sure you understand this distinction and what an "Array" guarantees and what pointers don't)
int** arr[5] declares five int**. You are then free to assign any address to you like to each of the five pointers, as long as the type is int**. For example, you will allocate for your pointers with something similar to:
arr[i] = calloc (ROW, sizeof *arr[i]); /* allocates ROW number of pointers */
Then you are free to allocate any number of int and assign that address to each pointer, e.g.
arr[i][j] = calloc (COL, sizeof *arr[i][j]); /* allocates COL ints */
You can then loop over the integers assigning values:
arr[i][j][k] = v++;
A short example using your int** arr[5] type allocation could be similar to:
#include <stdio.h>
#include <stdlib.h>
#define ROW 3
#define COL ROW
#define MAX 5
int main (void) {
int **arr[MAX] = { NULL }, /* 5 pointer-to-pointer-to-int */
i, j, k, v = 0;
for (i = 0; i < MAX; i++) { /* allocate ROW pointers to each */
if ((arr[i] = calloc (ROW, sizeof *arr[i])) == NULL) {
perror ("calloc - pointers");
return 1;
}
for (j = 0; j < ROW; j++) { /* allocate COL ints each pointer */
if ((arr[i][j] = calloc (COL, sizeof *arr[i][j])) == NULL) {
perror ("calloc - integers");
return 1;
}
for (k = 0; k < COL; k++) /* assign values to ints */
arr[i][j][k] = v++;
}
}
for (i = 0; i < MAX; i++) { /* output each pointer-to-pointer to int */
printf ("pointer-to-pointer-to-int: %d\n\n", i);
for (j = 0; j < ROW; j++) { /* for each allocated pointer */
for (k = 0; k < COL; k++) /* output COL ints */
printf (" %4d", arr[i][j][k]);
free (arr[i][j]); /* free the ints */
putchar ('\n');
}
free (arr[i]); /* free the pointer */
putchar ('\n');
}
return 0;
}
You have allocated for five simulated 2D arrays assigning the pointer to each to your array of int **arr[5], the output would be:
Example Use/Output
$ ./bin/array_ptr2ptr2int
pointer-to-pointer-to-int: 0
0 1 2
3 4 5
6 7 8
pointer-to-pointer-to-int: 1
9 10 11
12 13 14
15 16 17
pointer-to-pointer-to-int: 2
18 19 20
21 22 23
24 25 26
pointer-to-pointer-to-int: 3
27 28 29
30 31 32
33 34 35
pointer-to-pointer-to-int: 4
36 37 38
39 40 41
42 43 44
Hopefully this has helped with the distinction between an array of pointers, and an array of pointers-to-pointer and shown how to declare and use each. If you have any further questions, don't hesitate to ask.
An array of pointers to ints;
int x = 1;
int y = 42;
int z = 12;
int * array[3];
array[0] = &x;
array[1] = &y;
array[2] = &z;
alternate syntax
int * array[] = {&x,&y,&z};
keeping it simple. Work upwards from there
C: pointer to array of pointers to structures (allocation/deallocation issues) - Stack Overflow
Are C arrays pointers ?
What is the purpose of arrays in C, when pointers could have done the job? - Software Engineering Stack Exchange
changing base address of array with pointers?
why afterall both 'b' and 'a' point to memory address of array
Because you don't change either of them? Note that you can't add to a. a is an array, you can't add to arrays. b however is a pointer. You can add to pointers to change where they point. Under most circumstances, an object of array type is implicitly converted to a pointer to the first element of that array, but the result is not an lvalue, so you can't assign to it. I hope this explains your confusion.
How do I declare an array of pointers?
To declare an array of pointers, you'd specify the pointer type first, followed by the array name and its size. In C or C++, you might do something like int *arr[5];, which declares an array of 5 pointers to integers.
What are the common use-cases for arrays of pointers?
Arrays of pointers are particularly useful when you're working with strings, dynamic memory allocation, or when you want to create an array of different-sized arrays. They're also handy for function pointers, allowing you to call different functions through your array elements.
Can I initialize an array of pointers at the time of declaration?
Yes, you can initialize an array of pointers at the time of declaration. For example, you could write int *arr[] = {&x, &y, &z}; where x, y, z are integers already declared in your code. This will store the addresses of x, y, z in the array.
Videos
So i am learning command lines arguments and just came cross char *argv[]. What does this actually do, I understand that this makes every element in the array a pointer to char, but i can't get around as to how all of this is happening. How does it treat every other element as another string? How come because essentialy as of my understanding rn, a simple char would treat as a single contiguous block of memory, how come turning this pointer to another pointer of char point to individual elements of string?
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!
Hello,
I'm new to C and would like to understand the differences between pointers and arrays. Everyone keeps telling me arrays are pointers but the following situation confuses me :
When i declare an array :
int myArray[] = {1,2,3,4};
I can get a pointer on the first element of this array:
int* myPointer = myArray;
When iterating in a for loop, i can use the following :
*(myPointer+i) = ... or
*(myArray+i) = ...
When iterating in a while loop, i can use my pointer :
*myPointer++ = ... but can't use
*myArray++ = ...
Is it because arrays are not pointers and increment operator is not defined for arrays ?
Thanks for your help ๐
Arrays are contiguous memory created on the stack. You can't guarantee contiguous stack memory without this syntactic sugar, and even if you could, you'd have to allocate a separate pointer in order to be able to do the pointer arithmetic (unless you wanted to do *(&foo + x), which I'm not sure but it might violate l-value semantics, but is at least quite awkward, and would scream out for some kind of syntactic sugar). Design-wise, it also is a form of encapsulation, since you can refer to the collection with a single identifier (which would otherwise require a separate pointer). And even if you could allocate them contiguously and allocated a separate pointer to reference them, you'd have either
int fooForSomething, fooForSomethingElse...
which forces a fair amount of creativity as your collection grows, so you might think to simplify with
int foo1, foo2 ...,
which looks just like an array but is harder to maintain.
Array notation is convenient, easier to read, and less prone to errors. It provides a formalism over pointers. It might be syntactic sugar, but we all need a little sweetness once in awhile, don't we?
As with all abstractions, you give up a little flexibility for the convenience that the abstraction provides.