Pointer to array of array of const pointer

R

RSL

In order to let compiler catches unintended changes of a passed object
in a function, we added const, for example:

struct MyStruct
{
int Value;
};

void bar(const MyStruct * const pObj)
{
// pObj = <address of another MyStruct object>;
// pObj->Value = <some value>;
}

int main()
{
MyStruct AObj;

bar(&AObj);
}

If uncommented the two lines in bar(), the compiler should be able to
catch them.

This also works for array of (const) pointers (to const):

void foo(MyStruct const *const (PtrAry)[10])
{
// PtrAry[0] = <address of another MyStruct object>;
// PtrAry[0]->Value = <some value>;
}

int main()
{
MyStruct *AryOfPtr[10] = { &AObj };
// ...
foo(AryOfPtr);
}

However, it does not works for array-of-array:

void foobar(MyStruct* const (*PtrAry)[10])
{
// PtrAry[0][0] = <address of another MyStruct object>;
PtrAry[0][0]->Value = 20;
}

int main()
{
MyStruct *ary2[10][10];
// ...
foobar(ary2);
}

In foobar(),
PtrAry[0][0]->Value = 20;
is allowed. This is expected because MyStruct is not declared as
const.

However, if foobar() is declared as such:
void foobar(const MyStruct* const (*PtrAry)[10])
{
// PtrAry[0][0] = <address of another MyStruct object>;
// PtrAry[0][0]->Value = <some value>;
}

Compiler can catch both lines (if uncommented) but generate an error
in main (cannot convert parameter 1 from 'MyStruct *[10][10]' to
'const MyStruct *const (*)[10]')

Is it possible to declare foobar() such that PtrAry points to an
arrays of pointer to non-modifiable object.
 
V

Victor Bazarov

RSL said:
[..]
However, if foobar() is declared as such:
void foobar(const MyStruct* const (*PtrAry)[10])
{
// PtrAry[0][0] = <address of another MyStruct object>;
// PtrAry[0][0]->Value = <some value>;
}

Compiler can catch both lines (if uncommented) but generate an error
in main (cannot convert parameter 1 from 'MyStruct *[10][10]' to
'const MyStruct *const (*)[10]')

Is it possible to declare foobar() such that PtrAry points to an
arrays of pointer to non-modifiable object.

So, to make PtrAry a pointer, you put * in front.
To make it point to an array, you surround it with parens and put the
brackets to the right.
Each element of the array is declared of the type that is to the left of
the parens. You want it (an element) to be a pointer, put the star in
front of it. The type goes to the left of that.

In the order explained:

*PtrAry : a pointer


(*PtrAry)[] : a pointer to an array


*(*PtrAry)[] : a pointer to an array of pointers

MyStruct const *(*PtrAry)[] :
a pointer to an array of pointers to const MyStruct objects

V
 
R

RSL

So, to make PtrAry a pointer, you put * in front.
To make it point to an array, you surround it with parens and put the
brackets to the right.
Each element of the array is declared of the type that is to the left of
the parens.  You want it (an element) to be a pointer, put the star in
front of it.  The type goes to the left of that.

In the order explained:

               *PtrAry      :       a pointer

               (*PtrAry)[]  :      a pointer to an array

              *(*PtrAry)[]  :   a pointer to an array of pointers

MyStruct const *(*PtrAry)[]  :
         a pointer to an array of pointers to const MyStruct objects

Right, but then, I am not able to call the function, and pass a non-
const argument:
int main()
{
MyStruct *ary2[10][10];
// ...
foobar(ary2);
}

What I want is to maintain const-correctness from within the
function. The function promise not to modify the pointer PtrAry[n]
[m], and the object PtrAry[n][m] points to. Therefore, the compiler
should be able to flag the following lines as error:
PtrAry[0][0] = ...; /* [1] */
PtrAry[0][0]->Value = ...; /* [2] */

In order for the compiler to catch [1], the function needs to be
declared as:
void foobar(MyStruct *const (*PtrAry)[10] )

In order for the compielr to catch [2], another 'const' needs to be
added before the leftmost '*':
void foobar(const MyStruct *const (*PtrAry)[10] )


OTOH, single dimensional array works as expected:
struct MyStruct
{
int Value;
};

// Pointer to const array of const pointer
void foo(MyStruct const *const (PtrAry)[10])
{
//PtrAry[0] = ...;
//PtrAry[0]->Value = ...;
}
int main()
{
MyStruct *AryOfPtr[10];
foo(AryOfPtr);
}
 
V

Victor Bazarov

RSL said:
So, to make PtrAry a pointer, you put * in front.
To make it point to an array, you surround it with parens and put the
brackets to the right.
Each element of the array is declared of the type that is to the left of
the parens. You want it (an element) to be a pointer, put the star in
front of it. The type goes to the left of that.

In the order explained:

*PtrAry : a pointer

(*PtrAry)[] : a pointer to an array

*(*PtrAry)[] : a pointer to an array of pointers

MyStruct const *(*PtrAry)[] :
a pointer to an array of pointers to const MyStruct objects

Right, but then, I am not able to call the function, and pass a non-
const argument:
int main()
{
MyStruct *ary2[10][10];
// ...
foobar(ary2);
}

I think this is explained in the C FAQ. Hmm... Where is it?... Hold
on, I'll find it for you... Ah, here it is: http://c-faq.com/. See
question 6.18. Or, another explanation is given in C++ FAQ 18.17.
What I want is to maintain const-correctness from within the
function. The function promise not to modify the pointer PtrAry[n]
[m], and the object PtrAry[n][m] points to. Therefore, the compiler
should be able to flag the following lines as error:
PtrAry[0][0] = ...; /* [1] */
PtrAry[0][0]->Value = ...; /* [2] */

In order for the compiler to catch [1], the function needs to be
declared as:
void foobar(MyStruct *const (*PtrAry)[10] )

That's a [single] pointer to an array of ten constant pointers.
In order for the compielr to catch [2], another 'const' needs to be
added before the leftmost '*':
void foobar(const MyStruct *const (*PtrAry)[10] )

Yes.

I think you already said that before.
OTOH, single dimensional array works as expected:

(Why OTOH?)
struct MyStruct
{
int Value;
};

// Pointer to const array of const pointer
void foo(MyStruct const *const (PtrAry)[10])

That's not a pointer to a const array. It's simply a pointer. The fact
that you write '10' between the brackets does not really matter. This
is one of the old (and not necessarily all that great) features of the
language, a carryover from C. According to the rules of declarations,
your function is actually:

void foo(MyStruct const* const* PtrAry)

(meaning, 'PtrAry' is a pointer to a const pointer to a const MyStruct).
{
//PtrAry[0] = ...;
//PtrAry[0]->Value = ...;
}
int main()
{
MyStruct *AryOfPtr[10];
foo(AryOfPtr);
}

Yes, that's OK. Since the type of the expression 'AnyOfPtr' (yes, it's
an expression) is 'MyStruct**', it is convertible to 'MyStruct const*
const*'. That's how the language works.

I am still trying to grok what problem you're trying to solve.

V
 
G

Gert-Jan de Vos

...
However, if foobar() is declared as such:
    void foobar(const MyStruct* const (*PtrAry)[10])
    {
        // PtrAry[0][0] = <address of another MyStruct object>;
        // PtrAry[0][0]->Value = <some value>;
    }

Compiler can catch both lines (if uncommented) but generate an error
in main (cannot convert parameter 1 from 'MyStruct *[10][10]' to
'const MyStruct *const (*)[10]')

Is it possible to declare foobar() such that PtrAry points to an
arrays of pointer to non-modifiable object.

No. 4.4 Qualification conversions details the const/volatile
conversions. These conversions are supported on multi level
pointers but not in arrays. So there is no conversion from an
array of MyStruct* to an array of const MyStruct*, or vice
versa. Why it works with 1D arrays is because the top level
array declaration in a function parameter is interpreted as a
pointer, there the qualification conversions are supported.
 
R

RSL

I am still trying to grok what problem you're trying to solve.

Thanks for the explanation.

Forget about the one-dimensional example, I think I've messed up. Let
me start over again...

What I want to know is as follow:

Given the codes:
struct MyStruct
{
int Value;
};

int main()
{
MyStruct* AryPtr[10][10];
foo(AryPtr);
}

and the following properties for foo():
- It will not modify AryPtr[n][m].
- It will not modify AryPtr[n][m]->Value.

How should foo() be declared for the compiler to enforce the
properties?

In other word, if I accidentally write these in foo(), ('AryPtr' is
the formal argument in foo()):
AryPtr[0][0] = <something>;
AryPtr[0][0]->Value = <some value>;

I want the compiler to catch and report errors.
 
R

RSL

...
However, if foobar() is declared as such:
    void foobar(const MyStruct* const (*PtrAry)[10])
    {
        // PtrAry[0][0] = <address of another MyStruct object>;
        // PtrAry[0][0]->Value = <some value>;
    }
Compiler can catch both lines (if uncommented) but generate an error
in main (cannot convert parameter 1 from 'MyStruct *[10][10]' to
'const MyStruct *const (*)[10]')
Is it possible to declare foobar() such that PtrAry points to an
arrays of pointer to non-modifiable object.

No. 4.4 Qualification conversions details the const/volatile
conversions. These conversions are supported on multi level
pointers but not in arrays. So there is no conversion from an
array of MyStruct* to an array of const MyStruct*, or vice
versa. Why it works with 1D arrays is because the top level
array declaration in a function parameter is interpreted as a
pointer, there the qualification conversions are supported.

Okay, I just read this after I send the last reply to Victor. I guess
it cannot be done if using multidimensional array.

Thanks.
 
V

Victor Bazarov

RSL said:
I am still trying to grok what problem you're trying to solve.

Thanks for the explanation.

Forget about the one-dimensional example, I think I've messed up. Let
me start over again...

What I want to know is as follow:

Given the codes:
struct MyStruct
{
int Value;
};

int main()
{
MyStruct* AryPtr[10][10];
foo(AryPtr);
}

and the following properties for foo():
- It will not modify AryPtr[n][m].
- It will not modify AryPtr[n][m]->Value.

How should foo() be declared for the compiler to enforce the
properties?

In other word, if I accidentally write these in foo(), ('AryPtr' is
the formal argument in foo()):
AryPtr[0][0] = <something>;
AryPtr[0][0]->Value = <some value>;

I want the compiler to catch and report errors.

So, the array has to be of const values and each value has to be a
pointer to a const object. And you want to be able to use your
two-dimensional array of pointers to non-const objects in that function.

I see. Hmm... I don't think it's possible. It seems that you want
something like

struct A { int i; };
A ga;

void foo(A const* const myarr[][10])
// 'myarr' is a pointer to an array of 10 const pointers to const A
{
myarr[5][5] = &ga; // gives an error
myarr[5][5]->i = 42; // gives an error
}

int main()
{
A *pAarr[10][10];
foo(pAarr);
}

But those deeply-seated 'const' qualifiers confuse the conversion
mechanism, and do not allow this conversion to happen.

V
 
R

RSL

So, the array has to be of const values and each value has to be a
pointer to a const object.  And you want to be able to use your
two-dimensional array of pointers to non-const objects in that function.

I see.  Hmm...  I don't think it's possible.  It seems that you want
something like

    struct A { int i; };
    A ga;

    void foo(A const* const myarr[][10])
// 'myarr' is a pointer to an array of 10 const pointers to const A
    {
        myarr[5][5] = &ga; // gives an error
        myarr[5][5]->i = 42; // gives an error
    }

    int main()
    {
        A *pAarr[10][10];
        foo(pAarr);
    }

But those deeply-seated 'const' qualifiers confuse the conversion
mechanism, and do not allow this conversion to happen.

Yes, after reading through all the reply and the Standard, I reckon it
cannot be done this way.

Thanks for all who helps.
 
R

RSL

So, the array has to be of const values and each value has to be a
pointer to a const object.  And you want to be able to use your
two-dimensional array of pointers to non-const objects in that function.

I see.  Hmm...  I don't think it's possible.  It seems that you want
something like

    struct A { int i; };
    A ga;

    void foo(A const* const myarr[][10])
// 'myarr' is a pointer to an array of 10 const pointers to const A
    {
        myarr[5][5] = &ga; // gives an error
        myarr[5][5]->i = 42; // gives an error
    }

    int main()
    {
        A *pAarr[10][10];
        foo(pAarr);
    }

But those deeply-seated 'const' qualifiers confuse the conversion
mechanism, and do not allow this conversion to happen.

Yes, after reading through all the reply and the Standard, I reckon it
cannot be done this way.

Thanks for all who helps.
 
R

RSL

So, the array has to be of const values and each value has to be a
pointer to a const object.  And you want to be able to use your
two-dimensional array of pointers to non-const objects in that function.

I see.  Hmm...  I don't think it's possible.  It seems that you want
something like

    struct A { int i; };
    A ga;

    void foo(A const* const myarr[][10])
// 'myarr' is a pointer to an array of 10 const pointers to const A
    {
        myarr[5][5] = &ga; // gives an error
        myarr[5][5]->i = 42; // gives an error
    }

    int main()
    {
        A *pAarr[10][10];
        foo(pAarr);
    }

But those deeply-seated 'const' qualifiers confuse the conversion
mechanism, and do not allow this conversion to happen.

Yes, after reading through all the reply and the Standard, I reckon it
cannot be done this way.

Thanks for all who helps.
 
R

RSL

Oops, I accidentally refreshes the page twice and multiply the last
reply. Is there any way to delete duplicated postings?

Really sorry about this.
 
V

Vladimir Jovic

Victor said:
RSL said:
[..]
However, if foobar() is declared as such:
void foobar(const MyStruct* const (*PtrAry)[10])
{
// PtrAry[0][0] = <address of another MyStruct object>;
// PtrAry[0][0]->Value = <some value>;
}

Compiler can catch both lines (if uncommented) but generate an error
in main (cannot convert parameter 1 from 'MyStruct *[10][10]' to
'const MyStruct *const (*)[10]')

Is it possible to declare foobar() such that PtrAry points to an
arrays of pointer to non-modifiable object.

So, to make PtrAry a pointer, you put * in front.
To make it point to an array, you surround it with parens and put the
brackets to the right.
Each element of the array is declared of the type that is to the left of
the parens. You want it (an element) to be a pointer, put the star in
front of it. The type goes to the left of that.

In the order explained:

*PtrAry : a pointer


(*PtrAry)[] : a pointer to an array


*(*PtrAry)[] : a pointer to an array of pointers

MyStruct const *(*PtrAry)[] :
a pointer to an array of pointers to const MyStruct objects

In other words : too complex, and if the OP can not decipher it on his
own, he is going to create a maintenance nightmare.
 
V

Victor Bazarov

RSL said:
Oops, I accidentally refreshes the page twice and multiply the last
reply. Is there any way to delete duplicated postings?

Really sorry about this.

Not after they have propagated. Usually you'd use the "cancel"
functionality offered by your newsreader software. If you're using
Google web interface (I don't), I have no idea if it has a way to do that.

Don't worry about it.

V
 
R

RSL

Not after they have propagated.  Usually you'd use the "cancel"
functionality offered by your newsreader software.  If you're using
Google web interface (I don't), I have no idea if it has a way to do that..

I was using the Google web interface.

After that, I explore a little and find that there is a clickable
"More options" at the beginning of each reply. Click it, it will
expand and show more clickable action links. One of them is
"Remove".

(One have to login first and can only remove own message).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top