Си++: различия между версиями

Содержимое удалено Содержимое добавлено
Строка 195:
 
TODO: главное отличие перечислений Си++ от Си.
 
=== Статические массивы: что да как? ===
 
Массив является одним из ключевых понятий программирования. Итак, массив - это несколько значений одного типа, расположенных в памяти рядом. Зная местоположение первого из этих элементов, можно обратиться к любому из них. Порядковый номер элемента в массиве называется <i>индексом</i>.
 
==== Объявление массивов на Си ====
 
Массивы - это та часть языка Си, которая не подверглась изменениям при эволюционировании языка в C++. Поэтому их объявление и работа с ними на обоих этих языках совпадает. Чтобы создать в памяти новый массив, используется такая запись:
<font color="blue">int</font> m[<font color="green">10</font>];
<tt>int</tt> - это тип элементов массива, одинаковый для всех них. Конечно, Вы можете использовать любой другой тип (кроме <tt>void</tt>), чтобы задавать массивы. Квадратные скобки обозначают, что это массив, целое число в скобках (обязательно константа, известная на момент компиляции) - его размер, т.е. количество элементов. <i>M<i> - это имя нашей переменной-массива. Важно заметить, что в C/C++ типы <i>"массив"</i> и <i>"указатель"</i> полностью идентичны, поэтому в функцию, которая требует указатель вполне законно передавать массив:
<font color="blue">void</font> MyFunc( <font color="blue">int</font> *arr );
MyFunc(m);
 
==== Инициализация ====
 
Если создаётся глобальный массив, то изначально все его элементы по умолчанию нули, однако зачастую возникает необходимость присвоить им другие начальные значения. Процесс присваивания начальных значений и называется <i>инициализацией</i>. В C/C++ инициализация осуществляется с помощью знака =, который пишется после имени переменной. Этот знак не есть оператор присваивания, поэтому если Вы будете таким образом инициализировать экземпляры классов, то будет вызван копирующий конструктор, а не функция <tt>operator=</tt>.
<font color="blue">double</font> dbl = <font color="green">1.0</font>; <font color="gray">/* инициализация простой переменной */</font>
<font color="blue">double</font> *m[<font color="green">5</font>] = {NULL, NULL, &dbl}; <font color="gray">/* инициализация массива указателей */</font>
Как видно из данного примера, значения для инициализации массива пишутся через запятую, причём вся группа значений берётся в фигурные скобки. Если указано <i>n</i> значений для инициализации, и <i>n</i> меньше часла элементов в массиве, то первые <i>n</i> элементов инициализируется согласно списку значений, а остальные эементы становятся нулями. То есть, массив <i>m</i> после инициализации будет выглядеть таким образом: <tt>NULL</tt>(0), <tt>NULL</tt>(0), &<i>dbl</i>, 0(<tt>NULL</tt>), 0(<tt>NULL</tt>).
 
Кроме указанного способа, массив символов можно инициализировать непосредственно с помощью строкового литерала:
<font color="blue">char</font> str[<font color="green">10</font>] = <font color="green">"Aspid"</font>;
Но при этом надо помнить, что длина строки на самом деле на единицу больше, чем видимое число символов в ней, поскольку она содержит ещё и символ завершаещего нуля.
 
Наконец, инициализация массива позволяет избежать явного объявления размера. Массив автоматически будет создан такого размера, сколько элементов содержится в списке инициализации:
<font color="blue">int</font> m[] = {<font color="green">2</font>, <font color="green">4</font>, <font color="green">6</font>}; <font color="gray">/* создаётся массив из трёх элементов */</font>
 
==== Использование массивов ====
 
Предположим, у нас имеется массив <i>m</i> (или, что то же самое, указатель на его начало). Как нам обратиться к самому первому его элементу? Ко второму? К (<i>k</i> + 1)-му? Правильно, так:
*m
*(m + 1)
*(m + k)
Вот это число, которое прибавляется к указателю <i>m</i>, и есть индекс элемента в массиве. В языках C/C++ индексация массива начинается с нуля, поэтому самый первый элемент массива всегда имеет индекс 0. К счастью, язык предоставляет гораздо более удобное средство обращения к элементу с индексом <i>k</i>, а именно, квадратные скобки:
m[k] = <font color="green">17</font>;
В данном примере в ячейку с индексом <i>k</i> записывается число 17. Существует так же альтернативный способ записи, который приводит к ровно такому же результату. Возможность такой записи вытекает из коммутативности сложения указателя и целого числа. Вот он, этот альтернативный способ:
k[m] = <font color="green">17</font>;
<font color="green">0</font>[&x] = x; <font color="gray">// контрольный вопрос : что делает эта строчка?</font>
Правда, я ещё ни разу не видел, чтобы такая экзотическая запись где-нибудь использовалась.
 
=== Операторы управления динамической памятью ===
 
При написании серьезных проектов всегда возникает необходимость выделить допонительный кусок памяти. Динамическая память - это отнюдь не "барство дикое", а необходимый инструмент. Просто зачастую (например, если мы описываем деревья или списки) изначально нам неизвестно, сколько ячеек памяти может понадобиться. На самом деле, такая пробема существуетбыла на всем протяжении существования науки/искусства программирования, поэтому неудивительно, что ещё в Си былы функции для динамической работой с памятью.
 
==== Как это делалось в старом добром Си ====
 
В Си для этого было две главных функции: одна называлась <tt>malloc()</tt> и выделяла непрерывный кусок памяти, другая, <tt>free()</tt>, этот кусок освобождала. Вот как выгядит код на Си для работы с динамической памятью (она на жаргоне называется <i>кучей</i>, <i>heap</i>):
<font color="blue">int</font> *Piece;
Piece = malloc(<font color="blue">sizeof</font>(<font color="blue">int</font>)); <font color="gray">/* аргумент функции malloc() - число байт, которые надо выделить */</font>
<font color="blue">if</font> (Piece == NULL) <font color="gray">/* malloc() возвращает NULL, если не может выделить память */</font>
{
printf(<font color="green">"Ошибка выделения памяти: видимо, недостаточно места в ОЗУ\n"</font>)
<font color="blue">return</font>;
}
. . .