русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Статический массив указателей


Дата добавления: 2015-06-12; просмотров: 1231; Нарушение авторских прав


 

Статический массив указателей, например, на объекты типа int размерности 5, объявляется следующим образом:

const n=5; int * ap[n];

Память для такого массива выделяется на этапе компиляции. При таком объявлении массив, который называется ap, состоит из n элементов, каждый из которых имеет тип int *. Другими словами, ap[i], где i=0, 1, 2, …, n-1, представляет собой не целое обрабатываемое в программе число (оценку студента, план выпуска продукции и т. п.), а адрес ячейки оперативной памяти, в которой будет храниться целое число. Можно использовать операцию разыменования “*”. Содержимое ячейки памяти, адрес которой находится в ap[i], обозначается в программе *ap[i].

По аналогии с обычными указателями, i-й элемент объявленного таким образом массива указателей ap[i] можно проинициальзировать одним из следующих способов:

1) с помощью адреса предварительно объявленной простой целочисленной переменной. Например,

int v; ap[i]=&v;

2) с помощью объявленного указателя. Например,

int * p; p= new int; ap[i]=p;

3) непосредственно с помощью операции new. Например,

a) … ap[i]=new int; резервируем память для размещения одного целого числа и его адрес засылаем в i-й элемент массива указателей. Значение i должно быть определено.

б) резервируем память для размещения массива из m целых чисел и адрес его начала засылаем в i-й элемент массива указателей

unsigned m; cin>>m;…ap[i]=new int[m];

В качестве m можно использовать как переменную (см. в примере), так и константу. Переменная i может принимать значение от 0 до n-1;

4) для инициализации элемента массива ap можно использовать адрес предварительно объявленного одномерного массива фиксированной размерности:

const m=10; int a[m]; ap[i]=a;

где i по-прежнему может принимать значение от 0 до n-1 (а не до m-1).



Напомним, что при таком объявлении a — адрес начала одномерного массива. Поэтому последнее присваивание будет корректным.

Логическим продолжением последнего способа является использование массива указателей при работе со статической числовой матрицей. Пусть объявлена матрица

const п=5, m=10; int matr[n][m];

и надо переставить к1-ю строку с k2-й строкой.

Один из способов, при котором элементы двух строк физически переставляются в памяти, был показан в первом семестре. Так как matr[k1] и matr[k2] — адреса начала k1-й и k2-й строк, то возникает вопрос: как для такой перестановки строк ограничиться изменением нескольких адресов, не перемещая элементы в памяти? Объявим для этого ещё один указатель int *p. Казалось бы, можно изменить адреса следующим образом:

p=matr[k1]; matr[k1]=matr[k2]; matr[k2]=p; // ошибка

Но при компиляции второго и третьего присваиваний будут ошибки, так как matr[k1] и matr[k2] — константные указатели на начало строк, то есть их значения нельзя менять. Заметим, что если бы такая возможность разрешалась, то мы потеряли бы доступ к строкам матрицы.

Выход из этой ситуации следующий. Объявляем дополнительно массив указателей размерности n, где n — количество строк матрицы: int * ap[n]; Инициализируем этот массив:

for (int i=0; i<n; i++) ap[i]=matr[i];

Почему присваивание, записанное в цикле, будет корректным? С одной стороны, ap[i] — это указатель, так как ap объявлен не как массив целых чисел (int ap[n];) и не как один указатель (int * ap;) , а как массив указателей. Напомним, что с другой стороны, объявив статическую матрицу, мы этим самым объявили и константый массив указателей, то есть matr[i] — это адрес начала i-й строки матрицы. И тогда меняем не matr[k1] и matr[k2], а ap[k1] и ap[k2] аналогичным образом:

int *p; p=ap[k1]; ap[k1]=ap[k2]; ap[k2]=p;

Вместо m*3 присваиваний, которые необходимо было выполнить при физическом перемещении элементов строк, достаточно выполнить всего три операции присваивания для адресов. При необходимости такие “перестановки” строк можно выполнять несколько раз в цикле. Это имеет место, например, в алгоритмах сортировки. Понятно, что в этом случае эффективность такого метода возрастает.

После таких “перестановок” матрица matr не изменилась. В этом легко убедиться, если вывести её (matr[i][j]) на экран. Доступ к преобразованной матрице осуществляется с помощью идентификатора ap. Например, вывод изменённой матрицы можно выполнить так:

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

{ cout<< endl;

for(int j=0; j<m; j++)

printf ( “%5d”, ap[i][j]);

}

Заметим, что несмотря на то, что, казалось бы, переменную ap не объявляли как двумерный массив (как матрицу), а как одномерный массив, но массив указателей, мы имеем возможность использовать эту переменную с двумя индексами (ap[i][j]).

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

const m=4;

int main()

{ // 1) Статическую матрицу не создаём. Её достаточно объявить

const n=5; int matr[n][m];

// Cтатический массив указателей на строки матрицы

int*u[n];

// 2) Получаем матрицу…

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

{ for(int j=0;j<m;j++)

matr [i][j]=random(15)-6;

/* … и формируем статический массив указателей на строки матрицы */

u[i]= matr [i];

}

/* 3) Получаем одномерный массив параметров s, каждый элемент которого —максимальное число в строке. Поэтому размерность этого массива совпадает с количеством строк матрицы */

int s[n],Mymax,Mymin,nmin;

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

{ Mymax= matr [i][0];

for(int j=0;j<m;j++)

if (matr [i][j]>Mymax)

Mymax= matr [i][j];

s[i]=Mymax;

}

// 4) Вывод матрицы matr и вектора s

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

{ cout<<endl;

for(int j=0;j<m;j++)

printf("%5d", matr [i][j]);

printf(" => %5d",s[i]);

}

cout<<endl;

// 5) Сортировка методом выбора минимального элемента

for(int start=0;start<=n-2;start++)

{

Mymin=s[start]; nmin=start;

for(int i=start;i<n;i++)

if(s[i]<Mymin)

{ Mymin=s[i];

nmin=i;

}

cout<< Mymin<< " "<<nmin<<endl;

// Комментарии в конце

int *p; p=u[start]; u[start]=u[nmin]; u[nmin]=p;

/* Переставляем элементы одномерного массива s с номерами start и nmin, не используя никакие указатели */

int t; t=s[start]; s[start]=s[nmin]; s[nmin]=t;

}

/* 6) Выводим рассортированную матрицу u (а не matr) и вектор s. */

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

{ cout<<endl;

for(int j=0;j<m;j++)

printf("%5d",u[i][j]);

printf(" => %5d",s[i]);

}

cout<<endl;

/* 7)Убеждаемся, что матрица matr осталась не рассортированной! Матрицы u и matr занимают одну и туже оперативную память, но u[i] и matr [i] имеют, вообще говоря, разные адреса. */

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

{ cout<<endl;

for(int j=0;j<m;j++)

printf("%5d",matr[i][j]);

}

getch(); return 0;

}

В первом семестре без использования указателей две строки матрицы c номерами start и nmin переставляли бы “физически” следующим образом:

int t1;

for(int j=0;j<m;j++)

{ t1= matr [start][j];

matr [start][j]= matr [nmin][j];

matr [nmin][j]=t1; }

Так как matr [i] – это константные адреса строк статической матрицы, их нельзя менять. Т. е. нельзя написать matr [start]= matr [nmin]. Поэтому переставляли полученные “новые” адреса строк матрицы с номерами start и nmin, то есть соответствующие элементы массива указателей u. Физически элементы этих строк остаются на старых местах, меняли только значения двух адресов в массиве u.



<== предыдущая лекция | следующая лекция ==>
С. Задачи повышенной сложности. | Частично динамическая матрица.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 1.536 сек.