Структуры
Структуры – это не что иное, как классы, у которых разрешен доступ ко всем их элементам. Пример структуры:
struct Record { int number; char name[20];};Так же, как и для классов, операция "." обозначает обращение к элементу структуры.
В отличие от классов, можно определить переменную - структуру без определения отдельного типа:
struct { double x; double y;} coord;Обратиться к атрибутам переменной coord можно coord.x и coord.y.
Битовые поля
В структуре можно определить размеры атрибута с точностью до бита. Традиционно структуры используются в системном программировании для описания регистров аппаратуры. В них каждый бит имеет свое значение. Не менее важной является возможность экономии памяти – ведь минимальный тип атрибута структуры это байт (char), который занимает 8 битов. До сих пор, несмотря на мегабайты и даже гигабайты оперативной памяти, используемые в современных компьютерах, существует немало задач, где каждый бит на счету.
Если после описания атрибута структуры поставить двоеточие и затем целое число, то это число задает количество битов, выделенных под данный атрибут структуры. Такие атрибуты называют битовыми полями. Следующая структура хранит в компактной форме дату и время дня с точностью до секунды.
struct TimeAndDate{unsigned hours:5; // часы от 0 до 24 unsigned mins:6; // минуты unsigned secs:6; // секунды от 0 до 60unsigned weekDay:3; // день неделиunsigned monthDay:6; // день месяца от 1 до 31unsigned month:5; // месяц от 1 до 12unsigned year:8; // год от 0 до 100 };Одна структура TimeAndDate требует всего 39 битов, т.е. 5 байтов (один байт — 8 битов). Если бы мы использовали для каждого атрибута этой структуры тип char, нам бы потребовалось 7 байтов.
Для того чтобы работать с текстом, в языке Си++ не существует особого встроенного типа данных. Текст представляется в виде последовательности знаков (байтов), заканчивающейся нулевым байтом. Иногда такое представление называют Си-строки, поскольку оно появилось в языке Си. Кроме того, в Си++ можно создать классы для более удобной работы с текстами (готовые классы для представления строк имеются в стандартной библиотеке шаблонов).
Строки представляются в виде массива байтов:
char string[20];string[0] = 'H';string[1] = 'e';string[2] = 'l';string[3] = 'l';string[4] = 'o';string[5] = 0;В массиве string записана строка "Hello". При этом мы использовали только 6 из 20 элементов массива.
Для записи строковых констант в программе используются литералы. Литерал – это последовательность знаков, заключенная в двойные кавычки:
"Это строка""0123456789""*"Заметим, что символ, заключенный в двойные кавычки, отличается от символа, заключенного в апострофы. Литерал "*" обозначает два байта: первый байт содержит символ звездочки, второй байт содержит ноль. Константа '*' обозначает один байт, содержащий знак звездочки.
С помощью литералов можно инициализировать массивы:
char alldigits[] = "0123456789";Размер массива явно не задан, он определяется исходя из размера инициализирующего его литерала, в данном случае 11 (10 символов плюс нулевой байт).
При работе со строками особенно часто используется связь между массивами и указателями. Значение литерала – это массив неизменяемых байтов нужного размера. Строковый литерал может быть присвоен указателю на char:
const char* message = "Сообщение программы";Значение литерала – это адрес его первого байта, указатель на начало строки. В следующем примере функция CopyString копирует первую строку во вторую:
voidCopyString(char* src, char* dst){ while (*dst++ = *src++); *dst = 0;}intmain(){ char first[] = "Первая строка"; char second[100]; CopyString(first, second); return 1;}Указатель на байт (тип char*) указывает на начало строки. Предположим, нам нужно подсчитать количество цифр в строке, на которую показывает указатель str:
#include <ctype.h>int count = 0; while (*str!= 0) { // признак конца строки – ноль if (isdigit(*str++)) /* проверить байт, на который указывает str, и сдвинуть указатель на следующий байт */ count++; }При выходе из цикла while переменная count содержит количество цифр в строке str, а сам указатель str указывает на конец строки – нулевой байт. Чтобы проверить, является ли текущий символ цифрой, используется функция isdigit. Это одна из многих стандартных функций языка, предназначенных для работы с символами и строками.
С помощью функций стандартной библиотеки языка реализованы многие часто используемые операции над символьными строками. В большинстве своем в качестве строк они воспринимают указатели. Приведем ряд наиболее употребительных функций. Прежде чем использовать эти указатели в программе, нужно подключить их описания с помощью операторов:
#include <string.h>
#include <ctype.h>
char* strcpy(char* target, const char* source);В примере показано копирование строки source по адресу target, включая завершающий нулевой байт. Функция предполагает, что памяти, выделенной по адресу target, достаточно для копируемой строки. В качестве результата функция возвращает адрес первой строки.
char* strcat(char* target, const char* source);В последнем примере показано присоединение второй строки к концу первой, включая завершающий нулевой байт. На место завершающего нулевого байта первой строки переписывается первый символ второй строки. В результате по адресу target получается строка, образованная слиянием первой со второй. В качестве результата функция возвращает адрес первой строки.
int strcmp(const char* string1, const char* string2);Здесь происходит сравнение двух строк в лексикографическом порядке (по алфавиту). Если первая строка должна стоять по алфавиту раньше, чем вторая, то результат функции меньше нуля, если позже – больше нуля, и ноль, если две строки равны. Функция
size_t strlen(const char* string);определяет длину строки в байтах, не считая завершающего нулевого байта.
В следующем примере, использующем приведенные функции, в массиве result будет образована строка "1 января 1998 года, 12 часов":
char result[100];char* date = "1 января 1998 года";char* time = "12 часов";strcpy(result, date);strcat(result, ", ");strcat(result, time);Как видно из этого примера, литералы можно непосредственно использовать в выражениях.
Определить массив строк можно с помощью следующего объявления:
char* StrArray[5] = {"one", "two", "three", "four", "five"};