C malloc 有效,但不应该

C malloc works, but it should not

提问人:Daniel 提问时间:11/5/2023 最后编辑:Daniel 更新时间:11/5/2023 访问量:128

问:

对于我的线性代数代码,我需要为较低的三角矩阵分配内存, 由一维数组表示。我正在试验我可以分配多少元素和 偶然发现了一个奇怪的行为。如果我设置为高于 的任何内容,则失败并且我的机器无法分配足够的内存,但将其设置为 不会失败,并且 我的代码稍后在循环中崩溃,在大约迭代后初始化数组(超出 边界索引被排除在外,因为可能的错误源)。有人知道这里发生了什么吗?double bottom_row_final240.0malloc410.0mallocfor30

//array.c
#include <stdio.h>
#include <stdlib.h>

void vector_alloc(int N, double **pM) {
    if ((*pM = (double *)malloc(N * sizeof(double))) == NULL) {
        printf("Error: malloc failed!\n");
        exit(0);
    }
}

void vector_free(double **pM) {
    free(*pM);
    *pM = NULL;
}

int main(void) {
    //-----------------------------------------------------------------------------------------------------------------------
    double grid_step = 0.0125;
    double bottom_row_final = 410.0;     //  230 works, 240 and above does not allocate anymore, but 410 does 

    int bottom_row_elements = (int)(bottom_row_final / grid_step) + 1;
    int lower_triangular_matrix_elements = bottom_row_elements * (bottom_row_elements + 1) / 2;
    double *matrix;
    vector_alloc(lower_triangular_matrix_elements, &matrix);
    int index_jumper = 0;
    //-----------------------------------------------------------------------------------------------------------------------  
    for (int i = 0; i <= bottom_row_elements; i++) {      
        if (i < bottom_row_elements) {
            printf("\n%d\t%d", index_jumper, lower_triangular_matrix_elements - 1);
            matrix[index_jumper] = 1.0;
            printf("\tInitialized with value");
            index_jumper += (bottom_row_elements - i);
        }
    }
    //-----------------------------------------------------------------------------------------------------------------------  
    vector_free(&matrix);
}

我尝试调试代码,但出现分段错误(显然),但不应该 甚至能够为上述分配内存。mallocdouble bottom_row_final240.0

阵列 C 分段-故障 malloc

评论

0赞 William Pursell 11/5/2023
与您的问题无关,但坏习惯应及早改掉。如果程序失败,它应该返回非零。错误消息属于 stderr。例如(或者,甚至更好,if( (*pm = ...) == NULL ) { perror("malloc"); exit(1); }exit(EXIT_FAILURE);)

答:

-1赞 Ken 11/5/2023 #1

我尝试复制您的问题,但我不能。你确定malloc()真的有效吗?您是否收到错误消息,在没有调试的情况下运行它?

评论

0赞 Daniel 11/5/2023
对不起,没有指定,如果 malloc 失败并退出,我的数组分配函数会打印错误。在这种情况下,将双bottom_row_final设置为 410.0,我的代码继续运行,稍后在 for 循环中崩溃。
1赞 Eric Postpischil 11/5/2023
这不是问题的答案。当您有足够的声誉时,您将能够对问题发表评论。您应该避免发表评论或问题作为答案。
3赞 chqrlie 11/5/2023 #2

问题就在这里:

int lower_triangular_matrix_elements = bottom_row_elements * (bottom_row_elements + 1) / 2;

当大于 时,乘法会导致有符号的算术溢出,该溢出具有未定义的行为。根据实际值,结果可能是负数或正数,导致请求因请求太大而失败,或者导致成功但内存量低于所需内存量,从而在访问超出分配大小末尾时导致进一步的未定义行为。bottom_row_elements46340malloc()

您应该使用 for the computations,而不是 .size_tint

//array.c
#include <stdio.h>
#include <stdlib.h>

void vector_alloc(size_t N, double **pM) {
    // Allocate the array, initialized to 0.0, assuming IEEE 754 doubles
    if ((*pM = (double *)calloc(N, sizeof(double))) == NULL) {
        printf("Fehler: malloc fehlgeschlagen!\n");
        exit(0);
    }
}

void vector_free(double **pM) {
    free(*pM);
    *pM = NULL;
}

int main(void) {
    //-----------------------------------------------------------------------------------------------------------------------
    double grid_step = 0.0125;
    double bottom_row_final = 410.0;

    size_t bottom_row_elements = (size_t)(bottom_row_final / grid_step) + 1;
    size_t lower_triangular_matrix_elements = bottom_row_elements * (bottom_row_elements + 1) / 2;
    double *matrix = NULL;
    vector_alloc(lower_triangular_matrix_elements, &matrix);
    size_t index_jumper = 0;
    //-----------------------------------------------------------------------------------------------------------------------  
    for (size_t i = 0; i < bottom_row_elements; i++) {      
        printf("\n%zu\t%zu",
               index_jumper, lower_triangular_matrix_elements - 1);
        matrix[index_jumper] = 1.0;
        printf("\tInitialized with value");
        index_jumper += bottom_row_elements - i;
    }
    //-----------------------------------------------------------------------------------------------------------------------  
    vector_free(&matrix);
}

评论

0赞 Daniel 11/5/2023
嗨,感谢您的编辑,使我的问题更加简洁,当然还有答案。我尝试使用 size_t,但 malloc 仍然设法分配内存,即使它不应该。也许我应该提一下,我在 Windows 上并使用 MinGW 的 gcc 端口。
0赞 chqrlie 11/5/2023
尝试上面修改后的版本:比 Windows 64 位大得多,并且必须用于所有大小和索引变量。您应该能够分配 537,936,400 个双精度的数组,即 4.3GB,除非您的系统阻止如此大的块。size_tint
0赞 Daniel 11/5/2023
您好,谢谢。我尝试使用 size_t但 malloc 仍然分配,即使它不应该。从 malloc 切换到 calloc 使其不再分配,这很好,但是为什么 malloc 仍然分配这个特定数字,当限制远远超过限制时?
0赞 chqrlie 11/5/2023
@Daniel:并且应该表现得一样。你确定这些论点吗?我曾经免费获得零初始化。根据操作系统的不同,数组可能会被分配为具有许多共享页面的稀疏数组。4.3 GB 不一定是这么大的数字,我的笔记本电脑有 24 GB,我可以毫不费力地分配 4.3 GB。callocmalloccalloc()
0赞 Daniel 11/5/2023
嗨,我同意,它们的行为应该相同,并且它们对 240.0 以上的每个数字bottom_row_final都是这样做的。但是对于 410.0 calloc 失败,并且 malloc 通过,即使我使用的是 size_t。我的系统只有 8 GB,我需要关闭所有程序,以便我的代码可以分配 4.3GB。这真的很神秘。