提问人:MRn0b0dy 提问时间:11/14/2023 最后编辑:ChrisMRn0b0dy 更新时间:11/14/2023 访问量:94
写出边界矩阵
Writing out of boundary matrix
问:
考试中的练习需要在纸上写下执行以下程序后记忆获得的值。问题是在这个程序中,当 for 循环到达元素 3 时,我们正在访问未分配的内存。写入未分配内存的值是实际存储的还是未定义的行为,因此不写入它是正确的,因为我们不知道实际发生了什么。按照程序:
#include <stdio.h>
int main()
{
int k[5][7] = {0};
int *p, *z;
p = k[1];
*p = 12;
for (int i = 0; i < 4; i++){
z = p + 8;
*z = *p + 2;
p = z;
}
return 0;
}
运行程序时,我遇到了分段错误,但在考试更正中,教授仍然分配了未分配内存区域中写入的值。那么,将我们正在写入未分配内存的值写在纸上是否正确?
答:
那么,将我们正在写入未分配内存的值写在纸上是否正确?
C 语言规范没有为该问题的任何特定答案提供任何理由,因为程序执行了多个未定义的行为。
但这并没有直接关系,因为是你的教授决定他们会接受什么答案。他们可能会接受一个答案,解释为什么行为是未定义的,而不是给出请求的内存布局,但他们更有可能希望你假设一些特定的行为并基于此做出答案。
我不太在意这样的问题,但如果我面对它,那么我可能会做上述所有事情:解释所涉及的未定义的行为,然后描述一个特定的、合理的行为选择,作为对记忆结果内容的答案的答案,然后给出该行为所暗示的答案。这涵盖了所有基础。
指针算术的规则(包括 的使用)在加法运算符的 C 标准章节 (C17 6.5.6 §8) 中指定。最重要的部分:[]
如果指针操作数和结果都指向 对同一数组对象的元素,或超过数组对象的最后一个元素的元素,计算 不得产生溢流;否则,行为是未定义的。如果结果指向过去 数组对象的最后一个元素,它不应用作一元 * 运算符的操作数,即 评价。
p
指向数组 。对于上述规则,多维数组无关紧要。k[1]
k
p
只允许在此数组的范围内进行指针算术。k[1]
- 作为特殊规则,允许在数组末尾的 1 项正好执行指针算术。所以会很明确。
p
p + 7
- 但这是未定义的行为。
p + 8
基本上,多维数组可以保证在内存中相邻分配。在内部数组 的末尾之后有一个有效的分配位置。但是,我们可能无法使用基于指向 的指针的指针算术来计算该“过了末尾”项的地址。指针算术本身可能会导致生成不正确的代码,因为编译器可以自由地假设对 through / 的任何访问都不会更改数组中的项。int
k[1]
k[1]
k[1]
p
z
k[2]
例如,我们可以将以下代码添加到循环的末尾:
if(k[2][1]==0)
puts("zero");
理论上,编译器可以自由地将其替换为非条件,因为代码中的任何内容都不允许更改此数组项。puts("zero")
因此,考试问题的正确答案是:这是未定义的行为,任何事情都可能发生。
评论
int (*k)[7] = malloc(sizeof(int[5][7]); ... z = p + 8;
k[1]
int
int (*k)[7] = malloc(sizeof(int[5][7]); int*p = (int*)k; p+=8;