Why did we allocate memory for matrix with double pointers?

Viewed 178

I have a hard time understanding this code:

int **arr = malloc(l * sizeof(int *));
for (i=0; i<l; i++)
  ​arr[i] = (int *)malloc(c * sizeof(int));`
  1. Why did we use a double pointer and not just one?
  2. And also I didn't understand the logic behind this code, so can you please explain it to me line by line.
3 Answers

The posted code allocates an indirect 2D matrix: an array of pointers each pointing to an array of int. This is allows for the matrix cells to be referred to as array2D[i][j] and was the solution in classic C (pre-c99) for variable numbers of columns.

C99 allows for a more efficient way to allocate or manipulate matrices with variable numbers of columns using a new construction called variable length arrays (VLA). This feature is not available in C++, that has more specific ways to represent vectors and matrices. It was not implemented in all C compilers and the Standard Committee decided to make it optional as of C11.

Here is an example using VLAs:

#include <stdio.h>
#include <stdlib.h>

void matrix_init(int rows, int cols, int matrix[rows][cols]) {
    int n = 0;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = n++;
        }
    }
}

void matrix_print(int rows, int cols, int matrix[rows][cols]) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("  %d", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int rows = 3;
    int cols = 4;
    // define `matrix` as a pointer to arrays of `cols` integers.
    // allocate the matrix as an array of such variable length arrays.
    // could also write `calloc(sizeof(int[cols]), rows)` 
    int (*matrix)[cols] = calloc(sizeof(*matrix), rows);
    matrix_init(rows, cols, matrix);
    matrix_print(rows, cols, matrix);
    free(matrix);
    return 0;
}

Why did we use a double pointer and not just one?

Double pointers are used to let syntax x[i][j] work. Simply speaking [] involves dereference and removing one star (*) from variable's type.

For example:

int *p;  // p type is int*
p[3];    // p[3] type is int
int **q; // q type is int**
q[2];    // q[2] type is int*
q[2][3]; // q[2][3] type is int

there is a distinct difference between the pointer to int and the pointer to int array. Below you have an example how to allocate the memory for the 2D array.

    int (*array2D)[rows][cols] = malloc(sizeof(*array2D));

Related