dynamic allocating array of arrays in C

2020-01-27 03:20发布

I don't truly understand some basic things in C like dynamically allocating array of arrays. I know you can do:

int **m;

in order to declare a 2 dimensional array (which subsequently would be allocated using some *alloc function). Also it can be "easily" accessed by doing *(*(m + line) + column). But how should I assign a value to an element from that array? Using gcc the following statement m[line][column] = 12; fails with a segmentation fault.

Any article/docs will be appreciated. :-)

7条回答
劳资没心,怎么记你
2楼-- · 2020-01-27 03:48

The m[line][column] = 12 syntax is ok (provided line and column are in range).

However, you didn't write the code you use to allocate it, so it's hard to get whether it is wrong or right. It should be something along the lines of

m = (int**)malloc(nlines * sizeof(int*));

for(i = 0; i < nlines; i++)
  m[i] = (int*)malloc(ncolumns * sizeof(int));

Some side-notes:

  • This way, you can allocate each line with a different length (eg. a triangular array)
  • You can realloc() or free() an individual line later while using the array
  • You must free() every line, when you free() the entire array
查看更多
叼着烟拽天下
3楼-- · 2020-01-27 03:54

Using malloc(3) for allocate the first array and putting in there pointers created by malloc(3) should work with array[r][c] because it should be equivalent to *(*(array + r) + c), it is in the C standard.

查看更多
家丑人穷心不美
4楼-- · 2020-01-27 03:57

Your syntax m[line][colummn] is correct. But in order to use a 2D array in C, you must allocate memory for it. For instance this code will allocated memory for a table of given line and column.

int** AllocateArray(int line, int column) {
  int** pArray = (int**)malloc(line*sizeof(int*));
  for ( int i = 0; i < line; i++ ) {
    pArray[i] = (int*)malloc(column*sizeof(int));
  }
  return pArray;
}

Note, I left out the error checks for malloc for brevity. A real solution should include them.

查看更多
兄弟一词,经得起流年.
5楼-- · 2020-01-27 03:58

Here's a modified version of quinmars' solution which only allocates a single block of memory and can be used with generic values by courtesy of void *:

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

void ** array2d(size_t rows, size_t cols, size_t value_size)
{
    size_t index_size = sizeof(void *) * rows;
    size_t store_size = value_size * rows * cols;

    char * a = malloc(index_size + store_size);
    if(!a) return NULL;

    memset(a + index_size, 0, store_size);
    for(size_t i = 0; i < rows; ++i)
        ((void **)a)[i] = a + index_size + i * cols * value_size;

    return (void **)a;
}

int printf(const char *, ...);

int main()
{
    int ** a = (int **)array2d(5, 5, sizeof(int));
    assert(a);
    a[4][3] = 42;
    printf("%i\n", a[4][3]);
    free(a);
    return 0;
}

I'm not sure if it's really safe to cast void ** to int ** (I think the standard allows for conversions to take place when converting to/from void * ?), but it works in gcc. To be on the safe side, you should replace every occurence of void * with int * ...


The following macros implement a type-safe version of the previous algorithm:

#define alloc_array2d(TYPE, ROWS, COLS) \
    calloc(sizeof(TYPE *) * ROWS + sizeof(TYPE) * ROWS * COLS, 1)

#define init_array2d(ARRAY, TYPE, ROWS, COLS) \
    do { for(int i = 0; i < ROWS; ++i) \
        ARRAY[i] = (TYPE *)(((char *)ARRAY) + sizeof(TYPE *) * ROWS + \
        i * COLS * sizeof(TYPE)); } while(0)

Use them like this:

int ** a = alloc_array2d(int, 5, 5);
init_array2d(a, int, 5, 5);
a[4][3] = 42;
查看更多
不美不萌又怎样
6楼-- · 2020-01-27 04:06

Humm. How about old fashion smoke and mirrors as an option?

#define ROWS  5
#define COLS 13
#define X(R, C) *(p + ((R) * ROWS) + (C))

int main(void)
{
    int *p = (int *) malloc (ROWS * COLS * sizeof(int));
    if (p != NULL)
    {
        size_t r;
        size_t c;
        for (r = 0; r < ROWS; r++)
        {
            for (c = 0; c < COLS; c++)
            {
                 X(r,c) = r * c;  /* put some silly value in that position */ 
            }
        }

        /* Then show the contents of the array */ 
        for (r = 0; r < ROWS; r++)
        {
            printf("%d ", r);   /* Show the row number */ 

            for (c = 0; c < COLS; c++)
            {
                 printf("%d", X(r,c));
            }

            printf("\n");
        }

        free(p);
    }
    else
    {
        /* issue some silly error message */ 
    }

    return 0;
}
查看更多
\"骚年 ilove
7楼-- · 2020-01-27 04:08

It's not a 2d array - it's an array of arrays - thus it needs the multiple allocations.

查看更多
登录 后发表回答