Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лекция 7.2 ятп.docx
Скачиваний:
5
Добавлен:
22.02.2015
Размер:
47.77 Кб
Скачать

---Лекция 7.2

Замечание о константных указателях

int x=10; int *p=&x; int &q=p;

const int * u;//-указатель на константу целого типа

int * const w=&x;// указатель-константа на целую переменную

const int n=200;

const int * const r=&n;//указатель-конст. на конс-ту цел. типа

10.Сложные типы.

Данные сложного типа строятся путём объединения данных простых и ранее построенных сложных типов в некоторую совокупность- её называют структура данных.

Смысл объединения – иметь возможность обращаться (по имени ) сразу ко всей структуре.

При построении совокупности данных обычно приходится решать 3 вопроса:

1)фиксируется или нет количество элементов в совокупности; если фиксируется, то говорят структура статическая, место под неё может быть выделено в указанном объеме и сохраняется в области видимости;

2)элементы в совокупности однотипные или необязательно однотипные, т.е. тип элементов можно указать один раз или указывать для каждого элемента.

3)элементы в совокупности упорядочены или нет. Упорядочивание бывает

= с помощью системы индексов, например: b0, b1, . . .b15

A1,1 A1,2 … A1,m

…………………………………………….

An,1 An,2 … An,m

= с помощью перечисления:

Тип имя;

……………….

Тип имя;

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

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

Описание массива (одномерного) :

Тип имя [размер];

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

Пример: int a[5]; // в массиве 5 элементов типа int.

Возможна инициализация массива:

double b[4] = {3.5,-1.2,5.1}; // инициализируются первые 3 элемента, а те, которым не задано значение , обнуляются.

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

int x[ ]={3,2,1}; //здесь объявлен массив из 3-х элементов.

==!!! В С++ у массива нет типа, с этим связаны некоторые особенности использования массива.

Рекомендуется при работе с массивом:

==Описать именованную константу, задающую размер массива (м.б. глобальную):

const int n=100;

==затем описать массив;везде, где требуется его размер, использовать n.

int a [n ]; // в дальнейшем, если окажется , что n надо изменить, исправить можно только строку с описанием именованной константы и перетранслировать программу.

Доступ к элементу массива выполняется с помощью такой конструкции

Имя_массива [индексное_выражение] это переменная с индексом. её тип –тип элемента массива

Здесь 0<= индексное_выражение<=n-1; инд. выраж.-целого типа

Например: a[0] a[1] a[2] . . a[i] . . a[n-1]-элементы а;

Тип этих переменных с индексом есть int, использование a[i], (например, в цикле) позволяет перебирать элементы массива с изменением i от 0 до n-1.

Замечание!!! Контроль за выходом значения индекса за пределы [0,n-1] не выполняется, поэтому использование индекса за пределами может привести к какой-нибудь непредсказуемой ситуации.

==Где можно использовать массив и его элементы?

Элемент массива можно использовать везде, где можно использовать переменную типа этого элемента: для простого типа(только они были рассмотрены ранее к этому моменту) в выражениях, ему можно присвоить значение в операторе присваивания, ему можно ввести значение (сin>>a[i]; ), можно вывести на экран его значение (cout<<a[i];)

Массив может быть передан в функцию, но присвоить его элементам что-то, ввести его или вывести можно только поэлементно!

Замечание. На [] нужно смотреть как на операцию определения адреса элемента массива, а затем доступа к элементу по найденному адресу. В случае многократного использования одного и того же элемента лучше присвоить его значение переменной, а затем её использовать.

if (a[i]>max) max=a[i];//дважды выполняется a[i]

Лучше: r=a[i]; if(r>max) max=r;

Связь массива и указателя Одна из особенностей С++ состоит в том, что идентификатор массива является константным указателем на его нулевой элемент.

int b[10]; имя b- константный указатель на b[0],т.е. b=&b[0];

Учитывая, что b-это указатель на начало массива, а элементы его располагаются последовательно в памяти друг за другом в порядке возрастания индексов, то адрес i-го элемента есть b+i, а сам элемент *(b+i), т.е. *(b+i)эквивалентно b[i].

Пример: во все элементы массива b поставить 1.

double b[n];

for(int i=0;i<n;++i) {*(b+i)=1;cout<<b[i]<<" ";}//b[i]=1;

//1 1 1 1 1 1 1 1 1 1

Можно описать указатель p и ему присвоить значение константного указателя b и изменять p:

double *p=b; for (int i=0;i<n;++i){*p++=2;cout<<b[i]<<" ";}

//2 2 2 2 2 2 2 2 2 2

!!! нельзя b++; *p++=2;вып-ся так *p=2; p++;

Работа с массивом переменной длины.

1 способ. Описывается массив некоторой максимальной длины n, а используется его часть- к элементов: от 0-го до (к-1)-го, причем к должно быть не больше n.

Передача массива в функцию в качестве параметра.

Массивы могут быть параметрами функций, функции могут возвращать массив, используя в качестве типа результата функции, указатель на массив, но не сам массив!

При передаче массива в функцию(через параметр,например,double a[n]) передаётся указатель, т.е. массив всегда передаётся по адресу(не требуется копировать его элементы в память стека!),при этом информация о размере массива n теряется и должна передаваться дополнительно. Так как передаётся указатель, то фактический параметр- массив может изменяться в функции (не имя этого фактического массива, а его элементы! )

Пример программы для ввода массива нужной длины, причём ввод массива и его длины выполнит функция , а главная функция к ней обращается.

#include <iostream>

using namespace std;

void rdm(int& ,double []);

void wrm(int ,double []);

== const int n=100;

int main()

{

double a[n];

int ma;

rdm(ma,a); wrm(ma,a); //фактический параметр – имя массива a

return 0;

}

== //ввод массива нужной длины

void rdm(int& k, double a[])

{// чтение массива

cout<<"\n kol-vo el-ov <= "<<n<<" ";

cin>>k;

cout<<"el-ti cherez probel:\n";

for(int i=0; i<k; i++) cin>>a[i];

}

==//выдача массива

void wrm(int k,double a[])

{cout<<’\n’;

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

{cout<<a[i]<<" ";

If((i+1)%10==0) cout<<’\n’;//по 10 чисел в строке

}

cout<<’\n’;

}

Пример 2.Найти скалярное произведение двух векторов.

#include <iostream>

using namespace std;

void rdm(int& ,double []);

double scalpr(int ,double *,double *);

void wrm(int ,double []);

const int n=10;

int main()

{

double a[n],b[n];

int ma,mb;

rdm(ma,a);wrm(ma,a);

rdm(mb,b);wrm(mb,b);

if (ma!=mb){cout<<"razmeri raznie"<<endl;return 1;}

cout<<"scalpr="<< scalpr(ma,a,b) <<'\n';

return 0;

}

. . . . . . . . . .

//Скалярное произведение

//двух векторов x и y

double scalpr(int k,double *x,double *y)

// double scalpr(int k,double x[],double y[])

{double a=0;

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

a+=*(x+i)**(y+i);

//a+=x[i]*y[i];

return a;

}

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

В С++ есть универсальная операция, которая получает память у операционной системы и возвращает указатель на начало выделенного блока. Если память не выделена, указатель получает значение 0.

Тип * имя_ указателя = new тип;

float * u=new float;//выделено место под значение типа float и на него указывает указатель u.

Обращение к выделенной памяти:

Переменная *u явл. переменной типа float.

Можно инициализировать память float * u=new float(1.5);

Можно выделить место под массив нужного размера:

int k; сin>>k;

double * p;

p=new double [k]; // double * p=new double [k];

В динамической памяти выделяется непрерывная область для размещения к переменных типа double.

!!! динамический массив не обнуляется;

Нельзя его инициализировать при создании.

Преимущества дин. массива очевидны:создаётся во время выполнения программы, нужного размера.

Обращение к элементам массива такое же, как к элементам статического массива, но только с использованием указателя: p[i] или *(p+i).

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

Для переменной: delete u;

Для массива: delete [] p;

Дин. память освобождается автоматически после окончания работы программы. Освобождение памяти , когда она больше не нужна, является хорошим тоном, а иногда это требуется выполнить обязательно. Однако , если в функции описана локальная переменная- указатель и ей присвоено значение по new , то по окончании работы функции эта переменная- указатель исчезнет, а выделенная дин. память останется недоступной.

Пример 3 пример функции, которая возвращает указатель на массив

//Слияние 2-ух массивов,

//упорядоченных по неубыванию

#include <iostream>

using namespace std;

void rdm(int& ,int []);

int * slmas(int ,int [],int ,int []);

void wrm(int ,int []);

const int n=100;

int main()

{

int a[n],b[n];

int ma,mb;

rdm(ma,a);wrm(ma,a);

rdm(mb,b);wrm(mb,b);

int *t=slmas(ma,a,mb,b);

wrm(ma+mb,t);

delete []t;

return 0;

}

//ввод массива нужной длины

void rdm(int& k, int a[])

{// чтение массива

cout<<"\n kol-vo el-ov <= "<<n<<" ";

cin>>k;

cout<<"el-ti cherez probel:\n";

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

cin>>a[i];

}

//выдача массива

void wrm(int k,int a[])

{

cout<<"\n";

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

cout<<a[i]<<" ";;

cout<<"\n";

}