Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Обозначение элементов многомерного массива




Описание многомерного массива позволяет использовать в программе любой из его элементов как индексированную переменную.

Индексированная переменная (индексное выражение) – обозначение ячейки для хранения конкретного элемента массивауказанием идентификатора массива и индексов элемента по каждому измерению.

В массивах Си/Си++ индексы элементов на единицу меньше заданных математически. Это обстоятельство должно учитываться в программе, особенно при формировании условия повторения (выхода из) цикла.

Особенность работы с массивами в Си/Си++ – любой двумерный массив можно представить в виде одномерного при условии укрупнения единицы хранения (элемента).

Например, если в качестве элементов выбрать строки (столбцы), то двумерный массив превратится в одномерный массив строк (столбцов).

Хранение двумерного массива, например X(m n), реализуется схемой распределения оперативной памяти (рис. 9.4).

Для хранения трехмерного массива, например S(k m n), схема распределения оперативной памяти представлена на рис 9.5 (первая и последняя страницы).

x00 x01 . . . x0j . . . x0 n-1

 

  x10 x11 . . . x1j . . . x1 n-1

 

............................

 

  xi0 xi1 . . . xij . . . xi n-1

 

............................

 

  xm-1 0 x m-1 1 . . . x m-1 j . . . x m-1 n-1  

Рис. 9.4. Хранение элементов двумерного массива

s000 s001 . . . s00j . . . s00 n-1

 

............................

 

  s0i0 s0i1 . . . s0ij . . . s0i n-1

 

............................

 

  s0m-1 0 s0 m-1 1 . . . s0 m-1 j . . . s0 m-1 n-1

 

............................

 

  sk-100 sk-101 . . . sk-10j . . . sk-10 n-1

 

............................

 

  sk-1i0 sk-1i1 . . . sk-1ij . . . sk-1i n-1

 

............................

 

  sk-1m-10 sk-1 m-1 1 . . . sk-1 m-1 j . . . sk-1 m-1 n-1  

Рис. 9.5. Хранение элементов трехмерного массива

Анализ схем показывает, что все элементы многомерного массива располагаются в оперативной памяти линейно (непрерывно и последовательно). При этом двумерный массив представляется последовательностью строк, трехмерный – последовательностью страниц, каждая из которых в свою очередь является последовательностью строк.

Изменение индексов происходит последовательно – справа налево. Например, для трёхмерного массива вначале полностью перебирается крайний правый индекс (столбцов), затем средний (строк) и последним – левый (страниц).

Длина ячейки хранения каждого элемента определяется типом массива.

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

Следовательно, n-мерный массив в Си/Си++ интерпретируется как совокупность массивов (n-1) размерности, которые также могут быть представлены совокупностью массивов еще меньшей размерности.

Структура обозначения индексированной переменной многомерного массива:

имя[индекс_1][индекс_2]...[индекс_i]...[индекс_n]

где имя – идентификатор массива;

индекс_i – целая константа, задающая номер элемента по i-му измерению;

[ ] – ограничители индекса элемента по каждому измерению.

Так, в описанном ранее массиве D(20 30) элемент, расположенный в первом столбце первой строки, обозначается индексным выражением d[0][0], во втором столбце той же строки – d[0][1], в первом столбце второй строки – d[1][0], текущий – d[i][j], элемент последнего столбца, последней строки – d[19][29].

Рассмотренный пример идентификации элементов массива D применим к любому из двумерных массивов, указанных в соответствующем описателе.

Для трехмерных массивов обозначение элементов выполняется аналогично. Например, в массиве S(10 5 15) (описан ранее) элемент первой страницы на пересечении первой строки и первого столбца обозначается индексным выражением s[0][0][0], элемент второго столбца первой строки той же страницы – s[0][0][1], второго столбца второй строки первой страницы – s[0][1][1], текущий – s[k][i][j], а элемент последнего столбца, последней строки, последней страницы – s[9][4][14].

Индекс, при необходимости, может задаваться арифметическим выражением. Например, d[i+2][5], d[i][j-1], s[3][i-1][j+2], s[k-3][i][2*j].

ü Внимание! Индекс на момент использования переменной должен быть определен (рассчитан) и укладываться в заданный описателем диапазон.

Рассмотренные формы представления индексированных переменных позволяют осуществить программную реализацию элементов алгоритма с использованием многомерных массивов.

Непрерывное и последовательное расположение элементов многомерного массива в оперативной памяти позволяет адрес каждого элемента представить зависимостью:

а = а1 + смещение,

где а – адрес некоторого текущего элемента массива;

а1 – адрес первого элемента массива;

смещение – номер текущего элемента относительно первого.

Смещение рассчитывается для массивов различной размерности по аналогичным методикам.

Так для двумерного массива

смещение = индекс_1*разм_2+индекс_2

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

Для трехмерного массива

смещение = индекс_1*(разм_2* разм_3) +

+ индекс_2 * разм_3 + индекс_3

Первое слагаемое определяет число элементов в ранее расположенных страницах, второе – в предыдущих строках текущей страницы, третье – число элементов в текущей строке текущей страницы.

ü Внимание! Для любого массива размер первого измерения (разм_1) в расчете смещения не используется.

В качестве сомножителей (разм_i) используются значения, указанные в описателях массивов.

Описатели массивов определяют максимально возможные значения (размеры) каждого измерения. Это позволяет использовать зарезервированное пространство оперативной памяти полностью, либо частично, обеспечивая универсальность размеров в сторону уменьшения. Для двумерного массива это утверждение поясняется схемой (рис. 9.6):

Размер, заданный в описателе (максимальное число столбцов nmax)  
Размер, используемый в расчетах (n)    
                    Размер, использу-емый в расчетах (m) Размер, заданный в описателе (максимальное число строк mmax)
                   
                   
                   
                     
                   
                   
                         

Рис. 9.6. Соответствие реальных размеров описанным

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

Так, если двумерный массив z описан как z[10][20], а в задаче используется с размерами m=7, n=12, то адрес текущего элемента &z[i][j] = z[0] + i * 20 + j, а не &z[i][j] = z[0] + i * n + j.

Исходя из изложенного, адрес i-го, j-го элемента массива D(20х30) вычисляется по формуле

&(d[i][j]) = d[0] + i * 30 + j,

а адрес k-го, i-го, j-го элемента массива S(10х5х15) вычисляется как

&(s[k][i][j]) = s[0][0] + k * (5 * 15) + i * 15 + j

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

С учетом изложенного идентификация переменных алгоритма и создаваемой программы представлена в табл. 9.1.

Таблица 9.1

Обозначение в алгоритме m n i j xпр xij yij
Обозначение в программе m n i j xp x[i][j] y[i][j]

На основании схемы алгоритма и таблицы идентификации составим программу решения задачи.

Классический вариант программирования задачи

#include <stdio.h> /* директивы */

#include <conio.h> /* препроцессора */

#include <windows.h>

#define M 10 /* увеличенные */

#define N 12 /* размеры массивов */

main() /* заголовок головной функции */

{

float x[M][N], y[M][N]; /* описатели массивов */

int i, j, n, m;

char buf[50]; /*описание символьного массива*/

clrscr();

CharToOem(" Введите m (m<= ",buf); /* запрос */

printf("\n %s %d):",buf,M); /* и */

scanf("%d", &m); /* ввод */

CharToOem(" Введите n (n<= ",buf); /* фактических */

printf("\n %s %d):",buf,N); /* размеров */

scanf("%d", &n); /* массивов */

printf("\n n=%d m=%d ", n, m); /*вывод размеров массивов*/

for(i = 0; i < m; i++) /*заголовок внешнего цикла ввода x[i][j]*/

for(j = 0; j < n; j++) /*заголовок внутр. цикла ввода x[i][j]*/

{

CharToOem(" Введите значение ",buf); /* ввод */

printf("\n %s x[%d][%d]:",buf,i+1, j+1); /* элементов */

scanf("%f", & x[i][j]); /*массива Х*/

}

CharToOem(" Массив X",buf); /* вывод */

printf("\n %s \n",buf); /*заголовка*/

for(i = 0; i < m; i++)/* заголовок внешн. цикла вывода x[i][j]*/

{

for(j=0; j < n; j++)/*заголовок внутр. цикла вывода x[i][j]*/

printf(" %5.2f", x[i][j]);

printf("\n");

}

for(i = 0; i < m; i++ /*заголовок внешн. цикла расчета y[i][j]*/

for(j = 0; j < n; j++)/*заголовок внутр. цикла расчета y[i][j]*/

y[ i ][ j ] = x[ i ][ j ] / 2.;

CharToOem(" Массив Y",buf); /* вывод */

printf("\n %s \n",buf); /*заголовка*/

for(i = 0; i < m; i++)/*заголовок внешн. цикла вывода y[i][j]*/

{

for(j = 0; j < n; j++) /*заголовок внутр. цикла вывода y[i][j]*/

printf(" %5.2f", y[i][j]);

printf("\n");

}

getch();

}

2 3 – размеры массива;

10. 20. 30. – элементы первой строки;

100. 200. 300. – элементы второй строки.

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 9.1.

Программирование задачи с графическим интерфейсом

Программирование задачи при использовании графического интерфейса предварим его разработкой.

ListBoxХi
ListBoxYi

Для ввода количества столбцов и строк массива планируем однострочные поля редактирования (EditN, EditМ). Для ввода элементов массива Х – многострочное поле редактирования (EditХ). Вывод элементов массивов X и Y реализуем в поля-списки (ListBoxXi, ListBoxYi).

Управление процессом решения реализуем двумя командными кнопками, расположенными в нижней части окна. Назначение каждой определяется ее названием.

Использование графического интерфейса для вывода числовых элементов двумерных массивов в виде таблицы требует:

· представления каждого числового данного соответствующей символьной строкой;

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

· размещение сформированной общей символьной строки в окне вывода.

Представление числовых данных символьными строками комментариев не требует.

Формирование элементов выводимой строки в единое целое выполняется функцией «склеивания» строк strcat.

Функция «склеивания» символьных строк strcat()

Функция предназначена для получения результирующей строки из двух исходных строк. Структура функции:

strcat(buf1, buf2)

где strcat – обозначение функции;

buf1 – имя исходной (результирующей) символьной строки;

buf2 – имя добавляемой символьной строки;

() – ограничители аргумента.

Функция располагается в библиотеке string.h.

Правила записи и использования

1. Операнды buf1 и buf2 – символьные строки. Строка buf1 увеличивает свое значение после выполнения функции на величину buf2.

2. Обязательное условие формирования строк buf1 и buf2 – окончание каждой символом «\0».

3. Пробелы, при необходимости, формируются структурой соответствующей строки (включением в нее).

4. Однократное использование функции – чтение строки buf1, добавление к ней строки buf2 и занесение результата в buf1. Поэтому размер buf1 в описателе создается увеличенным (на величину добавляемых компонентов).

5. Многократное использование функции – последовательное добавление второго операнда (buf2) к предварительно полученной строке buf1.

6. Повторное использование функции для создания новой результирующей строки требует предварительной очистки первого аргумента функции. Один из вариантов – присваивание строке buf1 пустой строки: sprintf(buf1,"%s","");

7. Проверка результирующей строки на переполнение не выполняется.

8. Функция используется как операнд арифметического выражения (присваивания) или самостоятельный оператор.

Общий вид фрагмента программы «склеивания» символьных строк str и buf:

#include <string.h> /* директива препроцессора*/

char str[25], buf[10]; /*описатель символьных строк*/

EditStr->GetText(str, 10); /*ввод строки str из поля EditStr*/

EditBuf->GetText(buf, 10); /*ввод buf из поля EditBuf*/

strcat(str, buf); /*формирование результирующей строки str «склеиванием» исходных строк str и buf*/

Описатель типа определяет массивы str и buf как символьные максимальной длины 25 и 10 символов. Пятая и шестая строки предписывает ввод строк str и buf из полей EditStr и EditBuf соответственно. Оператор strcat(str, buf); формирует «склеенную» строку и хранит ее под именем str.

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

Вариант 1: последовательное соединение нескольких строк

#include <string.h> /* директива препроцессора*/

char str[25], buf1[10], buf2[5];/*описатель символьных строк*/

EditStr->GetText(str, 10); /*ввод строки str из поля EditStr*/

EditBuf1->GetText(buf1, 10); /*ввод buf1 из поля EditBuf1*/

EditBuf2->GetText(buf2, 10); /*ввод buf2 из поля EditBuf2*/

strcat(str, buf1); /*формирование результирующей строки str «склеиванием» исходных строк str и buf1*/

strcat(str, buf2); /*формирование результирующей строки str «склеиванием» полученных str и buf2*/

Описатель типа определяет массивы str, buf1 и buf2 как символьные, максимальной длины 25, 10 и 5 символов, соответственно. Пятая, шестая и седьмая строки предписывает ввод str, buf1 и buf2 из полей EditStr, EditBuf1 и EditBuf2 соответственно. Операторы strcat(str, buf1); и strcat(str, buf2); последовательно формируют «склеенную» строку из str, buf1 и buf2. Полученная строка имеет имя str.

Вариант 2: использование функции в теле цикла.

#include <string.h> /* директива препроцессора*/

char str[50] = “ ”, buf[10];/*описание и инициализация

символьных строк*/

for(j = 0; j < 5; j++) /* заголовок цикла ввода buf и формирования str*/

{

EditBuf->GetLine(buf, 10, j); /* ввод buf */

strcat(str, buf); /*формирование результирующей строки str «склеиванием» исходных строк str и buf*/

}

Описатель типа определяет массивы str и buf как символьные максимальной длины 50 и 10 символов соответственно и инициализирует str пустой строкой. Оператор EditBuf->GetLine (buf, 10, j); предписывает ввод buf из j-й строки многострочного поля EditBuf. Оператор strcat(str, buf); формирует в теле цикла, из последовательно вводимых строк buf, «склеенную» строку и хранит ее под именем str.

С учетом планируемого интерфейса выполним программирование задачи.

#include<stdio.h>

#include<stdlib.h>

#include <string.h>

void TSumprDlgClient::Ok()

{

// INSERT>> Your code here.

float x[M][N], y[M][N]; /* описатели массивов */

int i, j, n, m;

char buf[30],buf1[90]=" "; /*описание символьного массива*/

ListBoxYi->ClearList(); /*очистка поля вывода*/

ListBoxXi->ClearList(); /*очистка поля вывода*/

EditN->GetText(buf, 10); /*ввод количества*/

n = atoi(buf); /* столбцов массива*/

EditM->GetText(buf, 10); /*ввод количества*/

m = atoi(buf); /* строк массива*/

for(i = 0; i < m; i++) /* заголовок внешн. цикла ввода x[i][j] */

for(j = 0; j < n; j++) /* заголовок внутр. цикла ввода x[i][j] */

{

EditX->GetLine(buf, 30, i*n+j); /* ввод элементов */

x[i][j]=atof(buf); /* массива Х*/

}

for(i = 0; i < m; i++) /*заголовок внешн. цикла вывода x[i][j]*/

{

for(j = 0; j < n; j++)/*заголовок внутр. цикла вывода x[i][j]*/

{

sprintf(buf,"%11.3f",x[i][j]); /* вывод текущих*/

strcat(buf1, buf); /*склеенных*/

}

ListBoxXi->AddString(buf1); /*значений xi*/

sprintf(buf1,"%s","");

}

for(i = 0; i < m; i++)/*заголовок внешн. цикла расчета y[i][j]*/

for(j = 0; j < n; j++) /*заголовок внутр. цикла расчета y[i][j]*/

y[ i ][ j ] = x[ i ][ j ] / 2.;

for(i = 0; i < m; i++)/*заголовок внешн. цикла вывода y[i][j]*/

{

for(j = 0; j < n; j++)/*заголовок внутр. цикла вывода y[i][j]*/

{

sprintf(buf,"%11.6f",y[i][j]); /* вывод текущих*/

strcat(buf1, buf); /*склеенных*/

}

ListBoxYi->AddString(buf1); /*значений yi*/

sprintf(buf1,"%s","");

}

}

3 2 – размеры массива;

10. 20. 30. – элементы первой строки;

100. 200. 300. – элементы второй строки.

Под закрывающей скобкой приведены исходные данные для решения задачи.

Результаты решения представлены в приложении 9.2.





Поделиться с друзьями:


Дата добавления: 2015-11-23; Мы поможем в написании ваших работ!; просмотров: 1101 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Так просто быть добрым - нужно только представить себя на месте другого человека прежде, чем начать его судить. © Марлен Дитрих
==> читать все изречения...

2510 - | 2261 -


© 2015-2025 lektsii.org - Контакты - Последнее добавление

Ген: 0.011 с.