Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a const array of const elements

I want to declare a constant array of constant char arrays. If I write it like this:

const char foo[] = "Foo";
const char bar[] = "Bar";
const char* const foobar[2] = { foo, bar };

It seems to work, but if I try to read it using "the spiral rule", foobar is read as:

"foobar is an array 2 of constant (??) to a pointer to a char constant"

Using this stack overflow answer,

const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.

the first const would apply to the char, and the second const would apply to same char as well.

Both ways of reading it doesn't make sense, but the code does function (in Arduino [sorry], at least). Which const is making which a constant? Is there a more logical way to write it?

like image 982
apscience Avatar asked Feb 04 '15 11:02

apscience


3 Answers

As you've stated:

const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.

const char* const foobar[2] = { foo, bar };

can be re-written as:

char const * const foobar[2] = { foo, bar };

Now imagine the paratheses encapsulating const qualifier and the entity qualified:

((char const) (* const)) foobar[2] = // doesn't matter

You've written that the second const would apply to same char as well. This is not true - the second const refers to the *, which means it's a constant pointer.

All in all, foobar is an array of constant pointers to constant chars.

You may also want to read this thread: constant pointer vs pointer on a constant value .

like image 83
rubikonx9 Avatar answered Oct 20 '22 21:10

rubikonx9


A finicky but important point; in C it is not possible to have a const array. (Ref: C11 6.3.2.3/2).

Everything that looks like it might be one is actually a non-const array whose elements are const. Link to related discussion.

In your example const char* const foobar[2] = { foo, bar };, the two const keywords mean:

  • The two pointers in the array cannot be made to point elsewhere
  • The characters being pointed to by those pointers shall not be modified through those pointers.

The text description is "foobar is an array 2 of constant pointer to a char constant".

Note the small but important distinction again that the chars being pointed to might actually be non-const char, because a const char * can point to both const and non-const. The effect of the first const is to say that we might not know whether the chars are const or not, and so we can't safely write to them, so the compiler will generate an error if we try to use this pointer ot write to them.

like image 34
M.M Avatar answered Oct 20 '22 20:10

M.M


foobar is an array of const pointers to const char. An array is always constant, there is no way to explicitly make it const.

In the declaration of function arguments, arrays decay to pointers, and a const pointer does exist; in this case, const can be put inside the []. These are equivalent:

void func(int foo[const]) { ... }
void func(int *const foo) { ... }

The spiral rule isn't perfect (it fails for some complex declarations), and I personally don't find it helpful in combination with qualifiers (const, volatile etc). I don't know of anything rendering the rules exactly but the grammar itself (C11 6.7 and 6.7.6).

In this case, however, it seems to work:

                    +--------------+
                    |      +---+   |
                    |      ^   |   |
       const char *const foobar[2] |
             ^      ^          |   |
             |      +----------+   |
             +---------------------+

"foobar is an array (with 2 elements) of const pointers to const char."

like image 4
mafso Avatar answered Oct 20 '22 21:10

mafso