2

我无法理解这两个代码片段之间的区别是什么:

// 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) >= 2^32),因此使用 uint64_t 而不是 int32_t 解决了问题。我仍然不清楚的是为什么上面的第一个案例会运行,而另一个是段错误。

4

3 回答 3

4

N * D是 3e9; 这不适合 32 位int

于 2013-08-21T20:31:11.690 回答
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]

出于这个原因,可能是(当使用符号值作为数组大小时!)您的两个示例实际上不会得到相同的结果。

于 2013-08-21T20:57:40.177 回答
-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不够大,它们都会以未定义的方式运行(并且可能会崩溃)。

于 2013-08-21T20:37:13.107 回答