Давайте обсудим это в терминах C / C ++;Есть еще кое-что, что нужно знать о массивах C #, но на самом деле это не имеет отношения к делу.
Учитывая массив 16-битных целочисленных значений:
short[5] myArray = {1,2,3,4,5};
На самом деле произошло то, что компьютервыделил блок памяти в памяти.Этот блок памяти зарезервирован для этого массива, он точно соответствует размеру, необходимому для хранения всего массива (в нашем случае 16 * 5 == 80 бит == 10 байт), и является непрерывным.Эти факты даны;если какой-либо из них или ни один из них не соответствует действительности в любой момент времени, вы, как правило, подвержены риску сбоя вашей программы из-за нарушения доступа.
Итак, учитывая эту структуру, какая переменная myArray
на самом деле, это за кадром, это адрес памяти начала блока памяти.Это также, удобно, начало первого элемента.Каждый дополнительный элемент выстраивается в памяти сразу после первого, по порядку.Блок памяти, выделенный для myArray
, может выглядеть следующим образом:
00000000000000010000000000000010000000000000001100000000000001000000000000000101
^ ^ ^ ^ ^
myArray([0]) myArray[1] myArray[2] myArray[3] myArray[4]
Операция с постоянным временем считается для доступа к адресу памяти и считывания постоянного числа байтов.Как и на рисунке выше, вы можете получить адрес памяти для каждого, если знаете три вещи;начало блока памяти, размер памяти каждого элемента и индекс элемента, который вы хотите.Итак, когда вы запрашиваете myArray[3]
в своем коде, этот запрос превращается в адрес памяти по следующему уравнению:
myArray[3] == &myArray+sizeof(short)*3;
Таким образом, при вычислении с постоянным временем вы нашли адрес памятичетвертого элемента (индекс 3) и с помощью другой операции с постоянным временем (или, по крайней мере, рассматриваемой так; фактическая сложность доступа - это детали аппаратного обеспечения и достаточно быстрая, чтобы вам было все равно), вы можете прочитать эту память.Вот почему, если вы когда-нибудь задумывались, почему индексы коллекций в большинстве языков стиля C начинаются с нуля;первый элемент массива начинается с местоположения самого массива, без смещения (sizeof (что-либо) * 0 == 0)
В C # есть два заметных различия.Массивы C # имеют некоторую информацию заголовка, которая используется CLR.Заголовок стоит первым в блоке памяти, и размер этого заголовка является постоянным и известным, поэтому уравнение адресации имеет только одно ключевое отличие:
myArray[3] == &myArray+headerSize+sizeof(short)*3;
C # не позволяет напрямую ссылаться на память вэто управляемая среда, но сама среда выполнения будет использовать что-то подобное для выполнения доступа к памяти из кучи.
Второе, что также характерно для большинства разновидностей C / C ++, заключается в том, что определенные типы всегдаразобрался с "по ссылке".Все, что вам нужно использовать для создания ключевого слова new
, является ссылочным типом (и есть некоторые объекты, такие как строки, которые также являются ссылочными типами, хотя они выглядят как типы значений в коде).Ссылочный тип, когда создается его экземпляр, помещается в память, не перемещается и обычно не копируется.Таким образом, любая переменная, которая представляет этот объект, за кадром является просто адресом памяти объекта в памяти.Массивы являются ссылочными типами (помните, что myArray был просто адресом памяти).Массивы ссылочных типов являются массивами этих адресов памяти, поэтому доступ к объекту, являющемуся элементом массива, является двухэтапным процессом;сначала вы вычисляете адрес памяти элемента в массиве и получаете его.Это еще один адрес памяти, который является местоположением фактического объекта (или, по крайней мере, его изменяемых данных; структура составных элементов в памяти - это совершенно другое).Это все еще операция с постоянным временем;только два шага вместо одного.