Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лк8.Операторы управления динамической памятью.docx
Скачиваний:
1
Добавлен:
22.11.2019
Размер:
44.32 Кб
Скачать

Основы практического программирования. Лекция №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").