Битовые поля
Член целого типа может состоять из определенного количества бит. Такой член называется битовым полем (bit field), а число соответствующих бит называется его шириной. Ширина определяется неотрицательным постоянным целым выражением, стоящим после двоеточия. Например:
struct pcard {// сжатое представление карты
unsigned s : 2;
unsigned p : 4;
} ;
Компилятор попытается упаковать битовые поля в памяти последовательно. При этом он может перейти к следующему байту или слову в целях выравнивания. Массивы битовых полей не допускаются. Кроме того, оператор определения адреса & не может быть применен к битовым полям.
Битовые поля используются для удобной адресации информации в упакованном виде. На многих машинах слово состоит из 32 бит, и битовая операция может выполняться параллельно (то есть одновременно со всеми битами слова). В этом случае битовые манипуляции можно использовать как технику реализации множеств, состоящих не более чем из 32 элементов, как показано ниже.
struct word {
unsigned wO:1, wl:1, w2:1, w3:1, w4:1, w5:1, w6:1, w7:1, w8:l, w9:l, wl0:l, wll:l, wl2:l, wl3:l, wl4:1, wl5:l,
wl6:l, wl7:l, wl8:l, wl9:l, w20:l, w21:l, w22:l, w23:l,
w24:l, w25:l, w26:l, w27:l, w28:l, w29:l, w30:l, w31:l;
};
Можно перекрыть word и unsigned в объединении для создания структуры данных, позволяющей манипулировать битами:
union set {
word m;
unsigned u;
};
int main()
{
set x, у ;
x.u = OxOf1Oof1O;
y.u = OxO1a1aOa1;
x.u = x.u | y.u; //объединение множеств
cout << "элемент 9 "
<< ((x.m.w9)? "присутствует" : "отсутствует") « endl;
}
В большинстве систем такая операция объединения множеств выполняется как параллельная операция над словами.
Пример: двумерные динамические массивы
В базовом языке многомерные динамические массивы (dynamic array) недопустимы. В научных, инженерных и других расчетах интенсивно используются двумерные массивы, называемые матрицами (matrix). Было бы неудобно писать специальные процедуры для каждого из возможных размеров матрицы. Соответствующая абстракция может быть реализована следующим образом.
//Двумерный динамический массив
struct twod {
double** base; //базовый адрес int row_size, colunm_size; //размер строки и колонки
};
Лежащая в основе структура данных очень проста. Указатель base является указателем на указатель на double. Указатель base содержит начальный адрес массива указателей, каждый из которых является начальным адресом ряда переменных с двойной точностью.
В следующем фрагменте обратите внимание, что функция allocate () сначала использует new для размещения вектора указателей на колонку, а затем — для размещения строки значений с двойной точностью. Освобождение памяти происходит в обратном порядке.
void allocate(int r, int s, twod& m)
{
in.base = new double*[s];
for (int i = 0; i < s; ++i)
m.base[i] = new double[r];
m.row_size = r;
m.column_size = s;
}
void deal locate(twod& m) {
for (int i = 0; i < m.column_size; ++i)
delete [] m.base[i];
delete [] m.base;
m.row_size =0;
m.column_size = 0;
}
Теперь напишем функцию find_max () — каноническую процедуру для обработки подобных двумерных динамических массивов.
double find_max(const twod& m)
{
int i,j;
double max = m.base[0] [0];
for (i = 0; i < m.column_size; ++ i)
for (j = 0; j < m.row_size; ++ j)
if (m.base[i] [j] > max)
max = m.base[i] [j];
return (max);
}
Обратите внимание как в представленной ниже main ( ) функция find_max ( ) работает с динамически распределенными структурами различного размера:
#include <iostream.h>
int main ( )
{
twod a, b;
int i, j;
allocate (2, 3, a);
allocate (4, 6, b);
for (i = 0; i < a.column_size; ++ i)
for (j = 0; j < a.row_size; ++ j)
a.base [i] [j] = i * j;
for (i = 0; i < b.column_size; ++ i)
for (j = 0; j < b.row_size; ++ j)
b.base [i] [j] = i * j;
cout << find_max (a) << «наибольшее в массиве 2 * 3\n»;
cout << find_max (b) << «наибольшее в массиве 4 * 6\n»;
}
1 В некоторых изданиях термин member применительно к данным переводится как элемент (элемент структуры, элемент данных). – Примеч. перев.