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


Это равнозначно поэлементной инициализации.



char str [7] = {'п', 'р', 'и', 'в', 'е', 'т', '0'};

Поскольку в C++ строки должны завершаться нулевым символом, убедитесь, что при объявлении массива его размер указан с учетом признака конца. Именно поэтому в предыдущем примере массив str объявлен как 7-элементный, несмотря на то, что в слове " привет" только шесть букв. При использовании строкового литерала компилятор добавляет нулевой признак конца строки автоматически.

Многомерные массивы инициализируются по аналогии с одномерными. Например, в следующем фрагменте программы массив sqrs инициализируется числами от 1 до 10 и квадратами этих чисел.

int sqrs[10][2] = {

  1, 1,

  2, 4,

  3, 9,

  4, 16,

  5, 25,

  6, 36,

  7, 49,

  8, 64,

  9, 81,

  10, 100

};

Теперь рассмотрим, как элементы массива sqrs располагаются в памяти (рис. 5.2).

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

int sqrs[10][2] = {

  {1, 1},

  {2, 4},

  {3, 9},

  {4, 16},

  {5, 25},

  {6, 36},

  {7, 49},

  {8, 64},

  {9, 81},

  {10, 100}

};

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

В следующей программе массив sqrs используется для поиска квадрата числа, введенного пользователем. Программа сначала выполняет поиск заданного числа в массиве, а затем выводит соответствующее ему значение квадрата.

#include < iostream>

using namespace std;

int sqrs[10][2] = {

  {1, 1},

  {2, 4},

  {3, 9},

  {4, 16},

  {5, 25},

  {6, 36},

  {7, 49},

  {8, 64},

  {9, 81},

  {10, 100}

};

Int main()

{

  int i, j;

  cout < < " Введите число от 1 до 10: ";

    cin > > i;

  // Поиск значения i.

  for(j=0; j< 10; j++)

    if(sqrs[j][0]==i) break;

  cout < < " Квадрат числа " < < i < < " равен ";

  cout < < sqrs[j][1];

  return 0;

}

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

#include < iostream>

#include < cstring>

using namespace std;

void f1();

Int main()

{

  f1();

  f1();

  return 0;

}

Void f1()

{

  char s[80]=" Этo просто тест";

  cout < < s;

  strcpy(s, " ИЗМЕНЕНО" ); // Изменяем значение строки s.

  cout < < s;

}

При выполнении этой программы получаем такие результаты.

Это просто тест

ИЗМЕНЕНО

Это просто тест

ИЗМЕНЕНО

В этой программе массив s инициализируется при каждом вызове функции f1(). Тот факт, что при ее выполнении массив s изменяется, никак не влияет на его повторную инициализацию при последующих вызовах функции f1(). Поэтому при каждом входе в нее на экране отображается следующий текст.

Это просто тест

" Безразмерная" инициализация массивов

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

char e1[14] = " Деление на 0";

char е2[23] = " Конец файла";

char еЗ[21] = " В доступе отказано\u1087? ";

Нетрудно предположить, что вручную неудобно подсчитывать символы в каждом сообщении, чтобы определить корректный размер массива. К счастью, в C++ предусмотрена возможность автоматического определения длины массивов путем использования их " безразмерного" формата. Если в инструкции инициализации массива не указан его размер, C++ автоматически создаст массив, размер которого будет достаточным для хранения всех значений инициализаторов. При таком подходе предыдущий вариант инициализации массивов для построения таблицы сообщений об ошибках можно переписать так.

char е1[] = " Деление на 0";

char е2[] = " Конец файла";

char еЗ[] = " В доступе отказано";

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

" Безразмерная" инициализация массивов не ограничивается одномерными массивами. При инициализации многомерных массивов вам необходимо указать все данные, за исключением крайней слева размерности, чтобы С++-компилятор мог должным образом индексировать массив. Используя " безразмерную" инициализацию массивов, можно создавать таблицы различной длины, позволяя компилятору автоматически выделять область памяти, достаточную для их хранения.

В следующем примере массив sqrs объявляется как " безразмерный".

int sqrs[][2] = {

  1, 1,

  2, 4,

  3, 9,

  4, 16,

  5, 25,

  6, 36,

  7, 49,

  8, 64,

  9, 81,

  10, 100

};

Преимущество такой формы объявления перед " габаритной" (с точным указанием всех размерностей) состоит в том, что программист может удлинять или укорачивать таблицу значений инициализации, не изменяя размерности массива.

Массивы строк

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

char str_array[30][80];

Массив строк — это специальная форма двумерного массива символов.

Получить доступ к отдельной строке довольно просто: достаточно указать только левый индекс. Например, следующая инструкция вызывает функцию gets() для записи третьей строки массива str_array.

gets(str_array[2]);

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

// Вводим строки текста и отображаем их на экране.

#include < iostream>

#include < cstdio>

using namespace std;

Int main()

{

  int t, i;

  char text[100][80];

  for(t=0; t< 100; t++) {

    cout < < t < < ": ";

    gets(text[t]);

    if(! text[t] [0]) break; // Выход из цикла по пустой строке.

  }

  // Отображение строк на экране.

  for(i=0; i< t; i++)

    cout < < text[i] < < ' ';

  return 0;

}

Обратите внимание на то, как в программе выполняется проверка на ввод пустой строки. Функция gets() возвращает строку нулевой длины, если единственной нажатой клавишей оказалась клавиша < Enter> . Это означает, что первым байтом в строке будет нулевой символ. Нулевое значение всегда интерпретируется как ложное, но взятое с отрицанием (! ) дает значение ИСТИНА, которое позволяет выполнить немедленный выход из цикла с помощью инструкции break.

Пример использования массивов строк

Массивы строк обычно используются для обработки таблиц данных. Рассмотрим, например, упрощенную базу данных служащих, в которой хранится имя, номер телефона, количество часов, отработанных служащим за отчетный период, и размер почасового оклада для каждого служащего. Чтобы создать такую программу для коллектива, состоящего из десяти служащих, определим четыре массива (из них первые два будут массивами строк).

char name[10][80]; // Массив имен служащих.

char phone[10][20]; // Массив телефонных номеров служащих.

float hours[10]; // Массив часов, отработанных за неделю.

float wage[10]; // Массив окладов.

Чтобы ввести информацию о каждом служащем, воспользуемся следующей функцией enter().

// Функция ввода информации в базу данных.

Void enter()

{

  int i;

  char temp[80];

  for(i=0; i< 10; i++) {

    cout < < " Введите фамилию: ";

      cin > > name[i];

    cout < < " Введите номер телефона: ";

      cin > > phone[i];

    cout < < " Введите количество отработанных часов: ";

      cin > > hours[i];

    cout < < " Введите оклад: ";

      cin > > wage[i];

  }

}

На основании введенных данных можно составить отчет, вычислив заработную плату, которая причитается каждому служащему. Для этого воспользуемся следующей функцией report().

// Отображение отчета.

Void report()

{

  int i;

  for(i=0; i< 10; i++) {

    cout < < name[i] < < ' ' < < phone[i] < < '';

    cout < < " Заработная плата за неделю: " < < wage[i] * hours[i];

    cout < < '';

  }

}

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

// Простая программа ведения базы данных служащих.

#include < iostream>

using namespace std;

char name[10][80]; // Массив имен служащих.

char phone[10] [20]; // Массив телефонных номеров служащих.

float hours[10]; // Массив часов, отработанных за неделю.

float wage[10]; // Массив окладов.

int menu();

void enter(), report();

Int main()

{

  int choice;

  do {

    choice = menu(); // Получаем команду, выбранную пользователем.

    switch(choice) {

      case 0: break;

      case 1: enter();

        break;

      case 2: report();

        break;

      default: cout < < " Попробуйте еще раз.";

    }

  }while(choice! = 0);

  return 0;

}

// Функция возвращает команду, выбранную пользователем.

Int menu()

{

  int choice;

  cout < < " 0. Выход из программы";

  cout < < " 1. Ввод информации";

  cout < < " 2. Генерирование отчета";

  cout < < " Выберите команду: ";

    cin > > choice;

  return choice;

}

// Функция ввода информации в базу данных.

Void enter()

{

  int i;

  char temp[80];

  for(i=0; i< 10; i++) {

    cout < < " Введите фамилию: ";

      cin > > name[i];

    cout < < " Введите номер телефона: ";

      cin > > phone[i];

    cout < < " Введите количество отработанных часов: ";

      cin > > hours[i];

    cout < < " Введите оклад: ";

      cin > > wage[i];

  }

}

// Отображение отчета.

Void report()

{

  int i;

  for(i=0; i< 10; i++) {

    cout < < name[i] < < ' ' < < phone[i] < < '';

    cout < < " Заработная плата за неделю: " < < wage[i] * hours[i];

    cout < < '';

  }

}


Глава 6: Указатели

Указатели, без сомнения, — один из самых важных и сложных аспектов C++. В значительной степени мощь многих средств C++ определяется использованием указателей. Например, благодаря им обеспечивается поддержка связных списков и динамического выделения памяти, и именно они позволяют функциям изменять содержимое своих аргументов. Однако об этом мы поговорим в последующих главах, а пока (т.е. в этой главе) мы рассмотрим основы применения указателей и покажем, как можно избежать некоторых потенциальных проблем, связанных с их использованием.

При рассмотрении темы указателей нам придется использовать такие понятия, как размер базовых С++-типов данных. В этой главе мы предположим, что символы занимают в памяти один байт, целочисленные значения — четыре, значения с плавающей точкой типа float — четыре, а значения с плавающей точкой типа double — восемь (эти размеры характерны для типичной 32-разрядной среды).

Что представляют собой указатели

Указатели — это переменные, которые хранят адреса памяти. Чаще всего эти адреса обозначают местоположение в памяти других переменных. Например, если х содержит адрес переменной у, то о переменной, х говорят, что она " указывает" на у.

Указатель — это переменная, которая содержит адрес другой переменной.

Переменные-указатели (или переменные типа указатель) должны быть соответственно объявлены. Формат объявления переменной-указателя таков:

тип *имя_переменной;

Здесь элемент тип означает базовый тип указателя, причем он должен быть допустимым С++-типом. Элемент имя_переменной представляет собой имя переменной-указателя. Рассмотрим пример. Чтобы объявить переменную р указателем на int-значение, используйте следующую инструкцию.

int *р;

Для объявления указателя на float-значение используйте такую инструкцию.

float *р;

В общем случае использование символа " звездочка" (*) перед именем переменной в инструкции объявления превращает эту переменную в указатель.

Базовый тип указателя определяет тип данных, на которые он будет ссылаться.

Тип данных, на которые будет ссылаться указатель, определяется его базовым типом. Рассмотрим еще один пример.

int *ip; // указатель на целочисленное значение

double *dp; // указатель на значение типа double

Как отмечено в комментариях, переменная ip — это указатель на int-значение, поскольку его базовым типом является тип int, а переменная dp — указатель на double-значение, поскольку его базовым типом является тип double, Следовательно, в предыдущих примерах переменную ip можно использовать для указания на int-значения, а переменную dp на double-значения. Однако помните: не существует реального средства, которое могло бы помешать указателю ссылаться на " бог-знает-что" . Вот потому-то указатели потенциально опасны.

Операторы, используемые с указателями

С указателями используются два оператора: " *" и " & " Оператор " & " — унарный. Он возвращает адрес памяти, по которому расположен его операнд. (Вспомните: унарному оператору требуется только один операнд.) Например, при выполнении следующего фрагмента кода

balptr = & balance;

в переменную balptr помещается адрес переменной balance. Этот адрес соответствует области во внутренней памяти компьютера, которая принадлежит переменной balance. Выполнение этой инструкции никак не повлияло на значение переменной balance. Назначение оператора можно " перевести" на русский язык как " адрес переменной", перед которой он стоит. Следовательно, приведенную выше инструкцию присваивания можно выразить так: " переменная balptr получает адрес переменной balance" . Чтобы лучше понять суть этого присваивания, предположим, что переменная balance расположена в области памяти с адресом 100. Следовательно, после выполнения этой инструкции переменная balptr получит значение 100.

Второй оператор работы с указателями (*) служит дополнением к первому (& ). Это также унарный оператор, но он обращается к значению переменной, расположенной по адресу, заданному его операндом. Другими словами, он ссылается на значение переменной, адресуемой заданным указателем. Если (продолжая работу с предыдущей инструкцией присваивания) переменная balptr содержит адрес переменной balance, то при выполнении инструкции

value = *balptr;

переменной value будет присвоено значение переменной balance, на которую указывает переменная balptr. Например, если переменная balance содержит значение 3200, после выполнения последней инструкции переменная value будет содержать значение 3200, поскольку это как раз то значение, которое хранится по адресу 100. Назначение оператора " *" можно выразить словосочетаинем " по адресу" . В данном случае предыдущую инструкцию можно прочитать так: " переменная value получает значение (расположенное) по адресу balptr" . Действие приведенных выше двух инструкций схематично показано на рис. 6.1.

Последовательность операций, отображенных на рис. 6.1, реализуется в следующей программе.

#include < iostream>

using namespace std;

Int main()

{

  int balance;

  int *balptr;

  int value;

  balance = 3200;

  balptr = & balance;

  value = *balptr;

  cout < < " Баланс равен: " < < value < < '';

  return 0;

}

При выполнении этой программы получаем такие результаты:

Баланс равен: 3200

К сожалению, знак умножения (*) и оператор со значением " по адресу" обозначаются одинаковыми символами " звездочка" , что иногда сбивает с толку новичков в языке C++. Эти операции никак не связаны одна с другой. Имейте в виду, что операторы " *" и " & " имеют более высокий приоритет, чем любой из арифметических операторов, за исключением унарного минуса, приоритет которого такой же, как у операторов, применяемых для работы с указателями.


Поделиться:



Популярное:

  1. B. 1. В США говорят по-английски. 2. Эта сумка сделана из кожи. 3. Окно разбито. 4. Владимир был построен в 10 веке. 5. Масло и сыр делают из молока. 6.Этот дом был построен моим дедом.
  2. S:Укажите вид предложения: Рассказать об этом человеке хотелось так, чтобы придерживаться фактов и чтобы было интересно. (Д.Гранин)
  3. V. ВОСПРИЯТИЕ ОКРУЖАЮЩЕЙ ДЕЙСТВИТЕЛЬНОСТИ. РОЛЬ СЛУХА В ЭТОМ ПРОЦЕССЕ
  4. А. Деньги – это всеобщий эквивалент стоимости товаров и услуг.
  5. Административное право – это совокупность правовых норм, регулирующих управленческую деятельность органов исполнительной власти.
  6. Аквабайкинг - Преднамеренное катание в аццкий дождь со всеми вытекающими. Традиционно все участники при этом остаются крайне довольны катушкой
  7. Аналогия — это зеркало, но не волшебное
  8. База данных – это поименованная совокупность структурированных данных некоторой предметной области.
  9. Безусловно, этот метод применим и к текстовым файлам.
  10. Богатые горожанки узнают об этом происшествии
  11. Болезни — это результат чревоугодия
  12. В конце XX столетия предложения этого ученого выглядят как никогда кстати.


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


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