descf
descf

Reputation: 1312

C++ Pointers & Arrays

Below is some code from a C++ procedure. The original can be found here; https://code.ros.org/trac/opencv/browser/trunk/opencv/modules/imgproc/src/grabcut.cpp

My perspective is that I am a C# rather than C++ programmer so this code is a bit of a mystery to me even though I ran it through a code converter and it came out unchanged.

My questions are: a). How does 'coefs' become an array, and b). how does 'c' get populated?

To give a bit more information: 'coefs' does not seem to start out as an array and 'c' somehow seems to magically get at least 8 items

    // 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]);

Upvotes: 1

Views: 500

Answers (5)

fredoverflow
fredoverflow

Reputation: 263118

How does coefs become an array

In C and C++, p[i] is just syntactic sugar for *(p + i). Of course, this construct is only meaningful if p happens to point to an element of an array and p + i does not march off the bounds of that array. Otherwise, you get undefined behavior.

Kos wrote: please don't just say "undefined behaviour" every time something's wrong unless you can back it up with a standard

Okay, since you were asking for it:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i - n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

Upvotes: 2

pr1268
pr1268

Reputation: 1186

float *c = cov + 9*ci;

c is a pointer to wherever cov points to plus 9 times the size of a float (4 bytes assuming standard IEEE-754 float). This is pointer arithmetic.

I'm unsure what coefs points to, but I assume it gets assigned somewhere in the model.ptr<float>(0); statement. Otherwise, it's an invalid pointer (probably NULL).

In C and C++, there exists a breakdown of the distinction between pointers and arrays. Consider the following code:

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

Upvotes: 0

casablanca
casablanca

Reputation: 70701

It appears from your code that model is the data structure that actually contains an array.

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

Here, coefs doesn't "become" an array, but it points to the existing array in model, after which it can be used just like a real array. The same happens with the other variables mean, cov and c -- they are all assigned a pointer to a specific location within the array. For example:

mean = coefs + componentsCount;

makes mean point to the 6th (since componentsCount = 5) element of the coefs "array". After this, mean can be viewed as an array that begins from the 6th element of model.

Upvotes: 0

John Dibling
John Dibling

Reputation: 101456

When you declare an array like this:

int my_ints[10];

my_ints is an array. But in C++ my_ints can also be evaluated as a pointer to the first item in the array. So code like this:

int* the_first_int = my_ints;

...is legal and valid, not to mention very common. You can also use the_first_int as if it were also an array, like this:

int the_third_int = the_first_int[2];

...which makes it practically seamless to go between C-style arrays and pointers and back again.

In your code you declare a pointer to a float:

float* coefs;

(by the way, this should be initialized to NULLL, but that's another story), and then you set it to some value:

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

I don't know what model.ptr<float>(0) does, but it probably either allocates an array and returns a pointer to that, or returns a pointer to an array that was already set up.

Now because the coefs is a pointer to float, you can use it like it were an array, which you do in the loop:

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

That's why this works.

Upvotes: 3

engf-010
engf-010

Reputation: 3929

In C and C++ pointers and arrays are equivalent. You can treat them as pointer or array ,tht up to you. A pointer to single variable can be considered an array of 1 element.

Upvotes: 0

Related Questions