Search code examples
cpointersmatrixdynamic-memory-allocationsizeof

Segmentation Fault: Dynamically allocating matrix using a double pointer


Trying to understand the usage and memory allocation of double pointers in C.

Below is my code: -

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

int main()
{
    
    printf("Enter rows and columns respectively: -\n");
    
    int rows, columns;
    scanf("%d%d", &rows, &columns);
    
    int **matrix;
    
    matrix = calloc(rows, sizeof(int));
    
    int i, j;
    for(i = 0; i < rows; i++)
    {
        matrix[i] = calloc(columns, sizeof(int));
    }
    
    printf("Enter your elements\n");
    
    for(i = 0; i < rows; i++)
    {
        for(j = 0; j < columns; j++)
        {
            scanf("%d", &matrix[i][j]);
        }
    }
    
    printf("Your elements are: -\n");
    
    for(i = 0; i < rows; i++)
    {
        for(j = 0; j < columns; j++)
        {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    free(matrix);
    
    return 0;
}

After getting Segmentation fault: 11, I searched on the net and found out that instead of writing this: -

int **matrix;
matrix = calloc(rows, sizeof(int));

I should write: -

int **matrix;
matrix = calloc(rows, sizeof(int*));

After making the above changes, my code works fine.

My question is: -

  1. What is the difference between sizeof(int) and sizeof(int *)?
  2. Don't both of them allocate 4 bytes? (int occupies 4 bytes and int* (which is noting but a pointer) also occupies 4 bytes?
  3. If both of them allocates the same space, then why was I getting a Segmentation fault in the first case?

Solution

  • Don't both of them allocate 4 bytes? (int occupies 4 bytes and int* (which is noting but a pointer) also occupies 4 bytes?

    What makes you think that a pointer is four bytes? On most modern (64 bit) architectures, pointers to object are 8 bytes, not 4.

    Hence, in general sizeof(int) ≠ sizeof(int *). But you can’t make many assumptions about the sizes of objects in portable C code, and you definitely can’t assume that sizeof(int) == 4, or sizeof(int*) == 8 (nor 4). Depending on the platform, these sizes vary. They could also have the same size. You just can’t assume that.

    To avoid confusion between pointer and pointee size, some people (me included) recommend using the object name in the sizeof expression in allocations, rather than the type name:

    int **matrix = calloc(rows, sizeof *matrix);
    // …
    matrix[i] = calloc(columns, sizeof **matrix);
    

    This makes it clear what you are trying to allocate. Note that sizeof expr does not evaluate expr; this is important, since the expressions *matrix and **matrix are invalid before you’ve allocated the memory — deferencing the unassigned pointer would be undefined behaviour. But sizeof only determines the object size of the expression without actually evaluating it.