-1

I don't know what is wrong here, I get a seg fault when I try to run this code:

#include <stdlib.h>
    int **alloc_grid(int width, int height)
    {
        int i, j;
        int **grid;
   
        if (width < 1 || height < 1)
            return (NULL);
   
        grid = malloc(sizeof(int) * (width * height));
        if (grid == NULL)
            return (NULL);
        for (i = 0; i < height; i++)
        {
            for (j = 0; j < width; j++)
                grid[i][j] = 0;
        }
        return (grid);
    }

It's supposed to initialise the 2d array with 0.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
rzsamrio
  • 21
  • 4
  • 1
    I can't compile it: `error: expected unqualified-id before numeric constant 2`. It does not look like a segmentation fault. – 273K Mar 19 '23 at 19:49
  • oh, I forgot to add that this is a function to initialise the array and not main, so it wont compile. – rzsamrio Mar 19 '23 at 19:50
  • `grid[i][j]` does not work with `int **` as you suppose it. `grid[i]` is `int*` then `[j]` dereferences the uninitialized `int*`. – 273K Mar 19 '23 at 19:52
  • @273K oh, what should I do then? – rzsamrio Mar 19 '23 at 19:56
  • First `grid = malloc(sizeof(int*) * height));`. Then allocate memory for each row. – Weather Vane Mar 19 '23 at 20:00
  • Start from [How can I dynamically allocate 2D-array in one allocate C](https://stackoverflow.com/questions/43710298/how-can-i-dynamically-allocate-2d-array-in-one-allocate-c). – 273K Mar 19 '23 at 20:01
  • A more in-depth post: [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Lundin Mar 20 '23 at 09:04

2 Answers2

3

The problem is that actually you allocated a one-dimensional array

grid = malloc(sizeof(int) * (width * height));

So dereferencing the pointer grid like

grid[i]

you are attempting to read the uninitialized allocated memory as a value of an address that results in undefined behavior.

You need either to allocate an array of pointers to arrays that will simulate a two-dimensional array like for example

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

//...

grid = malloc(sizeof(int *) * height);

for ( int i = 0; i < height; i++ )
{
    grid[i] = malloc( sizeof( int ) * width );
}

for ( int i = 0; i < height; i++ )
{
    memset( grid[i], 0, sizeof( int ) * width );
}

Or you could allocate a one dimensional array as you already did but use only one subscript operator. In this case the pointer grid shall have the type int * and the function will be declared like

int * alloc_grid(int width, int height);

For example

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

//...

int *grid;
//...
grid = malloc( sizeof(int) * width * height );
memset( grid, 0, sizeof( int ) * height * width );

Or instead of calling the function memset you could initially initialize the arrays by zero using calloc instead of malloc as for example

grid = malloc(sizeof(int *) * height);

for ( int i = 0; i < height; i++ )
{
    grid[i] = calloc( width, sizeof( int ) );
}

or

grid = calloc( width * height, sizeof(int) );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

A pointer to pointer cannot be used to point at anything but the first item in an array of pointers. It cannot be used to point at 2D arrays.

Also note that if you only intend to set everything to zero after calling malloc, you may as well use calloc, which is guaranteed to do just that.

The quick solution would look like:

void* alloc_grid (int width, int height)
{
    if (width < 1 || height < 1)
      return NULL;
    grid_t* g = calloc( 1, sizeof(int[width][height]) );
    return g;
}

Usage:

int (*grid)[height] = alloc_grid(width, height);
if(grid == NULL)
/* handle error */
...
grid[i][j] = something;
...
free(grid);

The only downside is that the void* drops all type safety. More intricate solutions involve wrapping the array inside a struct.

Lundin
  • 195,001
  • 40
  • 254
  • 396