различие между двумя методами объявления массива 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 5

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 байт в вашем случае).

В отличие от b - это только указатель на одно место в памяти. В вашем случае существует блок из 12 байт, который динамически выделяется (через new int[3]). b сам по себе является автоматически выделенным 4-байтовым указателем, который указывает на первый int значение в этом 12-байтовом блоке.

Таким образом, это действительно два разных вида вещей. Это становится менее понятным для программистов C++. Одной из причин этого является тот факт, что вы можете использовать оператор [] для обоих типов. Другая причина заключается в том, что массивы неявно вырождаются в указатели в нескольких ситуациях (например, в функции 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) имеют размеры, ограниченные кучей (которая больше, чем стек).

Есть некоторые существенные преимущества производительности для распределения стека, посмотрите этот поток для получения дополнительной информации: Что быстрее: распределение стека или выделение кучи