Литмир - Электронная Библиотека
A
A

double ad[3][4];  // 2-мерный массив

char ac[3][4][5]; // 3-мерный массив

ai[1] = 7;

ad[2][3] = 7.2;

ac[2][3][4] = 'c';

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Этот подход наследует все преимущества и недостатки одномерного массива.

• Преимущества

 • Непосредственное отображение с помощью аппаратного обеспечения.

 • Эффективные низкоуровневые операции.

 • Непосредственная языковая поддержка.

• Проблемы

 • Многомерные массивы в стиле языка являются массивами массивов(см. ниже).

 • Фиксированные размеры (например, фиксированные на этапе компиляции). Если хотите определять размер массива на этапе выполнения программы, то должны использовать свободную память.

 • Массивы невозможно передать аккуратно. Массив превращается в указатель на свой первый элемент при малейшей возможности.

 • Нет проверки диапазона. Как обычно, массив не знает своего размера.

 • Нет операций над массивами, даже присваивания (копирования).

Встроенные массивы широко используются в числовых расчетах. Они также являются основным источником ошибок и сложностей. Создание и отладка таких программ у большинства людей вызывают головную боль. Если вы вынуждены использовать встроенные массивы, почитайте учебники (например, The C++ Programming Language, Appendix C, p. 836–840). К сожалению, язык C++ унаследовал многомерные массивы от языка C, поэтому они до сих пор используются во многих программах.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Большинство фундаментальных проблем заключается в том, что передать многомерные массивы аккуратно невозможно, поэтому приходится работать с указателями и выполнять явные вычисления, связанные с определением позиций в многомерном массиве. Рассмотрим пример.

void f1(int a[3][5]);     // имеет смысл только в матрице [3][5]

void f2(int [ ][5], int dim1);  // первая размерность может быть

                                // переменной

void f3(int [5 ][ ], int dim2); // ошибка: вторая размерность

                                // не может быть переменной

void f4(int[ ][ ], int dim1, int dim2); // ошибка (совсем

                                        // не работает)

void f5(int* m, int dim1, int dim2) // странно, но работает

{

  for (int i=0; i<dim1; ++i)

  for (int j = 0; j<dim2; ++j) m[i*dim2+j] = 0;

}

Здесь мы передаем массив

m
как указатель
int*
, даже если он является двумерным. Поскольку вторая переменная должна быть переменной (параметром), у нас нет никакой возможности сообщить компилятору, что массив
m
является массивом (
dim1, dim2
), поэтому мы просто передаем указатель на первую его ячейку. Выражение
m[i*dim2+j]
на самом деле означает
m[i,j]
, но, поскольку компилятор не знает, что переменная
m
— это двумерный массив, мы должны сначала вычислить позицию элемента
m[i,j]
в памяти.

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

24.5. Библиотека Matrix

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Каково основное предназначение массива (матрицы) в численных расчетах?

• “Мой код должен выглядеть очень похожим на описание массивов, изложенное в большинстве учебников по математике”.

 • Это относится также к векторам, матрицам и тензорам.

• Проверка на этапах компиляции и выполнения программы.

 • Массивы любой размерности.

 • Массивы с произвольным количеством элементов в любой размерности.

 • Массивы являются полноценными переменными/объектами.

 • Их можно передавать куда угодно.

• Обычные операции над массивами.

 • Индексирование:

()
.

 • Срезка:

[]
.

 • Присваивание:

=
.

 • Операции пересчета (

+=
,
–=
,
*=
,
%=
и т.д.).

 • Встроенные векторные операции (например,

res[i] = a[i]*c+b[2]
).

 • Скалярное произведение (res = сумма элементов

a[i]*b[i]
; известна также как
inner_product
).

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

• Массивы при необходимости можно увеличивать (при их реализации не используются “магические” числа).

Библиотека

Matrix
делает это и только это. Если вы хотите большего, то должны самостоятельно написать сложные функции обработки массивов, разреженных массивов, управления распределением памяти и так далее или использовать другую библиотеку, которая лучше соответствует вашим потребностям. Однако многие эти потребности можно удовлетворить с помощью алгоритмов и структур данных, надстроенных над библиотекой
Matrix
. Библиотека
Matrix
не является частью стандарта ISO C++. Вы можете найти ее описание на сайте в заголовке
Matrix.h
. Свои возможности она определяет в пространстве имен
Numeric_lib
. Мы выбрали слово
Matrix
, потому что слова “вектор” и “массив” перегружены в библиотеках языка C++. Реализация библиотеки
Matrix
основана на сложных методах, которые здесь не описываются. 

24.5.1. Размерности и доступ

Рассмотрим простой пример.

#include "Matrix.h"

using namespace Numeric_lib;

void f(int n1, int n2, int n3)

{

333
{"b":"847443","o":1}