Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
A.doc
Скачиваний:
36
Добавлен:
09.04.2015
Размер:
5.6 Mб
Скачать

192 Глава 4

Если вам нужно применять указатель с многомерными массивами, то нужно ясно представлять, что будет происходить. В качестве иллюстрации можете взять массив, объявленный следующим образом:

Вы можете объявить и присвоить значение указателю pbeans так:

Здесь вы устанавливаете указатель на адрес первого элемента массива, который имеет тип double. Вы также можете установить указатель на адрес первой строки массива с помощью следующего оператора:

Это эквивалентно применению имени одномерного массива, который заменяется его адресом. Мы использовали это в предыдущих дискуссиях; однако поскольку beans — двумерный массив, вы не можете присвоить указателю адрес таким оператором:

Проблема заключается в типе. Тип указателя определен как double*, но массив имеет тип double [3] [4]. Указатель, который может сохранить адрес этого массива, должен быть double* [4]. С++ ассоциирует измерения массива с его типом, и опера- тор, приведенный выше, был бы легальным только в том случае, если бы указатель был объявлен вместе с необходимым измерением. Это делается с применением не- сколько более сложной нотации, чем вы видели до сих пор:

Скобки здесь важны; без них это означало бы объявление массива указателей. С таким объявлением предыдущий оператор корректен, но указатель может использо- ваться только для сохранения адресов массивов с указанным измерением.

Нотация указателей с многомерными массивами

Вы можете использовать нотацию указателей с именами массивов для обращения к их элементам. Обратиться к элементам массива beans, который был объявлен ра- нее, и который имеет три строки по четыре элемента, можно двумя способами.

  • Используя имя массива с двумя значениями индексов.

  • Используя имя массива в нотации указателей. Таким образом, следующие два оператора эквивалентны:

Давайте разберемся, как это работает. В первой строке используется нормальная индексация массива для ссылки на элемент со смещением j в строке i массива.

Вы можете определить значение второй строки, разбирая ее изнутри наружу, beans ссылается на адрес первой строки массива, поэтому beans + i ссылается на строку номер i. Выражение * (beans + i) — это адрес первого элемента строки i, по- этому * (beans + i) + j — адрес элемента в строке i со смещением j. Таким образом, полное выражение ссылается на конкретный элемент массива.

Если вы действительно хотите все запутать (хотя это не рекомендуется), то следу- ющие два оператора, в которых смешивается нотация массивов с нотацией указате- лей, также легально ссылаются на тот же элемент массива:

Существует еще один аспект применения указателей, который на самом деле важ- нее всех остальных: возможность динамического выделения памяти для переменных. Мы рассмотрим это в следующем разделе.

Динамическое выделение памяти

Работа с фиксированным набором переменных в программе может серьезно стес- нять разработчика. Часто в приложениях возникает необходимость в оперативном принятии решений относительно динамического выделения места для размещения переменных различных типов непосредственно во время выполнения — в зависимо- сти от входных данных, полученных программой. Для одного набора данных может быть разумно применять большой массив целых чисел, в то время как другой набор входных данных может потребовать большого массива чисел с плавающей точкой. Понятно, что поскольку динамически распределенные переменные не могут быть определены во время компиляции, они не имеют имен в исходном тексте програм- мы. Когда они создаются, то идентифицируются адресами в памяти, которые сохра- няются в указателях. Благодаря мощности указателей и средствам динамического управления памятью в Visual С++ 2005, написание программ, обладающих такого рода гибкостью, выполняется легко и быстро.

Свободное хранилище, псевдоним "куча"

Во многих случаях, когда выполняется ваша программа, у компьютера есть неис- пользуемая память. Эта неиспользуемая память в С++ называется кучей или, иногда, свободным хранилищем. Вы можете выделить память внутри этого хранилища для новой переменной заданного типа с помощью специальной операции С++, которая возвращает адрес выделенного пространства. Этой операцией является new, и ее до- полняет операция delete, которая освобождает память, ранее выделенную new.

Вы можете выделить память в свободной хранилище для некоторой переменной в одной части программы, а затем освободить выделенное пространство и вернуть его в свободное хранилище после того, как необходимость в этой переменной отпадет. Это позволяет позже в той же программе повторно задействовать эту память для дру- гих динамически распределяемых переменных.

Память из свободного хранилища используется всякий раз, когда возникает по- требность в выделении памяти для элементов, которые могут быть определены лишь во время выполнения. Одним из примеров может служить выделение памяти для строк, вводимых пользователем вашего приложения. Нет способа заранее знать, на- сколько большими должны быть эти строки, поэтому имеет смысл выделять память для них во время выполнения, используя для этого операцию new. Позднее вы озна- комитесь с примером применения свободного хранилища для динамического распре- деления памяти массива, где измерения массива задаются пользователем во время работы программы.

Это может быть очень мощная техника, которая позволяет расходовать память очень эффективно, и во многих случаях разрабатывать программы, способные ре- шать намного более масштабные проблемы, обрабатывая большие объемы данных, чем это возможно без ее применения.