34

Original question: If I define:

const int z[5] = {10, 11, 12, 13, 14}; 

does it mean:

  1. it's a constant array of integers i.e. the address which z points to is always constant and can never change, but the elements of z can change.

OR

  1. Each element of z is a constant i.e. their value can never change.

Edit:

More info:

There is another variable:

const int *y = z;
func((int *) y);

where func is defined as:

void func(int y[]) {
    int i;
    for(i = 0; i < 5; i++) {
        y[i] = i; //y[i] can be set to any integer; used i as example
    }
}

where in func, using y, the array is traversed and each element is changed. Is this is valid even though all elements of z are const?

sandeeps
  • 966
  • 2
  • 9
  • 11
  • 4
    Did you try changing `z[0]`? – Amit Sep 21 '15 at 22:21
  • 6
    The address that `z` points to can never change anyway. In any case, you can use http://cdecl.org/ – juanchopanza Sep 21 '15 at 22:21
  • Cross reference [this post](http://stackoverflow.com/questions/7633776/constant-array-of-constant-objects) – lurker Sep 21 '15 at 22:23
  • @Amit Yes, I was able to change z[0]. I used to think the definition meant the meaning #2. But since I was able to change z[0], I am confused now. – sandeeps Sep 21 '15 at 22:27
  • Actually only the programmer guarantees for each value not to write to it. Nothing less, nothing more. Wheter the compiler will really use read-only memory is not defined by the standard. This becomes instantly clear when using this as a function argument. You can still pass non-`const` values. – too honest for this site Sep 21 '15 at 22:30
  • @sandeeps Sounds like your compiler is broken. – juanchopanza Sep 21 '15 at 22:30
  • 2
    That doesn't make sense. Given that declaration, any attempt to modify `z[0]` should have been rejected by the compiler. Please update your question with a complete self-contained example that demonstrates this. – Keith Thompson Sep 21 '15 at 22:30
  • 1
    @juanchopanza: That's doubtful. It's far more likely that the OP has made a mistake somewhere. – Keith Thompson Sep 21 '15 at 22:31
  • @KeithThompson Yes, that is what I was actually trying to say, in my own special way :-) – juanchopanza Sep 21 '15 at 22:31
  • @Olaf: A compiler *will* reject attempts to modify `const` objects (though you can bypass those checks with, for example, pointer casts). – Keith Thompson Sep 21 '15 at 22:34
  • @KeithThompson: I did not say different. However, if you really want to break the contract (e.g. by casting away `const`), the compiler will not hinder you. (but gcc still warns). C does not have true constants. – too honest for this site Sep 21 '15 at 22:39
  • @KeithThompson I have added more info to my question. – sandeeps Sep 21 '15 at 22:42
  • How is `func` declared? If it's something like `void func(int *arg)`, then you should get *at least* a warning on the call. – Keith Thompson Sep 21 '15 at 22:52
  • No, what does the declaration of `func` look like? – Keith Thompson Sep 21 '15 at 22:53
  • @KeithThompson I am writing it, I accidentally pressed the enter key earlier and it posted the incomplete statement. – sandeeps Sep 21 '15 at 22:54
  • 1
    You don't get a compiler warning because you cast the value of `y` to `int*`. You're telling the compiler to *pretend* that `y` points to non-`const` data. Since in fact `y` points to `const` data, you have lied to the compiler, and your code has undefined behavior. Casts, especially pointer casts, should usually be avoided. – Keith Thompson Sep 21 '15 at 23:11
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90270/discussion-between-sandeeps-and-keith-thompson). – sandeeps Sep 21 '15 at 23:13

2 Answers2

49

It means that each element of z is read-only.

The object z is an array object, not a pointer object; it doesn't point to anything. Like any object, the address of z does not change during its lifetime.

Since the object z is an array, the expression z, in most but not all contexts, is implicitly converted to a pointer expression, pointing to z[0]. That address, like the address of the entire array object z, doesn't change during the object's lifetime. This "conversion" is a compile-time adjustment to the meaning of the expression, not a run-time type conversion.

To understand the (often confusing) relationship between arrays and pointers, read section 6 of the comp.lang.c FAQ.

It's important to understand that "constant" and const are two different things.

If something is constant, it's evaluated at compile time; for example, 42 and (2+2) are constant expressions.

If an object is defined with the const keyword, that means that it's read-only, not (necessarily) that it's constant. It means that you can't attempt to modify the object via its name, and attempting to modify it by other means (say, by taking its address and casting to a non-const pointer) has undefined behavior. Note, for example, that this:

const int r = rand();

is valid. r is read-only, but its value cannot be determined until run time.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Could you explain what you mean by: "`z` is an array, **not a pointer**; it doesn't point to anything" and then "Since `z` is an array...is implicitly **converted to a pointer** to `z[0]` " Is it a pointer or not? – Ziezi Sep 21 '15 at 22:36
  • 1
    @simplicisveritatis: An array is not a pointer. Try taking the sizes of both. But the **name** of the array is implicitly converted to a pointer to the first element for most uses. – too honest for this site Sep 21 '15 at 22:42
  • 2
    A `const` object in C (different from C++) is not necessarily read-only. It is left to the implementation if there is any write-protection to the object. `const` is only a guarantee by the programmer not to write to the object. The compiler can rely on this contract. There are other languages, there is no practical difference between a constant and a literal. – too honest for this site Sep 21 '15 at 22:46
  • 2
    @simplicisveritatis: If it were already a pointer, it wouldn't need to be *converted* to a pointer. An array object contains a contiguous sequence of elements. A pointer object contains a single address. They're completely different things. Again, please read section 6 of the [comp.lang.c FAQ](http://www.c-faq.com); it explains this in more detail than I have time for. – Keith Thompson Sep 21 '15 at 22:49
  • @Olaf: A `const` object is read-only in the sense that any attempt to modify it via its declared name is a constraint violation, and any attempt to modify it otherwise has undefined behavior. – Keith Thompson Sep 21 '15 at 22:50
  • @KeithThompson: Right. But the compiler will not keep you from trying (this is useful for e.g. MCUs with data in Flash for updates - **if you know what you do**). Other languages OTOH will not allow such write under any circumstances, i.e. prevent you actively from breaking the contract. – too honest for this site Sep 21 '15 at 22:55
  • @Keith Thompson I just wanted to address and clarify this apparent ambiguity in two consecutive sentences of the answer you provide. :) The rest is crystal clear. – Ziezi Sep 21 '15 at 23:04
  • 1
    @simplicisveritatis: Ok. Are those two sentences clear now? – Keith Thompson Sep 21 '15 at 23:08
  • @Keith Thompson absolutely! :) – Ziezi Sep 21 '15 at 23:15
1

In your case the answer is:

  1. Each element of z is a constant i.e. their value can never change.

You can't create a const array because arrays are objects and can only be created at runtime and const entities are resolved at compile time.

So, the const is interpreted as in the first example below, i.e. applied for the elements of the array. Which means that the following are equivalent: The array in your example needs to be initialized.

 int const z[5] = { /*initial (and only) values*/};
 const int z[5] = { /*-//-*/ };

It is some type commutative property of the const specifier and the type-specifier, in your example int.

Here are few examples to clarify the usage of constant:

1.Constant integers definition: (can not be reassigned). In the below two expression the use of const is equivalent:

int const a = 3;  // after type identifier
const int b = 4;  // equivalent to before type qualifier

2.Constant pointer definition (no pointer arithmetics or reassignment allowed):

int * const p = &anInteger;  // non-constant data, constant pointer

and pointer definition to a constant int (the value of the pointed integer cannot be changed, but the pointer can):

const int *p = &anInteger;  // constant data, non-constant pointer
Ziezi
  • 6,375
  • 3
  • 39
  • 49
  • 12
    since when can an array only be "created" at runtime, in C ? If you define it as an array of const values then it will be created at compile time. – NikkyD May 25 '18 at 14:01
  • 4
    "`const` entities are resolved at compile time". This is false. For example, `const int r = rand();` is valid, but the value is evaluated in runtime – Kolay.Ne Apr 20 '21 at 12:07