C++ 指针和数组

Posted

技术标签:

【中文标题】C++ 指针和数组【英文标题】:C++ Pointers & Arrays 【发布时间】:2010-11-27 17:17:18 【问题描述】:

以下是来自 C++ 过程的一些代码。原件可以在这里找到; https://code.ros.org/trac/opencv/browser/trunk/opencv/modules/imgproc/src/grabcut.cpp

我的观点是我是一个 C# 而不是 C++ 程序员,所以这个代码对我来说有点神秘,即使我通过一个代码转换器运行它并且它没有改变。

我的问题是:a)。 'coefs' 如何成为一个数组,以及 b)。 'c' 是如何填充的?

提供更多信息:'coefs' 开始时似乎不是一个数组,而 'c' 似乎神奇地获得了至少 8 个项目

    // fields in class called MAT:
    // a distance between successive rows in bytes; includes the gap if any 
    size_t step;
    // pointer to the data
    uchar* data;

    // where ptr comes from:
    template<typename _Tp> _Tp* ptr(int y=0);
    template<typename _Tp> inline _Tp* Mat::ptr(int y)
    
        CV_DbgAssert( (unsigned)y < (unsigned)rows );
        return (_Tp*)(data + step*y);
        
    .....

    // original question code:
    static const int componentsCount = 5;
    Mat model;
    float* coefs;
    float* mean;
    float* cov;

    coefs = model.ptr<float>(0);
    mean = coefs + componentsCount;
    cov = mean + 3*componentsCount;

    for( int ci = 0; ci < componentsCount; ci++ )
        if( coefs[ci] > 0 )
            calcInverseCovAndDeterm( ci );

    void GMM::calcInverseCovAndDeterm( int ci )
    
        if( coefs[ci] > 0 )
        
            float *c = cov + 9*ci;
            float dtrm =
                covDeterms[ci] = c[0]*(c[4]*c[8]-c[5]*c[7]) - c[1]*(c[3]*c[8]-c[5]*c[6]) + c[2]*(c[3]*c[7]-c[4]*c[6]);

【问题讨论】:

【参考方案1】:

当你像这样声明一个数组时:

int my_ints[10];

my_ints 一个数组。但在 C++ 中,my_ints 也可以作为指向数组中第一项的指针来计算。所以代码如下:

int* the_first_int = my_ints;

...是合法有效的,更不用说很常见了。您也可以像使用数组一样使用the_first_int,如下所示:

int the_third_int = the_first_int[2];

...这使得在 C 样式数组和指针之间来回切换几乎无缝。

在您的代码中,您声明了一个指向 float 的指针:

float* coefs;

(顺便说一句,这应该初始化为NULLL,但那是另一回事了),然后将其设置为某个值:

coefs = model.ptr<float>(0);

我不知道model.ptr&lt;float&gt;(0) 做了什么,但它可能要么分配一个数组并返回一个指向该数组的指针,要么返回一个指向已经设置好的数组的指针。

现在因为coefs 是指向float 的指针,所以您可以像使用数组一样使用它,您可以在循环中这样做:

for( int ci = 0; ci < componentsCount; ci++ )
    if( coefs[ci] > 0 )

这就是它起作用的原因。

【讨论】:

【参考方案2】:

coefs如何变成数组

在 C 和 C++ 中,p[i] 只是 *(p + i) 的语法糖。当然,这个结构只有在p 恰好指向一个数组的元素并且p + i 没有超出该数组的边界时才有意义。否则,你会得到undefined behavior。

Kos 写道:请不要在每次出现问题时都说“未定义的行为”,除非你可以用标准来支持它

好的,既然你要求它:

当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有类型 的指针操作数。如果指针操作数指向数组对象的一个​​元素,并且数组是 足够大,结果指向与原始元素偏移的元素,使得 结果和原始数组元素的下标等于整数表达式。换句话说,如果 表达式P 指向数组对象的第i 个元素,表达式(P)+N(等效于N+(P)) 和(P)-N(其中N 的值为n)分别指向数组的第i + n 个和第i 个元素 对象,只要它们存在。此外,如果表达式P 指向数组对象的最后一个元素, 表达式 (P)+1 指向数组对象的最后一个元素,如果表达式 Q 指向 在数组对象的最后一个元素之后,表达式(Q)-1 指向数组的最后一个元素 目的。 如果指针操作数和结果都指向同一个数组对象的元素,或者一个过去 数组对象的最后一个元素,评估不应产生溢出; 否则,行为未定义。

【讨论】:

不真实...好吧,技术上正确,但不清楚:),因为p 实际上可能指向数组的任何元素。另外,请不要每次出现问题时都说“未定义的行为”,除非您可以用标准来支持它 - 仍然存在“未指定”和“实现定义”,后者基本上意味着存在情况(特定机器,架构,编译器...)这样的代码将是有效的。 @Kos:我明白你的观点,我并不反对,但这实际上是未定义的行为。 @Fred:说“是 p 恰好指向数组中的第一个元素,[否则它是 UB]”不太正确。正确的说法是“如果 *(p+1) 不指向数组中的元素,则得到 ub”是正确的。如果你要祈求UB之神,你应该是正确和准确的。 你是说 - 假设我在 GCC 的 32 位机器上有 3 个 32 位浮点数的 POD 结构 - 如果我尝试通过指向第一个浮点数的指针来引用第二个浮点数增加 1 ,我可以期待恶魔从我的鼻子里飞出来,或者 - 嗯 - 比人们指责我的坏作风更糟糕的事情吗?虽然我无法确认,但我相信这种情况下的行为是可以预测的;这就是我对“实现定义”的理解(类似于工会、reinterpret_casts 等的情况)。如果我在这里错了,请用一些来源纠正我。 @Kos:事物可以由实现定义,而不是实现定义。 C++ 标准将很多东西保留为 UB(这意味着它不是实现定义的),但是没有规则阻止特定实现定义它在该特定实现上的行为方式(所以它是可以预测的,但 C++ 标准并不要求它是这样,因此它仍然是 UB)。如果标准说它是由实现定义的,那么事情只有在 C++ 用语中是实现定义的。这有意义吗?【参考方案3】:

在 C 和 C++ 中,指针和数组是等价的。您可以将它们视为指针或数组,这取决于您。指向单个变量的指针可以被认为是一个包含 1 个元素的数组。

【讨论】:

不,指针和数组不等价。在某些情况下,数组的行为很像指针(数组到指针衰减),但它不是指针。例如,sizeof(some_array) 产生整个数组的大小,而sizeof(some_pointer) 产生指针的大小。 float*float[1] 是存储不同内容的不同类型。 @FredOverflow:它们是等价的,但它们并不相同。 int 和 short 是等价的,但不一样。 intshort 到底是如何等效的? “数组对象可以隐式转换为指向数组内部类型的指针”,用 C++ 术语表示。我不记得 C++ 有 “等效” 的概念。【参考方案4】:

从您的代码看来,model 是实际包含数组的数据结构。

coefs = model.ptr<float>(0);

这里,coefs 不会“变成”数组,而是指向model 中的现有数组,之后它可以像真正的数组一样使用。其他变量meancovc 也是如此——它们都被分配了一个指向数组中特定位置的指针。例如:

mean = coefs + componentsCount;

使mean 指向coefs“数组”的第6 个(从componentsCount = 5 开始)元素。在此之后,mean 可以被视为从model 的第 6 个元素开始的数组。

【讨论】:

【参考方案5】:

float *c = cov + 9*ci;

c 是指向 cov 指向的任何位置的指针,加上浮点大小的 9 倍(假设标准 IEEE-754 float 为 4 个字节)。这是指针算法。

我不确定 coefs 指向什么,但我认为它是在 model.ptr&lt;float&gt;(0); 语句中的某个位置分配的。否则,它是一个无效的指针(可能为 NULL)。

在 C 和 C++ 中,存在指针和数组之间的区别的细分。考虑以下代码:

int A[5];
int y = *A;  // The first occurrence of A is also the dereferenced value of *A
int z = A[0]; // The first occurrence of A
int *w = A;  // pointer to the beginning of A
if (*w == y)  // TRUE, dereferenced int value == int value
if (w == A)  // TRUE, address == address

【讨论】:

如果 c 是指向 cov 指向的任何位置的指针加上浮点大小的 9 倍(或者您的意思是 int?),我将如何编写想要将 ci 的实际值乘以的代码9 而不是它的字节大小?

以上是关于C++ 指针和数组的主要内容,如果未能解决你的问题,请参考以下文章

c++二维数组和二级指针

C++ 指针与数组

C++ 指针 vs 数组

基于arm的C++反汇编 数组和指针的寻址

C++ 指针数组

如何使用 C++ 中的指针动态分配和解除分配二维数组?