在C99中数组启动之前指向元素

时间:2015-03-29 13:03:07

标签: c arrays pointers c99

我有一个整数数组:

int* counters = (int *) calloc(N, sizeof(int));

必须使用一个基于索引的索引,例如第一个元素有索引1,第二个元素有索引2,等等。由于性能非常重要,我决定使用一个技巧:

int* oneIndexedCounters = counters - 1;

允许我使用一个基于索引而不从索引中减去1:

// A[i] - contains one based indexes
for (int i = 0; i < K; i++) {
    oneIndexedCounters[A[i]] += B[i]; // many times in code
    // some other operations on oneIndexedCounters
}

绝对:

for (int i = 0; i < K; i++) {
    counters[A[i]-1] += B[i];
    // ...
}
我的函数返回了

counters数组,因此我无法在数组开头分配虚拟元素。

当你没有取消引用那个指针时,是否在数组有效之前指向一个元素(例如当数组在内存页边界上时)? 或者是否有其他解决方案不那么棘手并且提供了良好的性能?

2 个答案:

答案 0 :(得分:4)

  

当你没有取消引用那个指针时,是否在数组有效之前指向一个元素(例如当数组在内存页边界上时)?

不,它无效。

int* oneIndexedCounters = counters - 1;

counters - 1未指向有效对象,该操作会调用未定义的行为。

  

(C99,6.5.6p8)“如果指针操作数和结果都指向元素           相同的数组对象,或者超过数组最后一个元素的数组           对象,评估不得产生溢出;否则,           行为未定义。“

答案 1 :(得分:0)

正如ouah's answer正确指出的那样,从指向数组对象的初始元素的指针中减去1具有未定义的行为 - 即使您没有取消引用它。 (我记得有些版本的&#34; C&#34中的数字食谱;使用这种技术来模拟Fortran数组语义。它可以&#34;工作&#34;如果你很幸运。 )

还有一种方法:分配比你需要的更长的数组1元素,并通过指向第二个元素(元素1)的指针访问它的元素。

例如:

int *counters = calloc(N+1, sizeof(*counters));

然后,您可以通过counters[1]安全地访问counters[N],就像您有一个基于1的数组一样。唯一的缺点是你有一个你从不使用的额外元素0。如果它是一个相对较小类型的数组,那不重要。

calloc上的题外话:

严格地说,calloc()并不保证将浮点对象初始化为0.0,或指向NULL。实际上保证将整数初始化为0;该保证在C99后技术勘误和C11中明确规定。如果您碰巧知道您的系统表示浮点0.0并将空指针表示为全位零,那么可能可以使用calloc - 但我要添加评论使假设明确。 使用0.0NULL的所有位为零的系统很少见。由您来决定100%可移植性的重要性。