различие между двумя методами объявления массива c++
Это один из 2-х возможных способов объявления массивов (и выделения памяти для них) в c++
1. int a[3];
2. int *b = new int[3];
Я хочу понять, как c++ относится к этим двум по-разному.
A. В обоих случаях я могу обращаться к массиву со следующим синтаксисом: a[1]
и b[1]
B. Когда я пытаюсь cout<< a
и cout<< b
, оба печатают адреса первого элемента соответствующих массивов.
Мне кажется, что и a, и b рассматриваются как указатели на первые элементы массивы.
Но странно, когда я пытаюсь сделатьcout << sizeof(a)
и sizeof(b)
, они печатают разные значения - 4 и 12 соответственно.
Я не понимаю, почему в случае sizeof(b)
печатается размер всего массива.
5 ответов:
a
является массивом (типint [3]
)b
является указателем (Типint*
)В C++ это совершенно разные вещи.
Массив
Единственное, что объединяет массивы и указатели, - это то, что массивы часто "распадаются" на указатели в нескольких ситуациях. Вот что происходит, когда вы распечатываете их стоимость.sizeof
- это число элементов, умноженное на размер каждого элемента.
Указательsizeof
A не зависит от размера массива (обычно 4 или 8 байт).
Как вы заметили, это кажется, как будто оба
Разница между ними едва заметна при написании (или чтении) кода. Переменнаяa
иb
являются указателями на начало массива. Но в действительности толькоb
является указателем.a
на самом деле является массивом.a
рассматривается как регулярная переменная (так же, какint
илиdouble
), поскольку ей автоматически выделяется часть памяти. Для сравнения предположим, что вы объявилиint i
. Переменнаяi
является имя, данное определенному набору смежных байтов в памяти для хранения целого значения (4 байта на вашем компьютере). Аналогично,a
- это имя, данное набору смежных байтов, который содержит Ваш массив (12 байт в вашем случае).В отличие от
Таким образом, это действительно два разных вида вещей. Это становится менее понятным для программистов C++. Одной из причин этого является тот факт, что вы можете использовать операторb
- это только указатель на одно место в памяти. В вашем случае существует блок из 12 байт, который динамически выделяется (черезnew int[3]
).b
сам по себе является автоматически выделенным 4-байтовым указателем, который указывает на первыйint
значение в этом 12-байтовом блоке.[]
для обоих типов. Другая причина заключается в том, что массивы неявно вырождаются в указатели в нескольких ситуациях (например, в функцииvoid Foo(int a[3]);
,a
на самом деле это не массив, а указатель на начало массива). Но не обманывайтесь - массивы-это, а не указатели (как утверждают многие люди), и указатели-это определенно не массивы.
1 выделяется в стеке. Массивы в стеке должны иметь размер, известный во время компиляции.
2 выделяется на куче. Массивы в куче не имеют такого требования. Помните, если вы выделяете с помощью
new[]
, вам нужно освободить его позже с помощьюdelete[]
:int* b = new int[3]; delete[] b;
Массивы C++ в стеке имеют ограничение, которое
int array[10]; sizeof(array) needs to be compile-time constant and sizeof(array[0])==sizeof(array[1])==...==sizeof(array[9])
Массивы C++ в куче имеют только 2-е ограничение, но не первое. (это позволяет определять размер массива во время выполнения)
Массивы стека (#1) имеют размеры, ограниченные стеком. Массивы кучи (#2) имеют размеры, ограниченные кучей (которая больше, чем стек).
Есть некоторые существенные преимущества производительности для распределения стека, посмотрите этот поток для получения дополнительной информации: Что быстрее: распределение стека или выделение кучи