在对C中的多维数组进行一些研究以及它们如何存储在内存中时,我遇到了这样的问题:" Does C99 guarantee that arrays are contiguous?"。最高投票的答案表明"还必须能够用(char *),#34;迭代整个数组。然后提供以下"有效"代码:
int a[5][5], i, *pi;
char *pc;
pc = (char *)(&a[0][0]);
for (i = 0; i < 25; i++)
{
pi = (int *)pc;
DoSomething(pi);
pc += sizeof(int);
}
然后海报继续说&#34;对(int *)执行相同操作将是未定义的行为,因为如上所述,没有涉及int的数组[25]。&#34;
那条线让我困惑。
为什么使用char指针构成有效/已定义的行为,而用整数指针替换它不会?&#t;
很抱歉,如果我的问题的答案显而易见。 :(
答案 0 :(得分:3)
使用char*
和int*
之间的区别是严格的别名规则:如果您访问(&a[0][0])[6]
(即通过int*
),编译器可以自由地假设访问[6]
不会将数组保留在a[0]
。因此,可以假设(&a[0][0]) + 6
和a[1] + 1
指向不同的内存位置,即使它们没有,也会相应地重新排序。
char*
是一个区别,因为它明确地免受严格别名规则的限制:您可以将任何内容转换为char*
并通过此指针操作其位而不调用未定义的行为。
答案 1 :(得分:1)
标准非常明确,如果你有:
int a[5];
int* p = &a[0];
然后
p += 6;
导致未定义的行为。
我们也知道为2D阵列分配的内存,例如
int a[5][5];
必须是连续的。鉴于此,如果我们使用:
int* p1 = &a[0][0];
int* p2 = &a[1][0];
p1+5
是一个法律表达式,给定a
的布局,它等于p2
。因此,如果我们使用:
int* p3 = p1 + 6;
为什么不等同于
int* p3 = p2 + 1;
如果p2 + 1
是合法表达,为什么p1 + 6
不能成为合法表达?
从纯粹迂腐的标准解释来看,使用p1 + 6
导致未定义的行为。但是,当涉及到2D阵列时,标准可能无法充分解决问题。
总结
从所有实际角度来看,使用p1 + 6
都没有问题
从纯粹迂腐的角度来看,使用p1 + 6
是未定义的行为。
答案 2 :(得分:0)
int指针或char指针应该可以工作,但在这两种情况下操作应该略有不同。假设sizeof(int)
为4. pc += sizeof(int)
将指针向前移动4个字节,但pi += sizeof(int)
将向前移动4个字节4次。如果要使用int指针,则应使用pi ++
。
编辑:对不起上面的答案,使用int指针不符合C99(虽然它通常实际上有效)。原因问题很好地解释了原因:指针遍历数组在标准中没有很好地定义。如果使用int指针,则应从a[0]
开始,这是与a[1]
不同的数组。在这种情况下,a[0]
int指针不能合法地(明确定义)指向a[1]
元素。
第二次编辑:使用char
指针有效,因为原始答案给出了以下原因:
当给出memset,memmove或memcpy以及sizeof时,整个数组必须正常工作。还必须能够使用(char *)迭代整个数组。
从第6.5.6节“添加运算符”
出于这些运算符的目的,指向不是元素的对象的指针 数组的行为与指向长度为1的数组的第一个元素的指针相同 对象的类型作为其元素类型。
所以这是合理的。