1

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]);
descf
  • 1,302
  • 1
  • 12
  • 31

5 Answers5

3

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.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
2

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.

Community
  • 1
  • 1
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Untrue... OK, technically true, but unclear :), as `p` may point to any element of an array, actually. Also, please don't just say "undefined behaviour" every time something's wrong unless you can back it up with a standard - there's still "unspecified" and "implementation-defined", and the latter basically means that there are circumstances (specific machine, architecture, compiler...) where such code would be valid. – Kos Nov 27 '10 at 17:34
  • 2
    @Kos: I get your rant, and don't disagree with it, but this is in fact undefined behavior. – John Dibling Nov 27 '10 at 17:39
  • @Fred: Saying "is p happens to point to the first element in the array, [else it is UB]" Isn't quite right. The correct thing to say is "if *(p+1) doesn't point to an element in the array, you get ub" is correct. If you're going to invoke the UB gods, you should probably be correct and precise. – John Dibling Nov 27 '10 at 17:41
  • Are you saying that - assuming I have a POD struct of 3 32-bit floats on a 32-bit machine with GCC - if I try to reference the second float by pointer to the first increased by 1, I can expect demons flying from my nose, or - well - anything worse than people blaming me for bad style? While I can't confirm, I believe the behaviour is predictable in such case; and this is what I understand by "implementation-defined" (analogously to situation with unions, reinterpret_casts, etc). Please correct me with some source if i'm wrong here. – Kos Nov 27 '10 at 17:45
  • @Kos: Yes, I'm saying exactly that. Using pointer arithmetic to access struct members is undefined behavior, because **a struct is not an array**. The standard quote leaves no doubt: "If [...] **point to elements of the same array** [...] otherwise [...] undefined" – fredoverflow Nov 27 '10 at 17:56
  • I'm equally surprised and convinced - I expected this situation to be treated similarly to a reinterpret_cast, which has its mapping *implementation-defined*. However, the explanation makes sense. But it's curious that it's the same in C, where there are no pointer-to-members (and this implies that you also cannot emulate them with operator `offsetof`). Also, great to know that one-past-last is still allowed :). Fred, thanks for the help, +1 obviously. – Kos Nov 27 '10 at 18:18
  • 1
    @Kos: Things can be defined by the implementation without being implementation-defined. There are many things that the C++ standard leaves as UB (which means that it is *not* implementation-defined), but there is no rule stopping the specific implementation from defining how it will behave on that specific implementation (so it will be predictable, but the C++ standard doesn't *require* it to be so, and therefore it is still UB). Things are only implementation-defined in C++ parlance if the standard says that it is defined by the implementation. Does that make sense? – jalf Nov 28 '10 at 19:24
0

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.

engf-010
  • 3,980
  • 1
  • 14
  • 25
  • 1
    No, pointers and arrays **are not equivalent**. An array behaves a lot like a pointer in certain circumstances (array to pointer decay), but it **is not** a pointer. For example, `sizeof(some_array)` yields the size of the entire array, whereas `sizeof(some_pointer)` yields the size of a pointer. – fredoverflow Nov 27 '10 at 17:27
  • 1
    `float*` and `float[1]` are distinct types that store different things. – Potatoswatter Nov 27 '10 at 17:28
  • @FredOverflow: They are equivalent ,they are not the same. int and short are equivalent ,but not the same. – engf-010 Nov 27 '10 at 17:44
  • How on earth are `int` and `short` equivalent? – fredoverflow Nov 27 '10 at 17:50
  • *"An array object is **implicitly convertible** to a pointer to the array's inner type"*, in C++ terms. I cannot remember C++ having a notion of *"equivalent"*. – Kos Nov 27 '10 at 17:50
  • float x[1] = {1.0}; float *y = x; func( x ); func( y ); void Func( float* z ) { *z = 0.0; } – engf-010 Nov 27 '10 at 17:53
  • @Edwin: Standard says that sizeof(int) >= sizeof(short) >= sizeof(char). You could concevably assign a value to an int that won't fit in a short. They are not the same, nor are the equivilant. – John Dibling Nov 27 '10 at 17:56
  • Obviously you all don't realize that equivalent does not mean 'the same' – engf-010 Nov 27 '10 at 17:57
  • @Edwin: It does according to http://mw1.meriam-webster.com/dictionary/equivalent. Moreover, there's no such concept as "equivilant" in the Standard. – John Dibling Nov 27 '10 at 17:58
  • @Edwin: The complaint is simply that "equivilant" is imprecise, not necesarrily wrong. If you were to replace "equivilant" with "implicitly convertible" the argument would evaporate. – John Dibling Nov 27 '10 at 18:00
  • @John Dibling: 1.meriam-webster.com/dictionary/equivalent (3) corresponding or virtually identical especially in effect or function – engf-010 Nov 27 '10 at 18:06
0

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.

casablanca
  • 69,683
  • 7
  • 133
  • 150
0

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
pr1268
  • 1,176
  • 3
  • 9
  • 16
  • if c is a pointer to wherever cov points to plus 9 times the size of a float (or did you mean int?), how would I write code that wanted to multiply the actual value of ci by 9 rather than its byte size? – descf Nov 27 '10 at 19:02