Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C99中指向数组开始之前的元素_C_Arrays_Pointers_C99 - Fatal编程技术网

在C99中指向数组开始之前的元素

在C99中指向数组开始之前的元素,c,arrays,pointers,c99,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;

我有一个整数数组:

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
}
//A[i]-包含基于一的索引
for(int i=0;i
代替:

for (int i = 0; i < K; i++) {
    counters[A[i]-1] += B[i];
    // ...
}
for(int i=0;i
计数器
数组由我的函数返回,因此我无法在数组开头分配伪元素

当您不取消引用该指针时,将一个元素指向数组之前是否有效(例如,当数组位于内存页边界上时)? 或者是否有其他解决方案不那么棘手且性能良好

当您不取消引用该指针时,将一个元素指向数组之前是否有效(例如,当数组位于内存页边界上时)

不,这是无效的

int* oneIndexedCounters = counters - 1;
计数器-1
未指向有效对象,该操作调用未定义的行为

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

当您不取消引用该指针时,将一个元素指向数组之前是否有效(例如,当数组位于内存页边界上时)

不,这是无效的

int* oneIndexedCounters = counters - 1;
计数器-1
未指向有效对象,该操作调用未定义的行为

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

正如正确指出的,从指向数组对象初始元素的指针中减去1具有未定义的行为——即使您没有取消引用它。(我记得,有些版本的“C中的数字配方”使用这种技术来模拟Fortran数组语义。如果你“幸运”,它可以“工作”。)

还有一种选择:分配一个数组1元素的长度超过您需要的长度,并通过指向第二个元素(元素1)的指针访问其元素

例如:

int *counters = calloc(N+1, sizeof(*counters));
然后,您可以通过
计数器[N]
安全地访问
计数器[1]
,就像您有一个基于1的数组一样。唯一的缺点是,您有一个从未使用过的附加元素0。如果它是一个相对较小类型的数组,这应该无关紧要

关于calloc的题外话:

严格地说,
calloc()
不保证将浮点对象初始化为
0.0
,也不保证将指针指向
NULL
。实际上保证将整数初始化为
0
;这一保证在C99之后的技术勘误表和C11中明确规定。如果您碰巧知道您的系统代表浮点
0.0
>空指针作为所有零位,使用
calloc
可能没问题,但我要添加一条注释,明确假设。对于
0.0
null
不使用所有零位的系统是很少见的。100%可移植性的重要性取决于您自己。

正确地说,从指向数组对象的初始元素有未定义的行为——即使您没有取消引用它。(我记得,有些版本的“C中的数字配方”使用这种技术来模拟Fortran数组语义。如果您“幸运”,它可以“工作”。)

还有一种选择:分配一个数组1元素的长度超过您需要的长度,并通过指向第二个元素(元素1)的指针访问其元素

例如:

int *counters = calloc(N+1, sizeof(*counters));
然后,您可以通过
计数器[N]
安全地访问
计数器[1]
,就像您有一个基于1的数组一样。唯一的缺点是您有一个从未使用过的附加元素0。如果它是一个相对较小类型的数组,那就不重要了

关于calloc的题外话:


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

不幸的是,我不能这样做,因为我必须将分配的数组返回给外部代码,这些代码必须在某个时刻释放它。这段代码(我无法控制)假设它是零索引的(混乱?是的)。@csharpfolk:是的,混乱。您需要将其视为基于1的,但将分配的数组返回给的调用方需要将其视为基于0的?我认为您需要为这个问题添加更多的细节。更准确地说,数组在我的代码和外部代码中是以零为基础的(第一个元素总是在索引0处),但我使用的算法假设数组是以1为基础的,因此我必须在多个地方编写
array[somecomplexidexpr-1]
,以将以1为基础的索引转换为以0为基础的索引。我只需要一种跳过减法1部分的方法-首先我试图修改
数组
指针,但正如@ouah指出的,它会触发未定义的行为。不幸的是,我不能这样做,因为我必须返回已分配的数组