![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Многомерные массивы, динамическое распределение памяти
Кроме одномерных массивов возможна работа с многомерными массивами. Объявление многомерного массива: < тип> < имя> [< размер 1 > ][< размер 2 > ]…[< размер N> ]={{список начальных значений}, {список начальных значений}, …}; Наиболее быстро изменяется последний индекс элементов массива, поскольку многомерные массивы размещаются в памяти компьютера в последовательности столбцов. Например, элементы двухмерного массива b[2][1] размещаются в памяти в следующем порядке: b[0][0], b[0][1], b[1][0], b[1][1], b[2][0], b[2][1]. Следующий пример иллюстрирует определение массива целого типа, состоящего из трех строк и четырех столбцов, с инициализацией начальных значений: int a[3][4] = {{0, 1, 2, 0}, {9, -2, 0, 0}, {-7, 1, 6, 8}}; Если в какой-то группе {…} отсутствует значение, то соответствующему элементу присваивается 0. Предыдущий оператор будет эквивалентен следующему определению: int a[3][4] = {{0, 1, 2}, {9, -2}, {-7, 1, 6, 8}};
Создать двумерный массив целых чисел NxM (N и M не более 50), используя функцию rand и вывести на экран в форме матрицы, N, M ввести с клавиатуры: #include< stdio.h> #include< stdlib.h> #include< conio.h> #define rnd (rand()/ 32768.0) // rand - генератор случайных чисел от 0 до int, rnd – от 0 до 1 void main(void) { int i, j, n, m, a[50][50]; puts(“\n Input n, m: ”); scanf(“%d %d”, & n, & m); printf(“\n Array a \n”); for(i=0; i< n; i++) for(j=0; j< m; j++) { a[i][j]=rnd*10-5; // диапазон от –5 до 5 printf(“%d%c“, a[i][j], (j= =m-1)? ’\n’: ’ ‘); } getch(); } В языке С/C++ можно использовать массивы указателей, элементы которых содержат, как правило, указатели на строковые данные. Объявляется такой массив например так: char *m[5]. Здесь массив m[5] – массив, который может содержать пять адресов данных типа char. Массив указателей можно при объявлении инициализировать, т.е. назначать его элементам конкретные адреса заданных строк. В качестве примера приведена программа, формирующая массив указателей с одновременной инициализацией его элементов. Программа распечатывает номер строки, ее адрес и значение. #include < stdio.h> #include < conio.h> void main(void) { int i, k; char *m[]={" Winter", " Spring", " Summer", " Automn" }; k=sizeof(m)/sizeof(*m); printf(" \n Количество строк = %d", k); for(i=0; i< k; i++) printf(" \n Номер - %d; Адрес - %p; Строка: %s", i+1, m[i], m[i]); getch(); } В результате получим: Количество строк = 4 Номер - 1; Адрес - 0042007C; Строка: Winter Номер - 2; Адрес - 00420074; Строка: Spring Номер - 3; Адрес - 0042006C; Строка: Summer Номер - 4; Адрес - 00420064; Строка: Automn Конкретные значения адресов зависят от ряда причин: архитектура компьютера, тип и размер оперативной памяти и т.д. Связь указателей и массивов с одним измерением справедливо и для массивов с большим числом измерений. Например, рассмотрим двумерный массив float m[5][10]; Если рассматривать его как массив пяти массивов размерностью по десять элементов каждый, то очевидна схема его размещения в памяти - последовательное размещение «строк» элементов. Обращению к элементам m[i][j] соответствует эквивалентное выражение *(*(m+i)+j), а объявление этого массива указателем будет: float **m; Таким образом, имя двумерного массива - имя указателя на указатель. Например, двухмерный массив m(3х4) компилятор рассматривает как массив трех указателей, каждый из которых указывает на начало массива со значениями размером по четыре элемента каждый (рис. 1).
рис. 1
Cхема размещения такого массива в памяти - последовательное (друг за другом) размещение строк - одномерных массивов со значениями. Аналогичным образом можно установить соответствие между указателями и массивами с произвольным числом измерений. Количество символов «*» определяет уровень вложенности указателей друг в друга. При объявлении указателей на указатели возможна их одновременная инициализация. Например: int a=5; int *p1=& a; int **pp1=& p1; int ***ppp1=& pp1; Теперь присвоим целочисленной переменной а новое значение, например 10. Одинаковое присваивание произведут следующие операции: a=10; *p1=10; **pp1=10; ***ppp1=10; Для доступа к области памяти, отведенной под переменную а можно использовать и индексы. Справедливы следующие аналоги: *p1 равносильно p1[0] **pp1 равносильно pp1[0][0] ***ppp1 равносильно ppp1[0][0][0] Таким образом, указатели на указатели – это имена многомерных массивов. Очевидна эквивалентность выражений: & name[0][0] < -> & (**name) < -> name // адрес нулевого элемента матрицы **name < -> name[0][0] // значение нулевого элемента матрицы Пример программы: #include < stdio.h> int x0[4]={ 1, 2, 3, 4}; int x1[4]={11, 12, 13, 14}; // Декларация и инициализация int x2[4]={21, 22, 23, 24}; // массивов целых чисел int *y[3]={x0, x1, x2}; // Создание массива указателей void main(void) { int i, j; for (i=0; i< 3; i++) { printf(" \n %2d)", i); for (j=0; j< 4; j++) printf(" %2d", y[i][j]); } } Результаты работы программы: 0) 1 2 3 4 1) 11 12 13 14 2) 21 22 23 24
Такие же результаты получим и при следующем объявлении массива: int y[3][4]={{1, 2, 3, 4}, {11, 12, 13, 14}, {21, 22, 23, 24}}; // Декларация и инициализация матрицы целых чисел В последнем случае массив указателей на массивы создается компилятором. Здесь собственно данные массива располагаются в памяти последовательно по строкам, что является основанием для объявления y в виде z[3][4]={ 1, 2, 3, 4, 11, 12, 13, 14, 21, 22, 23, 24}; // Декларация и инициализация матрицы целых чисел скобочного выражения z[3][4] на z[12] здесь не допускается, так массив указателей в данном случае создан не будет.
|