2015-10-07 1 views
1

Я написал программу C для отображения значений массива с помощью указателя. Вот код:Содержит ли n-й индекс массива размера n размера?

#include <stdio.h> 

int main() 
{ 
    int a[] = {1, 1, 1, 1, 1}; 
    int *ptr = a; 
    for (int i = 0 ; i < 5; i++) 
     printf("%d ", *ptr++); 
    printf("%d", *ptr); 
} 

Как вы можете видеть, после завершения цикла, указатель содержит адрес памяти значения из массива. Поскольку он, то есть последний выход не инициализирован, он должен быть значением мусора. Но каждый раз он показывает 5, размер массива. Затем я подумал, что следующий адрес памяти выделенной памяти для массива содержит размер массива. Но этого не происходит с массивом двойного типа.

Output for int array : 1 1 1 1 1 5 
Output for double array : 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 

Кто-нибудь объяснит выход?

+0

Вы используете i ++, поэтому ptr указывает на область памяти в вашей программе вне массива a. Поскольку вы перекомпилировали для перехода от int к double, я не могу сделать вывод, почему в одном случае вы получаете 5, а в другом случае - ноль. Как double, так и int хранятся как 4 байта, а double - число с плавающей запятой IEEE 488. – jdweng

+0

@jdweng: 1) нет никакого смысла в дальнейшем исследовании неопределенного поведения. 2) double требует не менее 64 бит, т. Е. 8 октетов (если ваши байты не имеют 16 бит, что было бы вполне корректно), проверьте CHAR_BIT) 3) Что такое IEEE488? Обычно C использует плавучую точку IEC 60559 (aka IEEE754). Никогда не заголовок о стандарте, который вы упомянули. Можете ли вы предоставить ссылку? – Olaf

+2

«* Это должно быть значение для мусора *» - это ** ** значение мусора. * «Но каждый раз, когда он показывает 5, который является размером массива. * '-' 5' - мусор. У мусора нет необходимости иметь другое значение каждый раз, когда вы его смотрите, казалось бы, мусор все еще мусор –

ответ

2

Что вы делаете, вызывает Неопределенное поведение.

Это просто совпадение и, вероятно, только значение i, напечатайте адрес i и проверьте. Но будьте осторожны, это не всегда будет так. Просто объявите новую переменную в программе, и она может измениться.

В случае double это не работает, потому что адрес после массива больше не совпадает с адресом i. Это то, что я имею в виду, когда я говорю Будьте осторожны.

+0

Это не может быть просто совпадением. Я запустил код более 20 раз. Я несколько раз перезапускал ID Code ID. Перезагрузил компьютер. Изменен размер массива. И все же я получаю размер в n-й позиции. –

+0

Это зависит от памяти стека от программы, это не изменится только потому, что вы перекомпилируете его или потому, что вы измените размер массива, однако он изменится, если вы измените программу, попробуйте объявить новую переменная 'int' до t он 'for' и дает ему случайное значение, отличное от' 5'. Или, возможно, используйте другой компилятор. –

+2

@ParvezMRobin: Это артефакт того, как компилятор организовал объекты в стеке для этой конкретной программы *. Ваша конкретная коллекция переменных просто возникает, когда она выкладывается таким образом, что (как выглядит) 'i' следует за последним элементом массива. Другой компилятор или один и тот же компилятор с разными настройками оптимизации могут выставлять переменные в другом порядке. Это не определенное поведение, это действительно просто совпадение. –

-3

5 является адрес, поэтому я считаю, что вы код правильный

+3

'5' является адресом чего? –

+4

5 просто счастливое совпадение ... –

+2

@KamenStoykov Не обязательно счастливы, предположим, что ОП не спрашивал и просто предполагал, что это так. Это стало бы грустным совпадением *. –

6

Это просто значение из памяти в этом адресе. Вы никогда не должны получать доступ к памяти, которая не выделена вами (в этом случае вы получаете доступ к 6-му элементу, но вы указали только 5). В некоторых случаях это может привести к ошибке сегментации.

+1

* Ошибка сегментации в некоторых случаях * just -> * undefiend behavior *. –

+0

Да, вы правы –

+0

Это не может быть просто значение из адреса памяти. Я запустил код более 20 раз. Я несколько раз перезапускал ID Code ID. Перезагрузите компьютер. Изменен размер массива. И все же я получаю размер на n-й позиции. –

3

C не сохраняет метаданные массива (включая длину массива) в любом месте, в начале или в конце массива. В случае целочисленного массива, то скорее всего объяснения для вывода является то, что память, используемая переменной i непосредственно следует за последний элемент массива, например так:

+---+ 
a: | 1 | a[0] 
    +---+ 
    | 1 | a[1] 
    +---+ 
    | 1 | a[2] 
    +---+ 
    | 1 | a[3] 
    +---+ 
    | 1 | a[4] 
    +---+ 
i: | 5 | a[5] 
    +---+ 

Однако не может полагаются на согласованность этого поведения, как вы видели при изменении типа массива на double.

Попытка прочитать значение, содержащееся в элементе, расположенном за конец массива, приводит к неопределенным поведением. Chapter and (truncated) verse:

6.5.6 Аддитивные операторы
...
8 Когда выражение, которое имеет целочисленный тип добавляется или вычитается из указателя, то результат имеет тип указателя операнда ... Если результат указывает один за последний элемент объекта массива, он не должен использоваться в качестве операнда унарного оператора *, который оценивается.

Для хихиканье, я составил свой код на моей системе на работе, и я получаю следующий результат:

1 1 1 1 1 0 

Это действительно просто артефакт, как компилятор устанавливает объекты в памяти для этого конкретной программы.