
- •Статические массивы. Материал из Викиучебника
- •Инициализация
- •Использование массивов
- •Многомерные массивы
- •Операторы управления динамической памятью
- •Как это делалось в Си
- •Операторы new и delete
- •Классы, использующие свободную память
- •Возникающие проблемы
- •Решение проблемы
- •Когда используются присваивание и копирующий конструктор
- •Использование модификатора const
Основы практического программирования. Лекция №8. 25 октября 2012
Статические массивы. Материал из Викиучебника
http://ru.wikibooks.org/wiki/%D0%A1%D0%B8%2B%2B#.D0.A1.D1.82.D0.B0.D1.82.D0.B8.D1.87.D0.B5.D1.81.D0.BA.D0.B8.D0.B5_.D0.BC.D0.B0.D1.81.D1.81.D0.B8.D0.B2.D1.8B:_.D1.87.D1.82.D0.BE_.D0.B4.D0.B0_.D0.BA.D0.B0.D0.BA.3F
Массив — это несколько значений одного типа, расположенных в памяти последовательно. Зная местоположение первого из этих элементов, можно обратиться к любому из них. Порядковый номер элемента в массиве называется индексом.
Массивы — это та часть языка Си, которая не подверглась изменениям в языке в Cи++. Поэтому их объявление и работа с ними на обоих этих языках совпадает. Чтобы создать в памяти новый массив, используется такая запись:
int m[10];
int — это тип элементов массива, одинаковый для всех них. Квадратные скобки обозначают, что это массив, целое число в скобках (обязательно константа, известная на момент компиляции) — его размер, т.е. количество элементов. m — это имя переменной-массива. Важно заметить, что в Cи/Cи++ типы "массив" и "указатель" тесно связаны, а именно: массив практически всегда автоматически приводится к указателю на свой первый элемент. Поэтому в функцию, которая требует указатель, можно передавать массив:
void MyFunc( int *arr );
MyFunc(m);
С другой стороны, среди формальных параметров функции можно объявить и обычный массив, и даже массив без указания размера. Если тип параметра — T[N] или T[], то он автоматически меняется на T*. Так что следующие три объявления функций абсолютно идентичны:
void MyFunc1( int *arr ); // компилятор посчитает
void MyFunc2( int arr[] ); // эти три объявления
void MyFunc3( int arr[15] ); // абсолютно идентичными
Однако можно передать массив по ссылке, так как для параметров-ссылок таких замен не производится:
void MyFunc4( int (&arr)[15] ); /* Сюда можно передать массив из 15 элементов типа int (но ни из какого другого количества)*/
void MyFunc5( int (&arr)[3] ); /* А сюда можно передать массив из 3 элементов типа int *. Указатели сюда передавать нельзя. Менять параметры внутри функций тоже нельзя, так как они являются псевдонимами массивов, а не указателями. */
Если нужно передать массив по значению, то нужно объявить структуру с полем типа массив и передавать объект этой структуры.
Имя переменной-массива трактуется тождественно указателю на первый элемент только в value context.
К value context не относятся:
а) аргумент операций sizeof, typeid
б) lvalue context — т.е. левый операнд присваивания, операнд операции адресации &, инкремента/декремента ++/--, аргумент конструктора ссылки, как частный случай — аргумент для функции, ожидающей ссылку в качестве параметра и т. д.
sizeof() массива запрещен для массивов с хотя бы одним неуказанным размером, и является размером всего массива в ином случае. sizeof() указателя имеет совсем иной смысл.
Операции ++/-- и использование слева от присваивания для массива запрещены. Операция адресации, применённая к массиву (как и ко всякой lvalue) возвращает его адрес, численно равный указателю на первый элемент массива, но имеющий другой тип: указатель на массив, а не указатель на элемент. Например, для массива mas из трёх элементов типа int верно
typeid(&mas) == typeid(int(*)[3])
typeid((int*)mas) == typeid(int*),
при этом
(void*)&mas == (void*)(int*)mas
Следует отметить, что операция индексации [] применяется именно к указателям, а не к массивам, и x[y] тождественно равно *(x + y) (где один из х и у — указатель, а другой — целое). То есть в контекстах mas[i] и i[mas] происходит автоматическое приведение типа mas к int*.
Страуструп отмечал, что понятие массива в Си (которое было взято в Си++ без изменений) является слабым местом, так, например, невозможно различать указатель на элемент массива и на одиночный объект. Потому в Си++ для массивов настоятельно рекомендуется использовать std::vector<T>
Но при всём том, массив и указатель — это различные типы. Так, если написать в одном файле
int a[10];
а в другом
extern int *a;
— компилятор, скорее всего, выдаст Вам ошибку (компилятор об этом даже не узнает, ошибку даст линкер, и только в том случае, если переменная объявлена вне блока extern "C").