Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Указатель на массив или массив указателей



 

Рассмотрим следующие три объявления:

1: Cat Family0ne[500];

2: CAT > > FamilyTwo[500];

3: CAT * FamilyThree = new CAT[500];

В первом случае объявляется массив FamilyOne, содержащий 500 объектов типа CAT. Во втором случае — массив FamilyTwo, содержащий 500 указателей на объекты класса CAT, и в третьем случае — указатель FamilyThree, ссылающийся на массив из 500 объектов класса CAT.

В зависимости от того, какое объявление используется в программе, принципиально меняются способы управления массивом. Как ни странно, но указатель FamilyThree по сути своей гораздо ближе к массиву FamilyOne, но принципиально отличается от массива указателей FamilyTwo.

Чтобы разобраться в этом, следует внимательно рассмотреть, что содержат в себе все эти переменные. Указатель на массив FamilyThree содержит адрес первого элемента массива, но ведь это именно то, что содержит имя массива FamilyOne.

 

Имена массивов и указателей

 

В C++ имя массива представляет собой константный указатель на первый элемент массива. Другими словами, в объявлении

CAT Family[50];

создается указатель Family на адрес первого элемента массива & Family[0].

В программе допускается использование имен массивов как константных указателей и наоборот. Таким образом, выражению Family + 4 соответствует обращение к пятому элементу массива Family[4].

Компилятор выполняет с именами массивов те же математические действия сложения, инкремента и декремента, что и с указателями. В результате операция Family + 4 будет означать не прибавление четырех байтов к текущему адресу, а сдвиг на четыре объекта. Если размер одного объекта равен четырем байтам, то к адресу в имени массива будут добавлены не 4, а 16 байт. Если в нашем примере каждый объект класса CAT содержит четыре переменные-члена типа long по четыре байта каждая и две переменные-члена типа short по два байта каждая, то размер одного элемента массива будет равен 20 байт и операция Family + 4 сдвинет адрес в имени указателя на 80 байт.

Объявление массива в динамической области памяти и его использование показано в листинге 12.7.

Листинг 12.7. Создание массива с использованием ключевого слова new

1: // Листинг 12.7. Массив в динамической области памяти

2:

3: #include < iostream.h>

4:

5: class CAT

6: {

7: public:

8: CAT() { itsAge = 1; itsWeight=5; }

9: ~CAT();

10: int GetAge() const { return itsAge; }

11: int GetWeight() const { return itsWeight; }

12: void SetAge(int age) { itsAge = age; }

13:

14: private:

15: int itsAgo;

16: int itsWeight;

17: };

18:

19: CAT:: ~CAT()

20: {

21: // cout < < " Destructor called! \n";

22: }

23:

24: int main()

25: {

26: CAT * Family = new CAT[500];

27: int i;

28:

29: for (i = 0; i < 500; i++)

30: {

31: Family[i].SetAge(2*i +1);

32: }

33:

34: for (i = 0; i < 500; i++)

35: {

36: cout < < " Cat #" < < i+1 < < ": ";

37: cout < < Family[i].GetAge() < < endl;

38: }

39:

40: delete [] Family;

41:

42: return 0;

43: }

 

Результат:

Cat #1: 1

Cat #2: 3

Cat #3: 5

...

Cat #499: 997

Cat #500: 999

 

Анализ: В строке 26 объявляется массив Family для пятисот объектов класса CAT. Благодаря использованию выражения new CAT[500] весь массив сохраняется в области динамической памяти.

 

Удаление массива из области динамической памяти

 

Куда деваются при удалении массива все эти объекты класса CAT, показанные в предыдущем разделе? Не происходит ли здесь утечка памяти? Удаление массива Family с помощью оператора delete[ ] (не забудьте установить квадратные скобки) освобождает все ячейки памяти, отведенные для него. Компилятор достаточно сообразительный, чтобы удалить из памяти все объекты удаляемого массива и освободить динамическую память для нового использования.

Чтобы убедиться в этом, измените размер массива в предыдущей программе с 500 на 10 в строках 26, 29 и 34. Затем разблокируйте выражение в строке 21 с оператором cout и запустите программу. Когда будет выполнена строка 43, последует десять вызовов деструктора для удаления каждого объекта класса CAT в массиве Family.

Создавая какой-либо объект в области динамической памяти с помощью ключевого слова new, всегда удаляйте его из памяти с помощью оператора delete, если этот объект больше не используется в программе. В случае создания массива в области динамического обмена выражением new < class> [size] удалять его из памяти нужно оператором delete[]. Квадратные скобки указывают, что удаляется весь массив.

Если вы забудете установить квадратные скобки, то из памяти будет удален только первый объект массива. В этом можно убедиться, если в нашем примере программы удалить квадратные скобки в строке 38. Если уже были внесены изменения в строку 21, как указывалось выше, то при выполнении программы на экране отобразится вызов только одного деструктора объекта, который удалит первый объект массива. Поздравляем вас! Вы потеряли огромный блок памяти для дальнейшего использования программой.

 

Рекомендуется: Помните, что для обращения к массиву из n элементов используются индексы от 0 до n-1. Используйте свойства математических операций с указателями для управления доступом к элементам массива.

 

Не рекомендуется: Не записывайте данные за пределы массива. Не путайте массив указателей с указателем на массив.

 

Массивы символов

 

Строка текста представляет собой набор символов. Все строки, которые до сих пор использовались нами в программах, представляли собой безымянные строковые константы, используемые в выражениях с оператором cout, такие как:

cout < < " hello world.\n";

Но в C++ строку можно представить как массив символов, заканчивающийся кон- цевьш нулевым символом строки. Такой массив можно объявить и инициализировать точно так же, как любой другой массив, например:

char Greeting[ ] = { 'H', 'e', ' 1', 'Г, 'o', ' ', 'W', 'o', 1 r', '1', 'd', 1 \0' };

В последний элемент массива заносится нулевой концевой символ строки (\0), который многие функции C++ распознают как символ разрыва строки. Хотя метод ввода строки текста в массив символ за символом работает нормально, это довольно утомительная процедура, чреватая ошибками. К счастью, C++ допускает упрощенный метод ввода строк текста в массивы:

char Greeting[] = " hello world";

Обратите внимание на два момента данного синтаксиса.

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

• Нет необходимости добавлять концевой нулевой символ, так как компилятор сделает это автоматически.

Строка Hello World займет 12 байт. Пять байтов пойдет на слово Hello, пять на слово World и по одному байту на пробел и концевой нулевой символ.

Инициализацию строкового массива можно оставить на потом. При этом, также как и с другими массивами, нужно следить, чтобы затем в массив не было записано символов больше, чем отводилось для этого места.

В листинге 12.8 показан пример использования массива символов, который инициализируется строкой, вводимой пользователем с клавиатуры.

Листинг 12.8. Заполнение массива символами

1: //Листинг 12.8. Заполнение массива символами

2:

3: #include < iostream.h>

4:

5: int main()

6: {

7: char buffer[80];

8: cout < < " Enter the string: ";

9: cin > > buffer;

10: cout < < " Here is' the buffer: " < < buffer < < endl;

11: return 0;

12: }

 

Результат:

Enter the string: Hello World

Here's the buffer: Hello

 

Анализ: В строке 7 объявляется массив buffer, рассчитанный на 80 символов. Taкой массив может содержать строку из 79 букв, включая пробелы, плюс нулевой концевой символ строки.

В строке 8 пользователю предлагается ввести строку текста, которая копируется в массив buffer в строке 9. Метод cin автоматически добавит нулевой концевой символ в конце введенной строки.

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

Чтобы решить эти проблемы, нужно использовать метод get(), применяемый вместе с оператором cin: cin, get(). Для выполнения метода нужно задать три параметра.

• Буфер ввода.

• Максимальное число символов.

• Разделительный символ прерывания ввода.

По умолчанию в качестве разделительного задается символ разрыва строки. Использование этого метода показано в листинге 12.9.

Листинг 12.9. Заполнение массива

1: //Листинг 12.9. Использование метода cin.get()

2:

3: #include < iostream.h>

4:

5: int main()

6: {

7: char buffer[80];

8: cout < < " Enter the string: ";

9: cin.get(buffer, 79); // ввод завершается после 79 символа или символа разрыва строки

10: cout < < " Here's the buffer: " < < buffer < < endl;

11: return 0;

12: }

 

Результат:

Enter the string: Hello World

Here's the buffer: Hello World

 

Анализ: В строке 9 осуществляется вызов метода cin.get(). Буфер ввода, заданный в строке 7, передается в функцию как первый аргумент. Второй аргумент задает максимальную длину строки, равную 79 символам. Допускается ввод только 79 символов, поскольку последний элемент массива отводится на концевой нулевой символ строки. Устанавливать третий аргумент не обязательно. В большинстве случаев в качестве разделительного символа подходит задаваемый по умолчанию символ разрыва строки.

 


Поделиться:



Популярное:

  1. A. Холодный двигатель не запускается или запускается плохо
  2. Agrale — бразильская фирма из Кашиас-ду-Сул, производящая небольшие грузовые автомобили, автобусы и сельскохозяйственную технику. Образована в 1962 году.
  3. D-технология построения чертежа. Типовые объемные тела: призма, цилиндр, конус, сфера, тор, клин. Построение тел выдавливанием и вращением. Разрезы, сечения.
  4. Exercise 2: Are these statements true or false? – Истинны или ложны данные высказывания?
  5. I. Если глагол в главном предложении имеет форму настоящего или будущего времени, то в придаточном предложении может употребляться любое время, которое требуется по смыслу.
  6. I.5. Киностилистика и монтаж
  7. II. Книги (по алфавиту авторов или названий)
  8. II.1.2. Глоссарий «Проблем киностилистики»
  9. II.2. Коррекция и реабилитация речевой патологии у детей, страдающих дизартрией
  10. II.3.1. Именной библиографический указатель
  11. II.3.1. ИМЕННОЙ БИБЛИОГРАФИЧЕСКИЙ УКАЗАТЕЛЬ
  12. III. Стабилизация исламского режима в 1980-е гг.


Последнее изменение этой страницы: 2017-03-08; Просмотров: 772; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.036 с.)
Главная | Случайная страница | Обратная связь