使用char *在C ++中使用指针运算

时间:2013-08-21 20:15:36

标签: c++ pointers pointer-arithmetic

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

// 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修复了问题。对我来说仍然不清楚的是,为什么第一个上述案例会贯穿,而另一个案件会出现这种情况。

3 个答案:

答案 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不够大,他们都会以未定义的方式行事(并且可能会崩溃)。