Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информатика 1 курс / метод указания / Информатика. Основы программирования на С++. Учебное пособие.doc
Скачиваний:
142
Добавлен:
08.06.2015
Размер:
2.15 Mб
Скачать

Результат выполнения программы

Исходный массив чисел:

mas[3][4]=

5 8 4 2

4 9 6 4

1 5 6 8

Норма матрицы=23

!! Проанализируйте программу. Создав новый файл проекта с именем ukaz_2.ide, наберите в нем текст данной программы, откомпилируйте ее и произведите запуск программы на выполнение.

Указатели и динамическое распределение памяти – мощное средство С++. Однако возможности, которые получает программист при работе с указателями, накладывают на него большую ответственность, так как наибольшее количество ошибок вносится в программу именно при работе с указателями. К характерным ошибкам можно отнести следующие "промахи" неопытных программистов.

  1. Использование неверного адреса в операции delete. В результате внутренняя структура памяти будет испорчена, что может привести к порче нужной информации.

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

  3. Запись по неверному адресу. В результате, скорее всего, будут испорчены какие-либо данные, получен неверный результат, сбой программы и т.п. Ошибку определить в этом случае очень сложно, так как она обычно проявляется не сразу.

7.3. Указатели и функции

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

В списке параметров такой функции перед именем переменной указывается символ косвенной адресации '*', который свидетельствует о том, что в функцию передается указатель на переменную. В теле функции тоже перед именем параметра ставится символ операции разыменования '*'.

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

Пример. Обмен значениями двух переменных.

# include <iostream.h>

void chage (float*, float*); // прототип функции

void main ( )

{ float a,b;

cin>>a>>b; //ввод значений переменных

сhage (&a, &b); //вызов функции

cout<<"a="<<a<<"\tb="<<b;

}

void chage (float *x, float *y) //х, у - указатели

{ float z;

z=*x; *x=*y; *y=z; //обмен значениями

}

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

(int n, float a[], float b[]) //традиционный способ

(int n, float *a, float *b) //альтернативный способ

Для динамических массивов применяется второй вариант определения функции.

Если используются динамические двумерные массивы, то в заголовке функции записывается указатель на массив указателей на строки матрицы:

(int n, float **a, float **b)

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

Например:

double**matr(intn,intm) //n,m– размерности массива

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

Пример. Перемножение матриц А и В соответственно с размерностями (nxm) и (mxr) (лист. 7.3).

Листинг 7.3. ukaz_3.сpp

/*Программа перемножения матриц С=А*В

соответственно с порядками [n*m],[m*r]*/

#include <iostream.h>

#include <iomanip.h>

void mult_matr(int,int,int,int**,int**,int**);

void cin_matr( int,int,char,int**);

void cout_matr(int,int,char,int**);

int **RAM(int,int);

void del_RAM(int,int**);

void main()

{

int n,m,r,**a,**b,**c;

//Ввод размерностей матриц

cout<<"Введите размерности матриц:\n";

cout<<" n=",cin>>n;

cout<<" m=",cin>>m;

cout<<" r=",cin>>r;

a=RAM(n,m); //Выделение памяти под матрицу A

b=RAM(m,r); //Выделение памяти под матрицу B

c=RAM(n,r); //Выделение памяти под матрицу C

//Вызовы функций

cin_matr(n,m,'A',a); //Ввод матрицы А

cin_matr(m,r,'B',b); //Ввод матрицы В

mult_matr(n,m,r,a,b,c); //Вычисление матрицы С

cout_matr(n,m,'A',a); //Вывод матрицы А

cout_matr(m,r,'B',b); //Вывод матрицы В

cout_matr(n,r,'C',c); //Вывод матрицы С

//Освобождение выделенной памяти

del_RAM(n,a); //под массив А

del_RAM(m,b); //под массив В

del_RAM(n,c); //под массив С

}

//Функция выделения памяти

int **RAM(int p,int q)

{int **s;

s=new int*[p];

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

s[i]=new int[q];

return s;

}

//Функция освобождения памяти

void del_RAM(int k,int**z)

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

delete z[i];

delete []z;

}

//Функция ввода матрицы

void cin_matr(int p,int q,char Y,int**X)

{cout<<"\nВведите элементы матрицы "<<Y<<endl;

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

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

{

cout<<Y<<"["<<i<<"]"<<"["<<j<<"]=";

cin>>X[i][j];

}

}

//Функция вывода матрицы

void cout_matr(int p,int q,char Y,int**X)

{

cout<<"\n Матрица "

<<Y<<"["<<p<<"]"<<"["<<q<<"]=\n";

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

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

{ cout<<setw(6)<<X[i][j];

if(j==q-1)cout<<endl;

}

}

//Функция перемножения матриц С=А*В

void mult_matr(int N,int M,int R,

int **A,int **B,int **C)

{ for(int i=0;i<N;i++)

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

{

C[i][j]=0;

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

C[i][j]+=A[i][k]*B[k][j];

}

}