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

pointer arithmetic in C++ using char*

本文关键字:指针 运算 char C++      更新时间:2023-10-16

我很难理解这两个代码片段之间的区别:

// 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处冻结-我认为它是segfault,但我不能100%确定,因为我不习惯在windows上开发),我担心我错过了指针算术如何工作的一些明显内容。这可能与推进char*有关吗?

EDIT:我们现在已经确定问题是索引溢出(即(i*D+j)>=2^32),因此使用uint64_t而不是int32_t解决了问题。我仍然不清楚的是,为什么上面的第一个案例会贯穿始终,而另一个则会出现故障。

N * D为3e9;其不适合于32位CCD_ 2。

当使用N作为数组大小时,为什么要使用int?数组的负值有逻辑意义吗?

你说"不起作用"是什么意思?

只需将指针看作内存中的地址,而不是"对象"。

char* 
void*
int*

都是指向内存地址的指针,因此在定义或传递到函数中时完全相同。

char * a;
int* b = (char*)a;
void* c = (void*)b;

a==b===c;

不同之处在于,当访问a,a[i]时,检索到的值是地址a的下一个(*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]

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

版本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不够大,它们都将以未定义的方式运行(并且可能崩溃)。