HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Allocating a contiguous block of memory for an array

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
arrayblockformemorycontiguousallocating

Problem

I try to work with a contiguous block of memory, to create an array (2D) whose SIZE is not known at compile time (before c99) so no variable-length arrays are involved here.

I came up with the following:

#include 
#include 

int main(void){
    unsigned int row, col,i, j, k;
    int l = 0;
    int *arr;

    printf("Give the ROW: ");
    if ( scanf("%u",&row) != 1){
        printf("Error, scanf ROW\n");
        exit(1);
    }

    printf("Give the COL: ");
    if ( scanf("%u",&col) != 1){
        printf("Error, scanf COL\n");
        exit(2);
    }

    arr = malloc(sizeof *arr * row * col);
    if(arr == NULL){
        printf("Error, malloc\n");
        exit(3);
    }

    for ( i = 0; i < row ; i++){
        for ( j = 0 ; j < col ; j++){
            arr[i * col + j] = l;
            l++;
        }
    }

    for (k = 0 ; k < (row * col) ; k++){
        printf("%d ",arr[k]);
    }

    free(arr);
}


Which gives me the following:

Give the ROW: 6
Give the COL: 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17


Is this the right approach?

Solution

Of course this in not a true 2d array, just a 1d array indexed using arr[i * col + j].

This is an OK approach. When able, I prefer an array of pointers to an array of ints, as it is usually more flexible to the tasks I tackle. YMMV.

-
Modest extreme case: sizeof arr row col is multiplied in the right order. When row or col is int/unsigned, good to use sizeof arr first as that is type size_t and the subsequent multiplication will then happen at least using size_t math. The concern being that with unsigned row, col, row*col calculated first could overflow using unsigned math, but not size_t math.

Pedantically, even sizeof arr row * col can overflow. Should code need to detect this, the reasonable approach is to use the widest unsigned types like unsigned long long or uintmax_t. (Other more pedantic methods exist.)

assert(1LLU * sizeof *arr * row * col < SIZE_MAX);


-
Suggest using size_t for row, col, i, j instead of any other type. size_t is the Goldilocks type for array indexes - not too narrow, not too wide.

-
Error messages are better sent to stderr. 2 advantages: will not get lost in code's typical stdout output and the stderr stream is flushed ensuring output is not mixed after later input.

-
Idea: Using a arr = 0; after the free(arr); has merit when the free'd variable is still in scope for a long time. Although not needed, a decent compiler will optimized it out, but errant subsequent use is easier to detect when arr == NULL than arr = some_freed_value.

-
Minor: printf("%d ",arr[k]); in a loop is sometimes a problem when trying to print more than some environmental limit number (e.g. 4095) of characters on the same line. Liberal use of fflush(stdout); or including a '\n' in the text usually solves this.

-
A key comment missing is: is this array row or column major? With some analysis, that is discernible, but from a header only interface, knowing which dimension moves in the smallest steps is important in how higher level code will want to use this array for cache hit efficiency.

-
Coding style: No need to introduce a variable until ready for assignment. Consider the 2nd style.

// int *arr;
// ... many lines
// arr = malloc(sizeof *arr * row * col);

... many lines
int *arr = malloc(sizeof *arr * row * col);

Code Snippets

assert(1LLU * sizeof *arr * row * col < SIZE_MAX);
// int *arr;
// ... many lines
// arr = malloc(sizeof *arr * row * col);

... many lines
int *arr = malloc(sizeof *arr * row * col);

Context

StackExchange Code Review Q#129207, answer score: 3

Revisions (0)

No revisions yet.