设置数组元素时出现MSVC访问冲突

Qno*_*ish -1 c c++ memory-management

我一直在努力寻找对以下代码中出现的错误的解释:

#include <stdlib.h>

int main() {
    int m=65536;
    int n=65536;
    float *a;

    a = (float *)malloc(m*n*sizeof(float));

    for (int i = 0; i < m; i++){
       for (int j = 0; j < n; j++){
            a[i*n + j] =  0;  
        }    
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么执行此程序时出现"访问冲突"错误?

内存分配是成功的,问题是在一些迭代计数的嵌套for循环中.我尝试使用较小的m&n值并且程序正常运行.

这是否意味着我内存不足?

Adr*_*thy 7

问题是m*n*sizeof(float)可能是溢出,导致相对较小的值.因此malloc工作,但它没有像你期望的那样分配那么多的内存,所以你运行缓冲区的末尾.

具体来说,如果你的ints是32位宽(这是常见的),那么65336 * 65336已经是溢出,因为你需要至少33位来表示它.C++中的有符号整数溢出(我相信C)会导致未定义的行为,但是一个常见的结果是最重要的位被删除,而你留下较低的位.在你的情况下,它给出0.然后乘以sizeof(float),但零次,任何东西仍为零.

所以你试图分配0个字节.事实证明malloc会让你这样做,它会返回一个有效的指针,而不是一个空指针(如果分配失败,你会得到它).(见下面的编辑.)

所以你有一个有效的指针,但取消引用它是无效的.您完全取消引用它的这一事实是实现的副作用:为了生成一个不会被重用的唯一地址,这就是当您要求0字节时要求malloc执行的操作,malloc可能分配了一个小但非零的字节数.当您尝试引用远远超出这些范围时,通常会遇到访问冲突.

编辑:

事实证明,malloc在请求0字节时所执行的操作可能取决于您使用的是C还是C++.在过去,C标准需要一个0字节的malloc来返回一个唯一的指针作为生成"特殊"指针值的方法.在现代C++中,未定义0字节的malloc(参见C++ 11标准的3.7.4.1节中的脚注35).当我最初写答案时,我还没有意识到malloc的API已经以这种方式改变了.(我喜欢它,当一个新手问题让我学习新的东西.)VC++ 2013似乎保留了较旧的行为(返回一个唯一的指针,分配0字节),即使在编译C++时也是如此.