【问题标题】:How to make sure the following function did not over-allocate?如何确保以下功能没有过度分配?
【发布时间】:2026-01-06 18:10:02
【问题描述】:

我正在尝试创建一个获取列数和行数(宽度和高度)的函数,构建一个二维矩阵,然后将 Matrix[0][0] 的地址返回给原始调用者中的指针-函数。

int **allocateMatrix(int width, int height) // function that allocate 
//memory for 2D matrix and check that memory allocation was successful
{
    int **Matrix;
    int row;
    Matrix = (int**)malloc(sizeof(int*)*height); 
    if (!Matrix)
    {
        printf("failed to allocate memory. this program is over.\n");
        exit(1);
    }
    for (row = 0; row < height; row++)    
    {   Matrix[row] = (int*)malloc(sizeof(int)*width);     
      if (!Matrix[row])
      { 
        printf("failed to allocate memory. this program is over.\n");
        exit(1);
      }
    }
    return Matrix;
}

在分配过程中,我通过调试器观察了整个事情,它似乎创建了一个我想要的太大的矩阵,并且通常是一种意想不到的行为。 如:高=5,宽=5, 虽然 Matrix[0][30] - 存在且可达。

此外,我不确定我返回的地址。

【问题讨论】:

  • @Ofer Bar Oz,你希望Matrix[0][30] 做什么?您是否期望 C 能够发现编码错误?
  • 由于void *被自动提升,因此无需转换 malloc 的结果
  • 建议将Matrix[row] = calloc (width, sizeof *Matrix[row]) 分配为calloc 将在Matrix[row] 初始化所有元素0 中的所有字节归零,以防止在无意中访问未初始化元素时出现未定义行为

标签: c function pointers memory malloc


【解决方案1】:

您的分配没有问题。在 C 语言中,如果您超出边界并且很幸运,您会收到分段错误信号并且程序终止(如果您尚未为此信号安装特定的信号处理程序),但如果您登陆一些有效内存,您可以访问记忆和破坏某些东西的风险。

正如其他人在 cmets 中所说,C 不会捕获编码错误,但如果您使用标志 -Wall -pedantic -g 进行编译,编译器会在某些东西关闭时生成一些警告,有时它甚至会提示您如何修正错误。还可以了解如何使用valgrind

【讨论】:

    【解决方案2】:

    您的分配方案没有任何问题,但仍有许多改进之处。如果您的调试器报告可以访问 30 个元素的行 - 您查看信息的方式有问题。

    首先,malloc 的返回不需要强制转换,没有必要。请参阅:Do I cast the result of malloc?

    在分配函数中避免使用exit。调用者应该可以选择优雅地处理分配失败,而不是您的程序在此时退出。虽然exit 有效,但它严重限制了您处理故障的选择。相反,成功时返回一个有效指针,否则返回NULL,并让调用者处理错误。在分配失败的情况下,在返回 NULL 之前,由您决定 free() 之前的所有分配。

    考虑使用callocmatrix[row] 分配存储空间。 calloc 将分配的所有字节设置为零,有效地将每一行的每个元素初始化为0,防止在返回后无意访问未初始化的元素时出现未定义的行为

    将所有部分放在一起,您可以执行以下操作:

    /* allocatematrix allocates storage for a width x height matrix of type int.
     * all elements are initialized zero. on success returns a pointer to pointer
     * to type, otherwise all allocations are freed and NULL is returned.
     */
    int **allocatematrix (int width, int height)
    {
        int **matrix;
        int row;    /* declare row in for loop declaration, unless c89 support needed */
    
        matrix = malloc (height * sizeof *matrix);  /* allocate pointers */
        if (!matrix) {                  /* validate */
            perror ("malloc-matrix");   /* malloc failure set errno, use it */
            return NULL;                /* evaluate return in caller */
        }
    
        for (row = 0; row < height; row++) {    /* for each pointer */
            matrix[row] = calloc (width, sizeof *matrix[row]);  /* alloc rows */
            if (!Matrix[row]) {         /* validate */
                perror ("calloc-matrix[row]");  /* ditto for calloc */
                while (row--)           /* loop over previous rows */
                    free (matrix[row]); /* free previously allocated rows */
                free (matrix);          /* free pointers */
                return NULL;            /* evaluate return in caller */
            }
        }
    
        return matrix;  /* return initial pointer address */
    }
    

    (注意:虽然不是错误,但 C 通常避免使用 camelCaseMixedCase 变量和函数名称,而支持所有 小写 而保留 大写 名称以用于宏和常量。这是风格问题 - 所以完全取决于您)

    (另请注意:使用perror而不是printf进行错误报告。当函数设置errno失败时,应使用perror。此外,它已经提供在stderr 上输出。如果处理未设置errno 的故障,则使用fprintf(如果需要转换)或fputs,否则在stderr 上报告错误而不是stdout )

    查看一下,如果您还有其他问题,请告诉我。

    【讨论】:

      最近更新 更多