Correct way to allocate and free arrays of pointers to arrays

前端 未结 3 1249
自闭症患者
自闭症患者 2021-01-02 02:46

I want to create an array of pointers to arrays of 3 floats. What is the correct way to do this?

float *array1[SIZE]; // I think it is automatically allocate         


        
相关标签:
3条回答
  • 2021-01-02 03:33

    I want to create an array of pointers to arrays of 3 floats. What is the correct way to do this?

    Why do you want an array of pointers to arrays? Wouldn't an array of arrays be sufficient? (Keep in mind that arrays are already pointer-like, they are not passed by value, rather the address of the first element is passed when an array is passed as an argument to a function).

    // stack allocation, no need to free
    float array[SIZE][3]; 
    
    for (int i = 0; i < SIZE; i++) {
        // do something with array[i][0], array[i][1], array[i][2]
    }
    

    Then how would I free the data?

    In this case you wouldn't, since the data is stack allocated (will be cleaned up automatically once out of scope). Just remember the rule of thumb is that for every memory allocation you make, a corresponding free is necessary. So if you allocate memory for an array of floats, as in

    float* arr = malloc(sizeof(float) * 3); // array of 3 floats
    

    Then you only need to call free on the array that you malloc'd, no need to free the individual floats. If you perform nested allocation as in

    // array of length SIZE, consisting of float pointers
    float** arr = malloc(sizeof(float*) * SIZE);
    
    // allocate the array of 3 floats at each index
    for (int i = 0; i < SIZE; i++) 
        arr[i] = malloc(sizeof(float) * 3);
    

    Then you will need to perform a free for every malloc, as in

    // free the individual arrays
    for (int i = 0; i < SIZE; i++)
        free(arr[i]);
    // free the array of arrays
    free(arr);
    

    The lesson to take away here is to avoid dynamic allocation of arrays all-together. Stick with either std::vector or stack-allocated arrays.

    0 讨论(0)
  • 2021-01-02 03:37

    A general rule is that for each time you call malloc() or calloc() you will need to do a free() call on the returned pointer.

    If you want a two dimensional array with compile-time known size, just use a two dimensional array! float val[5][3] is perfectly valid.

    If you want a two dimensional array and you don't know it's size during compile-time, you most probably want to use a standard, single diemensional calloc() and an appropriate getter.

    #define ARR_COLUMNS 10
    #define ARR_ROWS 10
    float* arr = calloc (ARR_COLUMNS * ARR_ROWS, sizeof(float));
    
    int get(float* arr, int x, int y) {
      if (x<0 || x>= ARR_COLUMNS) return 0;
      if (y<0 || y>= ARR_ROWS) return 0;
      return arr[ARR_COLUMNS*y+x];
    }
    
    void set (int* arr, int x, int y, float val) {
      if (x<0 || x>= ARR_COLUMNS) return;
      if (y<0 || y>= ARR_ROWS) return;
      arr[ARR_COLUMNS*y+x] = val;
    }
    

    Of course replace the defines with appropriate variables.

    By doing so you will:

    • save yourself costly allocs and frees
    • have less fragmented memory
    • simplify your possible realloc calls
    • ensure the data is cached better and accessed without the common [x][y] vs [y][x] iteration cache problem.
    0 讨论(0)
  • 2021-01-02 03:38

    If you know the array size at compile time (and you do, if SIZE is a compile-time constant), you should just declare a two-dimensional array. You don't need to free this at all (and must not).

    float array1[SIZE][3];
    

    You need to use calloc, and to create an array of pointers, only if the dimensions are not known at compile time. In this case, there should be one call to free for each call to calloc. And since you cannot use an array after you free it, you need to free the row arrays before you free array1.

    float **array1 = calloc(nrows, sizeof (float *));
    for (int i=0; i < nrows; i++)
        array1[i] = calloc(3, sizeof(float));
    // Use it...
    
    // Now free it
    for (int i=0; i < nrows; i++)
        free(array1[i]);
    free(array1);
    

    Edit: if you won't be rearranging the pointers (to sort the rows in-place, for example), you can do all of this with just one calloc (and one call to free afterwards):

    float (*array1)[3] = calloc(3*nrows, sizeof (float));
    

    That's because the number of columns is known at compile-time, and that's all the pointer arithmetic needs to know. Then you can write things like array1[i][j], and you can still pass around array1[i] as if it was a real pointer to a row. C is great that way, take advantage of it!

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