C Programming: malloc() for a 2D array (using pointer-to-pointer)

前端 未结 4 1180
抹茶落季
抹茶落季 2020-12-09 23:02

yesterday I had posted a question: How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?

From the ans

相关标签:
4条回答
  • 2020-12-09 23:37

    It also looks like, You are using uninitialized rows and cols variables

    0 讨论(0)
  • 2020-12-09 23:39

    In your alloc_2D_pixels function, you need another level of indirection when accessing memory. As it is now, you only modify the parameter, not the pointer pointed to by the parameter. For example,

    memory = malloc(rows * sizeof(unsigned char** ));
    // becomes
    *memory = malloc(rows * sizeof(unsigned char** ));
    
    // and later...
    memory[i] = malloc(cols * sizeof(unsigned char));
    // becomes
    (*memory)[i] = malloc(cols * sizeof(unsigned char));
    

    (basically, anywhere you are using memory, you need to use (*memory); the parentheses are only needed when you are using subscripts to ensure that the operators are applied in the correct order)

    0 讨论(0)
  • 2020-12-09 23:48

    One mistake is posting code that won't compile :). Below is corrected code with my comments in
    /* this style */:

    /* Next four lines get your code to compile */
    #include <stdio.h>
    #include <stdlib.h>
    #define NO_ERROR 0
    #define ERROR    1
    
    /* prototypes for functions used by main but declared after main
       (or move main to the end of the file */
    signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols);
    void free_2D_pixels(unsigned char** ptr, unsigned int rows);
    
    /* main should return int */
    int main()
    {
        unsigned char** ptr;
        /* need to define rows and cols with an actual value */
        unsigned int rows = 5, cols = 5;
    
        if(alloc_2D_pixels(&ptr, rows, cols) == ERROR)    // Satisfies this condition
            printf("Memory for the 2D array not allocated"); // ERROR is returned
    
        if(ptr == NULL)                    // ptr is NULL so no memory was allocated
            printf("Yes its NULL!");
        else
        {
            /* Added else clause so below code only runs if allocation worked. */
            /* Added code to write to every element as a test. */
            unsigned int row,col;
            for(row = 0; row < rows; row++)
                for(col = 0; col < cols; col++)
                    ptr[0][0] = (unsigned char)(row + col);
    
               /* no need for &ptr here, not returning anything so no need to pass
                  by reference */
               free_2D_pixels(ptr, rows);
        }
    
        return 0;
    }
    
    signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols)
    {
        signed char status = NO_ERROR;
    
        /* In case we fail the returned memory ptr will be initialized */
        *memory = NULL;
    
        /* defining a temp ptr, otherwise would have to use (*memory) everywhere
           ptr is used (yuck) */
        unsigned char** ptr;
    
        /* Each row should only contain an unsigned char*, not an unsigned
           char**, because each row will be an array of unsigned char */
        ptr = malloc(rows * sizeof(unsigned char*));
    
        if(ptr == NULL)
        {
            status = ERROR;
            printf("ERROR: Memory allocation failed!");
        }
        else
        {
            /* rows/cols are unsigned, so this should be too */
            unsigned int i;
    
            /* had an error here.  alloced rows above so iterate through rows
               not cols here */
            for(i = 0; i < rows; i++)
            {
                ptr[i] = malloc(cols * sizeof(unsigned char));
    
                if(ptr[i] == NULL)
                {
                    status = ERROR;
                    printf("ERROR: Memory allocation failed!");
                    /* still a problem here, if exiting with error,
                       should free any column mallocs that were
                       successful. */
                }
            }
        }
    
        /* it worked so return ptr */
        *memory = ptr;
        return status;
    }
    
    
    /* no need for *** here. Not modifying and returning ptr */
    /* it also was a bug...would've needed (*ptr) everywhere below */
    void free_2D_pixels(unsigned char** ptr, unsigned int rows)
    {
        /* should be unsigned like rows */
        unsigned int i;
    
        for(i = 0; i < rows; i++)
        {
            free(ptr[i]);
        }
    
        free(ptr);
    }
    
    0 讨论(0)
  • 2020-12-09 23:49

    Using multidimensional arrays in this way in C is "suboptimal" for performance.

    In no unclear words: Please do not use - and definitely not initialize - multidimensional arrays in the way you've illustrated. Multiple calls to malloc() will create you a batch of disjoint memory locations that doesn't map well to how actual graphics (as contiguous, single buffers) are stored anywhere. Also, if you have to do it hundreds or thousands of times, malloc() can be hideously expensive.

    Also, due to the fact that you're using malloc() very often, it's also a nightmare (and bug to bite you eventually) for cleaning up. You've even mentioned that in the comments in your code, and yet ... why ?

    If you absolutely must have this ptr[rows][cols] thing, create it better like this:

    signed char alloc_2D_pixels(unsigned char*** memory,
                                unsigned int rows,
                                unsigned int cols)
    {
        int colspan = cols * sizeof(char);
        int rowspan = rows * sizeof(char*);
        unsigned char **rowptrs = *memory = malloc(rowspan + rows * colspan));
    
        /* malloc failure handling left to the reader */
    
        unsigned char *payload = ((unsigned char *)rowptrs) + rowspan;
        int i;
        for (i = 0; i < rows; payload += colspan, i++)
            rowptrs[i] = payload;
    }
    

    that way you're allocating only a single block of memory and the whole thing can be freed in one go - ditch free_2D_pixels().

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