Читая книгу по C ++ Primer, я натолкнулся на следующее утверждение: «Количество элементов в массиве является частью типа массива». Поэтому я хотел узнать, используя следующий код:
#include<iostream>
int main()
{
char Array1[]{'H', 'e', 'l', 'p'};
char Array2[]{'P', 'l', 'e', 'a', 's', 'e'};
std::cout<<typeid(Array1).name()<<std::endl; //prints A4_c
std::cout<<typeid(Array2).name()<<std::endl; //prints A6_c
return 0;
}
И что интересно, результаты typeid на двух массивах показали, что они как-то разные.
- Что происходит за кулисами?
- Зачем массиву иметь тип, который включает его размер? Это только потому, что его размер не должен меняться?
- Как это повлияет на сравнение массивов?
Просто хочу быть в состоянии глубоко понять концепцию.
Ответы:
Не динамически распределяемый является по определению контейнером однородного элемента фиксированного размера . Массив
N
элементов типаT
размещается в памяти как непрерывная последовательностьN
объектов типаT
.Я не верю, что это необходимо для типа массива, чтобы включить его размер - фактически, вы можете использовать указатель для ссылки на непрерывную последовательность
T
объектов. Такой указатель потерял бы информацию о размере массива.Это, однако, полезно иметь. Это повышает безопасность типов и кодирует полезную информацию во время компиляции, которую можно использовать несколькими способами. Например, вы можете использовать ссылки на массивы для перегрузки массивов разных размеров.
или выяснить размер массива как константное выражение
На самом деле это не так.
Вы не можете сравнивать массивы в стиле C так же, как сравнивали бы два числа (например,
int
объекты). Вам придется написать какое-то лексикографическое сравнение и решить, что это значит для коллекций разных размеров.std::vector<T>
обеспечивает , и та же логика может быть применена к массивам.Бонус: C ++ 11 и выше предоставляет
std::array
обертку вокруг массива в стиле C с контейнероподобным интерфейсом. Следует отдавать предпочтение массивам в стиле C, поскольку они более соответствуют другим контейнерам (напримерstd::vector<T>
), а также поддерживают лексикографические сравнения из коробки.источник
std::equal
(черезstd::begin
иstd::end
которые определены для массивов). В этом случае массивы разных размеров не равны.Объем пространства, выделяемого объекту при его создании, полностью зависит от его типа. Распределение, о котором я говорю, - это не выделения из
new
илиmalloc
, а пространство, выделенное для того, чтобы вы могли запустить свой конструктор и инициализировать свой объект.Если у вас есть структура, определенная как (например)
Затем, когда вы строите объект:
Вы можете думать о процессе построения объекта как о процессе:
'a'
и'b'
в объект)Важно отметить, что 2 байта необходимого пространства полностью определяются типом объекта, аргументы функции не имеют значения. Таким образом, для массива процесс такой же, за исключением того, что теперь необходимое количество места зависит от количества элементов в массиве.
Таким образом, типы
a
иb
должны отражать тот факт, чтоa
нужно достаточно места для 1 символа иb
достаточно места для 5 символов. Это означает, что размер этих массивов не может внезапно измениться: после создания массива из 5 элементов это всегда массив из 5 элементов. Чтобы иметь объекты типа массива, размер которых может варьироваться, вам необходимо динамическое выделение памяти, которое в какой-то момент должно быть покрыто вашей книгой.источник
Это по внутренней причине для библиотеки времени выполнения. Например, если учесть следующие утверждения:
Тогда становится ясно, в чем проблема: например, адресация
unsigned int *
должна касатьсяsizeof operator
или адресацииunsigned int
.Есть более подробное объяснение остальной части того, что вы видите здесь, но это в значительной степени повторение того, что было описано в Языке программирования C, 2-е издание Керниганом и Ричи относительно программы, которая печатает текст на простом языке объявленного типа. строка.
источник