const headache const

L

lwawrzyniak

I'm having some fun with const and multiple indirection. Consider the
following:

int *a; /* pointer to an integer */
const int *b; /* pointer to a constant integer */
b = a; /* ok */

int **c; /* pointer to (pointer to an integer) */
const int **d; /* pointer to (pointer to a constant integer) */
d = c; /* not ok (incompatible pointer type) */

int *const *e; /* pointer to (constant pointer to an integer) */
e = c; /* ok */


This is important to me because I am trying to pass a dynamically
allocated two-dimensional "array" to a function that is not allowed to
modify the data at any level of indirection.

void f(const int * const * a) {
// *a is read-only
// **a is read-only
}

int main(void) {
int **a = NULL;
f(a); // <-- compiler warning:
// "passing arg 1 from incompatible pointer type"
// (undesired behaviour)
return 0;
}


Why are (int *) and (const int *) compatible but (int **) and (const
int **) are not? Likewise, why are (int **) and (int *const *)
compatible but (int **) and (const int *const *) are not?

How can I "constify" data pointed to by a function parameter at all
levels of indirection? (Other than wrapping it up in structs)

Please refrain from suggesting that I should just give up on using
const altogether. That would be too easy :)

Thanks,
Lukasz
 
F

Flash Gordon

I'm having some fun with const and multiple indirection. Consider the
following:

Please refrain from suggesting that I should just give up on using
const altogether. That would be too easy :)

There is a lot about this in the comp.lang.c FAQ, a document you should
always check before asking a question here. I suggest you read question
11.10 and then come back with any further questions.
 
M

Michael Mair

void f(const int * const * a) {
// *a is read-only
// **a is read-only
}

int main(void) {
int **a = NULL;
f(a); // <-- compiler warning:
// "passing arg 1 from incompatible pointer type"
// (undesired behaviour)
return 0;
}

Why are (int *) and (const int *) compatible but (int **) and (const
int **) are not? Likewise, why are (int **) and (int *const *)
compatible but (int **) and (const int *const *) are not?

How can I "constify" data pointed to by a function parameter at all
levels of indirection? (Other than wrapping it up in structs)
<snip>

Have a look at
http://c-faq.com/ansi/constmismatch.html

Cheers
Michael
 
B

Bill Pursell

I'm having some fun with const and multiple indirection. Consider the
following:
How can I "constify" data pointed to by a function parameter at all
levels of indirection? (Other than wrapping it up in structs)

I have a related question. Consider the following:

/*
* Set loc (location) to the first occurence of target
* in text. Return 0 on success, -1 on failure.
*/
int
locate(const char *text, char const **loc, char target)
{
int ret = -1;
for ( ; *text; text++) {
if (*text == target) {
*loc = text;
ret = 0;
break;
}
}
return ret;
}


In the declaration of locate, we definitely want
text to be declared with const. The subsequent
assignment of loc "poisons" loc so that it needs
to be const. But someone calling such a function
generally doesn't really want that 2nd argument
to be const...so what's a person to do? Either
the caller has to pass a const in for the 2nd arg,
or cast it, or take the compiler warning.
 
L

lovecreatesbeauty

Why are (int *) and (const int *) compatible but (int **) and (const
int **) are not?

int * is a pointer to an int object;
const int * is a pointer to an int object[1];
So, they are the pointers of same type, the pointer are compatible.

An int * object and a const int * object are different object types[2],
so pointers to them are pointers to different object types, the pointer
are incompatible.

I learnt these from a post of Ian Collins', do I understand it
correctly?

--
Questions on that:

[1] I mean it should be: ... to a CONST int object[1];
[2] then an int object and const int object are also different,
pointers to them are different: int * and const int * are different
and incompatible, right?
 
L

lovecreatesbeauty

Why are (int *) and (const int *) compatible but (int **) and (const
int **) are not?

int * is a pointer to an int object;
const int * is a pointer to an int object[1];
So, they are the pointers of same type, the pointer are compatible.

An int * object and a const int * object are different object types[2],
so pointers to them are pointers to different object types, the pointer
are incompatible.

I learnt these from a post of Ian Collins', do I understand it
correctly?

--
Questions on that:

[1] I mean it should be: ... to a CONST int object[1];
[2] then an int object and const int object are also different,
pointers to them are different: int * and const int * are different
and incompatible, right?
 
B

Ben Bacarisse

Bill Pursell said:
I have a related question. Consider the following:

/*
* Set loc (location) to the first occurence of target
* in text. Return 0 on success, -1 on failure.
*/
int
locate(const char *text, char const **loc, char target)
{
int ret = -1;
for ( ; *text; text++) {
if (*text == target) {
*loc = text;
ret = 0;
break;
}
}
return ret;
}


In the declaration of locate, we definitely want
text to be declared with const. The subsequent
assignment of loc "poisons" loc so that it needs
to be const. But someone calling such a function
generally doesn't really want that 2nd argument
to be const

No indeed, but it is not const. It is not even a pointer to a const.

Unless I am missing something, I don't see any problem. The second
parameter is not const, but it must be a pointer to a pointer to const
chars (which is what you have written). Personally, I would write

const char **loc

rather than your way, but they mean exactly the same. The ordering of
"char const" might have misled you?

If the second parameter did not have the const keyword, your function
would break the "constness" of the chars pointed to by the first parameter.
 
B

Bill Pursell

Ben said:
No indeed, but it is not const. It is not even a pointer to a const.

Unless I am missing something, I don't see any problem.

The "problem" is pretty minor. Namely, if you don't
declare it with const, then you get a compiler warning
about the assignment *loc = text. If you do declare it with const,
then the caller must only pass it a pointer to const,
or that call will generate a compiler warning.
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top