Difficulty: ★ ★ ★ ☆
I received a question via email regarding my recently-published book, Dan Gookin’s Guide to C Language Pointers (available at Amazon!). The question: How to use a pointer to navigate a multi-dimension array? While I do cover pointers to an array of strings (which is kinda what the reader wanted), I don’t specifically cover pointers and multi-dimensional arrays. Therefore, I created this month’s exercise to tackle the task.
Multi-dimensional arrays are useful for representing data in grids or matrixes. But the array notation used in C is only for your benefit; internally, the data is stored sequentially. The compiler does the math to ensure that the proper element is referenced no matter what dimensions are specified. Translating this data into pointers is a matter of approach coupled with various math thingies.
To start, I present the following code, which populates a two-dimensional array with random data:
2026_05_01-Lesson.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 4
#define COL 3
int main()
{
int values[ROW][COL];
int x,y;
/* seed the randomizer */
srand( (unsigned)time(NULL) );
/* populate and output the grid */
for( y=0; y<ROW; y++ )
{
for( x=0; x<COL; x++ )
{
values[y][x] = rand() % 100;
printf("[%d][%d] = %d\t",y,x,values[y][x]);
}
putchar('\n');
}
return 0;
}
The program’s output changes with each run, but here’s a sample:
[0][0] = 36 [0][1] = 70 [0][2] = 65 [1][0] = 14 [1][1] = 27 [1][2] = 99 [2][0] = 13 [2][1] = 62 [2][2] = 4 [3][0] = 42 [3][1] = 54 [3][2] = 9
Your task for this month’s Exercise is to use one or more pointers to navigate through the matrix and output the data.
In my solution, I output the data three times in addition to the initial output above:
- I use a single point to output the values.
- I use a single pointer, but output the values in a grid format.
- I use two pointers to work through each dimension of the array.
The way you manage your solution is up to you, though I’ll present all three in mine.
As a hefty tip, be aware that obtaining the base address of a multi-dimension array isn’t as straightforward as obtaining the address of a single-dimension array. For a typical array, such as array[], you can assign pointer a to the address by using the following statement:
a = array;
This approach doesn’t work for multi-dimensional arrays. I don’t know if there is an established trick to make the assignment, so what I use is the following:
a = array[0][0];
Pointer a is assigned the address of the array’s first element. As arrays are stored sequentially in memory, this approach works. Feel free to use it in your code, unless you can think of something better.
Click here to view my solution.
In my solution I didnʼt really follow the given instructions… sorry about that
Going with Jens Gustedts don’t be afraid of variably modified types I instead tried to solve the given task by relying on “variably-modified types” (VMT).
While the general consensus nowadays seems to be that VLAs (“variable-length arrays”) were a mistake (because its all too easy to exhaust available stack memory this way), relying on just the types of such VLAs is another thing entirely. If the compiler one relies on comes with support for C99ʼs VLA syntax, this can be a great way to simplify working with (multidimensional) arrays.
Actually there are two possibilities to use implement dynamically allocated two-dimensional arrays using VLA types:
1. as a pointer to a dynamically allocated 2-d array with a VLA type of
int [rows][cols]2. as a pointer to an array of 1-d arrays, each having a VLA type of
int [cols]The following supposes that there exists a function
print_matrix()which is typed as follows:void print_matrix (size_t const rows, size_t const cols, int matrix [rows][cols]);
ad 1.
/* values is a pointer to a dynamically allocated 2-d array (with ‘rows’ rows of ‘cols’ int each): */
int (*values) [4][3] = malloc (sizeof (*values));
/* the type of *values is a VLA capturing the number of rows and columns, which could therefore be calculated like so: */
size_t const rows = sizeof (*values) / sizeof ((*values) [0]);
size_t const cols = sizeof ((*values) [0]) / sizeof ((*values) [0][0]);
/* the following works because while the type of ‘*values’ is ‘int [rows][cols]’, the compiler will pass the array as a pointer to its first element, i.e. ‘int (*) [cols]’ */
print_matrix (rows, cols, *values);
ad 2.
size_t const rows = 4;
/* values is a pointer to a dynamically allocated array of 1-d arrays (of ‘cols’ int each): */
int (*values) [3] = malloc (rows * sizeof(*values));
/* the type of *values is a VLA capturing the number of columns, which could therefore be calculated like so: */
size_t const cols = sizeof (*values) / sizeof ((*values) [0]);
/* the following works because the type of ‘values’ is ‘int (*) [cols]’ (“pointer to an array of cols int”) which exactly matches the one expected by the functions ‘matrix’ parameter */
print_matrix (rows, cols, values);
In practice, most people seem to prefer variant 2. since itʼs a bit simpler. Of course, if the compiler in question doesnʼt support VLAs (and thus VMTs) there is no other choice than to use ‘int *values = malloc (rows * cols * sizeof (*values));’ and access all the elements using either pointer or 1-d array arithmetic.
Anyway, I wrote some code that illustrates both of the above alternatives which can be found here.
Yeah, you put way too much work into that! 🙂