Другие типы данных
7.1. Структуры, объединения и перечисления
Одним из преимуществ "новых" языков программирования (таких как "Паскаль", "Си") является появление "пользовательских" типов данных. В языке Си к таким данным относят структуры, объединения и перечисления. Рассмотрим их поподробнее.
Структура
Структура представляет собой несколько типов данных, расположенных вместе, в соседних ячейках памяти. Структура имеет собственное имя как тип данных, длина ее элемента (в памяти компьютера) вычисляется с помощью функции sizeof (в C и C++). Пример структуры следующий:
[Пример 01]
/* Инициализируем константу */ const unsigned short MAXSTRINGLENGTH = 256; /* Описание структуры stringz */ struct stringz { char string[MAXSTRINGLENGTH]; short nLength; }
Здесь определена структура с именем stringz, содержащая в себе массив string длиной MAXSTRINGLENGTH (в нашем случае - это 256 символов), и целым числом длиной 2 байта nLength, в котором может, например, храниться реальная длина строки.
Объединение
Объединение похоже на структуру, но в ней данные хранятся не вместе друг с другом, а вместо друг друга. Например, в следующем объединении с тегом data:
[Пример 02]
/* Объявление константы const unsigned short STRDATALENGTH = 32: /* Объявление объединения union data{ long intdata; double doubledata; char strdata[STRDATALENGTH]; }
Может храниться либо длинное целое, либо данные с плавающей точкой, либо массив-строка символов длиной 32 байта, причем все - в одних и тех же ячейках памяти. Функция sizeof, примененная к объединению, выдает значение самого длинного типа данных в объединении.
Обращение к элементам структуры и объединения осуществляется либо через знак "." (для переменной), либо знаком "->" (для указателей). Например:
[Пример 03]
/* Инициализируем константу */ const unsigned short MAXSTRINGLENGTH = 256; /* Объявление переменных */ struct stringz aString, *theString; union data aData, *theData; /* Присвоение значений переменным */ aString.nLength = 5; memset(theString -> string, '\0', MAXSTRINGLENGTH); aData.intdata = 1; theData -> doubledata = 7.0;
Перечисления
Перечисления иногда называют именованными типами данных. Их объявление на языке Си следующее:
enum <тег> {<константа 0>, <константа 1>, ... <константа n>};Листинг 7.1.
Например:
[Пример 04]
/* определяет булевский тип данных */ enum boolean {FALSE, TRUE}
Переменные типа "перечисление" представляют собой целые переменные без знака, способные принимать значения только из списка: <константа 0> ... <константа n>, причем первой константе соответствует значение "0".
Переменную перечисления в Си можно привести к целому типу. Обратное действие вызывает неопределенность.
Если Ваш язык не поддерживает перечисления, можно определить целые константы, соответствующие перечислению, и определить целую переменную, которая будет работать только с этими константами. Но это уже должен отслеживать программист, то есть Вы.
[Пример 05]
stringZ$ = "Привет!" stringZ% = 7
В этом примере вместо структуры stringz в языке Quick Basic используются переменные stringZ$ (для хранения символьных данных) и stringZ% для хранения целого числа.
7.2. Составные специальные типы
К составным специальным символьным типам данных автор относит такие типы данных, как класс "string" из библиотеки ClassLib в Borland C/C++, класс "String" стандартной библиотеки языка Java, класс "CString" в библиотеке MFC из пакета Microsoft Visual Studio и т.д. Эти классы частично заменяют такой примитивный символьный тип данных, как массив скаляров char[]. В стандартах на языки C++ и Sun Java 2 наличие таких предопределенных классов является обязательным. В таблице [[C_Tables.xls]07.I.] представлены стандартные методы классов "string" в Borland C/C++, "String" в Sun Java 2, "CString" в Microsoft MFC 2.0 и функции работы с символьными данными в Visual Basic Script.
В примерах [06 - 08] дается реализация алгоритмов Примера 01 "Примитивные символьные данные" с помощью классов "CString", "String" и "string" соответственно.
[Пример 06]
// Определение переменной: <имярек>. CString strImyaRek("Света"); // Определение переменной-результата. Cstring strResult(); // Символьные вычисления. strResult = _T("Привет ") + strImyaRek + _T("! С добрым утром.");
[Пример 07]
// Определение переменной: <имярек>. string strImyaRek("Света"); // Определение переменной-результата. string strResult(); // Символьные вычисления. strResult.append("Привет "); strResult += strImyaRek; strResult.append("! С добрым утром.");
[Пример 08]
// Определение переменной: <имярек>. String strImyaRek("Света"); // Определение временных переменных strPrivet("Привет "); strEnd("! С добрым утром."); // Определение переменной-результата. Cstring strResult(); // Символьные вычисления. strResult = strPrivet + strImyaRek + strEnd;
Подробнее о символьных типах данных смотри следующую литературу:
- примитивные символьные типы языка Си [31];
- пример класса String, определенного в C++ [51];
- диск с учебниками по программированию;
- класс String в Java 2 [74];
- класс CString в MFC 2.0 [Он-лайн руководство по Microsoft Visual C/C++];
- класс string в ClassLib [Он-лайн руководство по Borland C/C++ 5.01];
- описание языка Perl [59].
Замечания, касающиеся "взлома" программ
Реализацию собственных символьных классов следует производить с осторожностью. Если класс закрыт от изменений, но при этом он возвращает свои защищенные значения, то хакер может получить ссылку на этот объект, и, изменяя содержимое этой ссылки, фактически он меняет содержимое этого защищенного элемента класса. Более подробно об этой проблеме смотри примеры в книге [74].
Также к составным специальным символьным типам относят все переменные Perl. Подробнее о типах языках Perl см. "Переменные Perl" .