Const массивы в C

Оригинальный вопрос: Если я определяю:

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

означает ли это:

  • это постоянный массив целых чисел, то есть адрес, который указывает z, всегда постоянный и никогда не может меняться, но элементы z могут меняться.

ИЛИ

  1. Каждый элемент z является константой, т.е. их значение никогда не может измениться.

Edit:

Дополнительная информация:

Существует еще одна переменная:

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

где func определяется как:

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
    }
}

где в func, используя y, массив перемещается и каждый элемент изменяется. Действительно ли это верно, хотя все элементы z являются const?

Ответ 1

Это означает, что каждый элемент z доступен только для чтения.

Объект z является объектом массива, а не объектом указателя; это ни на что не указывает. Как и любой объект, адрес z не меняется в течение срока его службы.

Поскольку объект z является массивом, выражение z в большинстве, но не во всех контекстах неявно преобразуется в выражение указателя, указывающее на z[0]. Этот адрес, как и адрес всего объекта массива z, не изменяется в течение времени жизни объекта. Это "преобразование" является корректировкой значения выражения во время компиляции, а не преобразованием типов во время выполнения.

Чтобы понять (часто путающие) отношения между массивами и указателями, прочитайте раздел 6 comp.lang.c FAQ.

Важно понимать, что "константа" и const - две разные вещи. Если что-то постоянно, оно оценивается во время компиляции; например, 42 и (2+2) являются константными выражениями.

Если объект определен с помощью ключевого слова const, это означает, что он доступен только для чтения, а не (обязательно), что он постоянный. Это означает, что вы не можете пытаться изменить объект через его имя, а попытка изменить его другими способами (например, путем взятия его адреса и приведения к неконстантному указателю) имеет неопределенное поведение. Обратите внимание, например, что это:

const int r = rand();

действителен. r только для чтения, но его значение нельзя определить до времени выполнения.

Ответ 2

В вашем случае ответ:

  1. Каждый элемент z является константой, т.е. их значение никогда не может измениться.

Вы не можете создать массив const, потому что массивы являются объектами и могут создаваться только во время выполнения, а const сущности разрешаются во время компиляции.

Итак, const интерпретируется как в первом примере ниже, т.е. применяется для элементов массива. Это означает, что следующие эквиваленты: Массив в вашем примере должен быть инициализирован.

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

Это некоторый тип коммутативное свойство спецификатора const и спецификатор типа в вашем примере int.

Вот несколько примеров, поясняющих использование константы:

1. Определение целочисленных целых чисел: (нельзя переназначить). В приведенном ниже выражении использование const эквивалентно:

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

2. Определение указателя константы (без арифметики указателей или переопределения):

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

и определение указателя константе int (значение цельного числа не может быть изменено, но указатель может):

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