使用单个char指针迭代2D数组

时间:2016-02-01 05:04:33

标签: c arrays pointers

在对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;

很抱歉,如果我的问题的答案显而易见。 :(

3 个答案:

答案 0 :(得分:3)

使用char*int*之间的区别是严格的别名规则:如果您访问(&a[0][0])[6](即通过int*),编译器可以自由地假设访问[6]不会将数组保留在a[0]。因此,可以假设(&a[0][0]) + 6a[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的数组的第一个元素的指针相同   对象的类型作为其元素类型。

所以这是合理的。