我无法理解这两个代码段之间的区别是什么:
// out is of type char* of size N*D
// N, D are of type int
for (int i=0; i!=N; i++){
if (i % 1000 == 0){
std::cout << "i=" << i << std::endl;
}
for (int j=0; j!=D; j++) {
out[i*D + j] = 5;
}
}
此代码运行正常,即使是非常大的数据集(N = 100000,D = 30000)。根据我对指针算法的理解,这应该给出相同的结果:
for (int i=0; i!=N; i++){
if (i % 1000 == 0){
std::cout << "i=" << i << std::endl;
}
char* out2 = &out[i*D];
for (int j=0; j!=D; j++) {
out2[j] = 5;
}
}
然而,后者不起作用(它冻结在索引143886 - 我认为它是段错误,但我不是100%肯定,因为我不习惯在Windows上开发)用于非常大的数据集而且我'我害怕我错过了关于指针算法如何工作的明显事实。它可能与推进char *有关吗?
编辑:我们现在已经确定问题是索引溢出(即(i * D + j)&gt; = 2 ^ 32),所以使用uint64_t而不是int32_t修复了问题。对我来说仍然不清楚的是,为什么第一个上述案例会贯穿,而另一个案件会出现这种情况。
答案 0 :(得分:4)
N * D
是3e9;这不适合32位int
。
答案 1 :(得分:1)
当使用N作为数组大小时,为什么要使用int? 数组的负值是否具有任何逻辑含义?
你的意思是“不起作用”?
只需将指针视为内存中的地址而不是“对象”。
char*
void*
int*
都是指向内存地址的指针,因此在定义或传入函数时完全相同。
char * a;
int* b = (char*)a;
void* c = (void*)b;
a == b == c;
不同之处在于,当访问a,a [i]时,检索到的值是来自地址a的下一个sizeof(* a)字节。
当使用++推进指针时,指针所设置的地址由
提前sizeof(pointer_type) bytes.
示例:
char* a = 1;
a++;
a现在是2。
((int*)a)++;
a现在是6。
另一件事:
char* a = 10;
char* b = a + 10;
&(a[10]) == b
因为最终
a[10] == *((char*)(a + 10))
因此,示例中的数组大小应该没有问题,因为这两个示例是相同的。
修改
现在请注意,没有负内存地址,因此访问带有有符号负值的数组会将值转换为正数。
int a = -5;
char* data;
data[a] == data[MAX_INT - 5]
由于这个原因,可能是(当使用符号值作为数组大小!)时,你的两个例子实际上不会得到相同的结果。
答案 2 :(得分:-1)
版本1
for (int i=0; i!=N; i++) // i starts at 0 and increments until N. Note: If you ever skip N, it will loop forever. You should do < N or <= N instead
{
if (i % 1000 == 0) // if i is a multiple of 1000
{
std::cout << "i=" << i << std::endl; // print i
}
for (int j=0; j!=D; j++) // same as with i, only j is going to D (same problem, should be < or <=)
{
out[i*D + j] = 5; // this is a way of faking a 2D array by making a large 1D array and doing the math yourself to offset the placement
}
}
版本2
for (int i=0; i!=N; i++) // same as before
{
if (i % 1000 == 0) // same as before
{
std::cout << "i=" << i << std::endl; // same as before
}
char* out2 = &out[i*D]; // store the location of out[i*D]
for (int j=0; j!=D; j++)
{
out2[j] = 5; // set out[i*D+j] = 5;
}
}
他们正在做同样的事情,但是如果out
不够大,他们都会以未定义的方式行事(并且可能会崩溃)。