dynamic allocating array of arrays in C

后端 未结 7 797
南笙
南笙 2020-11-30 04:08

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 decla

相关标签:
7条回答
  • 2020-11-30 04:43

    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;
    }
    
    0 讨论(0)
  • 2020-11-30 04:47

    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;
    
    0 讨论(0)
  • 2020-11-30 05:04

    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.

    0 讨论(0)
  • 2020-11-30 05:05

    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
    0 讨论(0)
  • 2020-11-30 05:05

    Although I agree with the other answers, it is in most cases better to allocate the whole array at once, because malloc is pretty slow.

    
    int **
    array_new(size_t rows, size_t cols)
    {
        int **array2d, **end, **cur;
        int *array;
    
        cur = array2d = malloc(rows * sizeof(int *));
        if (!array2d)
            return NULL;
    
        array = malloc(rows * cols * sizeof(int));
        if (!array)
        {
            free(array2d);
            return NULL;
        }
    
        end = array2d + rows;
        while (cur != end)
        {
            *cur = array;
            array += cols;
            cur++;
        }
    
        return array2d;
    }
    

    To free the array simply do: free(*array); free(array);

    Note: this solution only works if you don't want to change the order of the rows, because you could then lose the address of the first element, which you need to free the array later.

    0 讨论(0)
  • 2020-11-30 05:06

    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.

    0 讨论(0)
提交回复
热议问题