简体   繁体   English

C编程:用于2D数组的malloc()(使用指针到指针)

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

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 answers I got, I was able to understand what mistake I was doing. 从我得到的答案中,我能够理解我在做什么错误。

I'm facing a new problem now, can anyone help out with this? 我现在面临一个新问题,任何人都可以帮忙解决这个问题吗?

I want to dynamically allocate a 2D array, so I'm passing a Pointer-to-Pointer from my main() to another function called alloc_2D_pixels(...) , where I use malloc(...) and for(...) loop to allocate memory for the 2D array. 我想动态分配一个2D数组,所以我将指针从我的main()传递给另一个名为alloc_2D_pixels(...)函数,在那里我使用malloc(...)for(...)循环为2D数组分配内存。

Well, after returning from the alloc_2D_pixels(...) function, the pointer-to-pointer still remains NULL, so naturally, when I try accessing or try to free(...) the Pointer-to-Pointer, the program hangs. 好吧,从alloc_2D_pixels(...)函数返回后,指针指针仍然保持为NULL,所以很自然地,当我尝试访问或尝试free(...)指针到指针时,程序挂起。

Can anyone suggest me what mistakes I'm doing here? 谁能告诉我我在这里犯的错误?

Help!!! 救命!!!

Vikram 维克拉姆


SOURCE: 资源:

main()
{


 unsigned char **ptr;
 unsigned int rows, cols;

 if(alloc_2D_pixels(&ptr, rows, cols)==ERROR)      // Satisfies this condition
  printf("Memory for the 2D array not allocated"); // NO ERROR is returned

 if(ptr == NULL)                    // ptr is NULL so no memory was allocated
  printf("Yes its NULL!");          

 // Because ptr is NULL, with any of these 3 statements below the program HANGS
 ptr[0][0] = 10;                    
 printf("Element: %d",ptr[0][0]);

 free_2D_alloc(&ptr);

}


signed char alloc_2D_pixels(unsigned char ***memory, unsigned int rows, unsigned int cols)
{
        signed char status = NO_ERROR;

        memory = malloc(rows * sizeof(unsigned char** ));

        if(memory == NULL)
        {
            status = ERROR;
            printf("ERROR: Memory allocation failed!");

        }
        else
        {
            int i;

            for(i = 0; i< cols; i++)
            {
                memory[i] = malloc(cols * sizeof(unsigned char));

                if(memory[i]==NULL)
                {
                    status = ERROR;
                    printf("ERROR: Memory allocation failed!");
                }
            }

        }

    // Inserted  the statements below for debug purpose only
        memory[0][0] = (unsigned char)10;     // I'm able to access the array from
        printf("\nElement %d",memory[0][0]);  // here with no problems


        return status;
}


void free_2D_pixels(unsigned char ***ptr, unsigned int rows)
{
     int i;

     for(i = 0; i < rows; i++)
     {
          free(ptr[i]);
     }

     free(ptr);
}

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);
}

In your alloc_2D_pixels function, you need another level of indirection when accessing memory . alloc_2D_pixels函数中,访问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) (基本上,在你使用memory任何地方,你需要使用(*memory) ;只有当你使用下标来确保运算符以正确的顺序应用时才需要括号)

它看起来像,你正在使用未初始化的rowscols变量

Using multidimensional arrays in this way in C is "suboptimal" for performance. 在C中以这种方式使用多维数组对于性能来说是“次优的”。

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. malloc()多次调用将创建一批不相交的内存位置,这些位置无法很好地映射到实际图形(连续的单个缓冲区)如何存储在任何位置。 Also, if you have to do it hundreds or thousands of times, malloc() can be hideously expensive. 此外,如果你必须做成百次或数千次, malloc()可能非常昂贵。

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. 此外,由于您经常使用malloc(),因此清理也是一场噩梦(以及最终咬你的错误)。 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: 如果你绝对必须有这个ptr[rows][cols]东西,那就更好地创建它:

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() . 这样你就只分配了一块内存,整个东西都可以在一个go - ditch free_2D_pixels()释放出来。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM