好吧,我一直认为如果我调用malloc函数,我会分配特定数量的内存,但是,我刚刚意识到如果我写的话:
int* a = (int*)malloc(sizeof(int) * 2);
我可以为a[4]
或任何其他索引分配值,但在这种情况下,我只能分配给a[0]
或a[1]
。我有什么概念错误?
答案 0 :(得分:2)
撰写a[4]
时,与撰写*(a + 4)
相同。由于编译器不知道a
指向的地址分配了多少内存,因此很高兴让您解决内存问题。
然而,位于那里的内存可能是任何东西 - 它可能是程序使用的另一个变量,堆栈的一部分,或者只是程序的范围之外。以这种方式访问分配的空间之外可能(最多)产生分段错误或(最坏的情况)通过覆盖程序的其他部分来引入安全漏洞。
你是正确的,因为你只能安全地分配给a[0]
或a[1]
,但C编译器会让你在那个边界之外分配(因为它没有知道任何不同的)。
在您的示例中执行a[4]
是不安全的。
答案 1 :(得分:2)
在C中, 没有办法检查阵列溢出。您可以继续在数组之外写入,直到您编写无效地址或只读页面等为止。
有一些工具可以让你立即检测,就像你越过数组边界一样。 NJAMD就是这样一种工具,它使得超出数组边界的直接内存位置成为只读。
当您访问只读内存时,它会给出SIGSEGV。这样你就可以立即检测到数组溢出。
答案 2 :(得分:1)
概念错误是相信C会保护你! C相信你知道你在做什么。你只能真正使用索引0或1,但它不会阻止你使用4(嗯,操作系统可能)。
答案 3 :(得分:1)
你可以做a[4]
的原因是C不进行任何边界检查。您可以访问超出数组边界的单元格,C将执行此操作。
问题是这是非常糟糕的做法,可能是一个安全漏洞。你不应该这样做,因为它可能导致非常糟糕和不可预见的后果。
答案 4 :(得分:1)
未定义的行为就是 - 未定义。它可能看起来像“正在工作”,但事实并非如此。
答案 5 :(得分:1)
扩展Keith的答案:你可以覆盖堆上的内存,因为C没有编译时或运行时绑定检查。 a [x]基本上将x * sizeof(x)
添加到指针“a”。指针指向malloced块的开头。