Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели



страница2/8
Дата29.04.2013
Размер0.57 Mb.
ТипПрактикум
1   2   3   4   5   6   7   8

Лабораторные работа № 11

Работа с векторами и матрицами.

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

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

В качестве первого примера рассмотрим программу, скалярно перемножающую два вектора x и y произвольного размера N. Перемножение осуществляется по обычному правилу:



Для хранения элементов векторов используются одномерные массивы.

Пример 1.

/*Program 10.1*/

#include

#include

void main()

{

float x[100], y[100], scal; int i,n; char* str; // (1)

printf(“\n Введите размерность векторов N “); // (2)

gets(str); // (3)

n=atoi(str); // (4)
printf(“\n Введите координаты вектора x \n “); // (5)

for(i=0;i

printf(“\n Введите координаты вектора y \n “); // (7)

for(i=0;i

for (i=0;i

printf ( “\n\n Скалярное произведение (x*y) = %f”,scal); // (10)

}

Требуется ввести с консоли размерность векторов N и их координаты (строки 2-8). Затем в цикле эти вектора перемножаюгся (строка 9), результат записывается в переменную scal и выводится на экран (строка10). Элементы массивов x и y можно было бы задавать не с консоли, а непосредственно инициализируя массивы. В этом случае вместо строки (1) следует написать, например,

float x[100] = {1., 2., 3., 4., 5.};

float y[100] = {-.1, -.2, -.3, -.4,-.5, -.6};

Элементы массива x с 0-го по 4-ый получают значения 1.,2.,3.,4.,5. . Остальные 95 элементов не инициализируются, и компилятор автоматически присваивает им всем нулевые значения. Аналогично, первые 6 элементов массива y будут инициализированы значениями -.1, -.2, -.3, -.4, -.5, -.6 , а оставшиеся с 6-го по 99-ый - нулевыми. Однако при таком способе задания координат векторов каждое их изменение потребует перекомпиляции программы.

Используем полученную программу перемножения векторов для нахождения угла между ними. Косинус угла вычисляется по формуле

, где , gif" name="object39" align=absmiddle width=94 height=49> - нормы векторов.

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

Пример 2.

/*Program 10.2*/

/* Вычисление угла между двумя векторами x и y, заданными в многомерном евклидовом пространстве размерности N.*/

#include

#include

#include

#include


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

{

float s=0; int i; // (1)

for(i=0;i

return(s); // (3)

}

void main()

{

float x[100], y[100], fi; int i,n; char* str;

system(“cls”); //Выполняет команду DOS очистки экрана.

printf(“\n Введите размерность векторов N “);

gets(str);

n=atoi(str);

printf(“\n Введите координаты вектора x \n “);

for(i=0;i

printf(“\n Введите координаты вектора y \n ”);

for(i=0;i

// Вычисление угла:

fi = acos( scal(x,y,n) / sqrt( scal(x,x,n) * scal(y,y,n) ) );

// Вывод результатов.

printf ( “\n\n Угол между векторами = %f”, fi );

}

Размерность векторов N и их координаты вводятся с консоли. Функция scal() вызывается из главной программы трижды с разными фактическими параметрами. Вычисляется угол и результат выводится на экран. Обратите внимание на способ передачи параметров в функцию scal() из основной программы. По правилам языка C при передаче простой переменной в функцию передается ее значение, а при передаче массива - адрес начала размещения этого массива в памяти. Изменяя локальную переменную, являющуюся формальным параметром в вызываемой функции, мы не затрагиваем соответствующую ей простую переменную - фактический параметр в вызывающей функции. Иная ситуация при работе с массивами. И вызывающая , и вызываемая функции ссылаются на один и тот же участок памяти и, следовательно, изменение значений элементов массива - формального параметра в вызываемой функции приводят к точно таким же изменениям фактического параметра в вызывающей функции.

В качестве фактических параметров при вызове функции scal() из главной функции используются имена массивов x и y. (Имена массивов являются указателями на начало размещения массивов в памяти, а значениями этих указателей служат адреса.) В определении самой функции scal() этим именам соответствуют формальные параметры - указатели float*a и float*b того же типа, что и элементы массивов x и y. С помощью этих указателей, используя адресную арифметику, функция scal() получает доступ к соответствующим элементам массивов x и y. Для иллюстрации в строке 2 доступ осуществляется и с помощью индексирования, и с помощью операции разыменования.

Для создания программы, которая будет перемножать матрицу на вектор-столбец используем ту же функцию scal() перемножения векторов. Операцию умножения матрицы на вектор определим обычным правилом: i-тая строка матрицы скалярно умножается на вектор-столбец и даёт i-тый элемент результирующего вектора. При таком определении, очевидно, число столбцов матрицы должно совпадать с числом элементов вектор-столбца.

Пример 3.

/*Program 10.3*/

#include

#include

#include


float scal(float*,float*,int);

void main()

{

static float a[100][100], b[100], c[100];

int i,j,n,m; char* str;

system(“cls”); //Выполняет команду DOS очистки экрана.

printf(“\nВведите размеры матрицы :”);

printf(\n число столбцов N “); gets(str); n = atoi(str);

printf(“\nчисло строк M “); gets(str); m = atoi(str);

// Формирование матрицы A и вектор-столбца B.

for(i=0;i

for(j=0;j

//Вызов функции перемножения векторов.

for(i=0;i

printf(“\n\n Компоненты результирующего вектора :”);

for(i=0;i

}

При вызове функции scal() в неё передаются в качестве параметров i-тая строка матрицы A и вектор b. a[i] является указателем на нулевой элемент i-той строки двумерного массива a, а имя одномерного массива b являтся указателем на начало его расположения в памяти. В определении функции scal() им соответствуют формальные параметры - указатели float *a, float*b. С помощью индексирования в функции scal() становятся доступными элементы i-той строки массива a и массива b. Главная программа содержит некоторые отличия от описанной в предыдущем примере.

Во-первых массивы a,b,c описаны с классом static. Связано это с особенностями использования памяти компилятором TС++. По умолчанию в C все данные имеют класс auto и размещаются в стеке. Предусмотрена возможность размещать данные в других сегментах. Для этого они могут быть описаны с классом static, и(или) программы должны компилироваться для большой (large) модели памяти. Для двумерных массивов N на N типа float это ограничивает их размер N = sqrt(64000/sizeof(float)) = 128. Если потребуется работать с массивами большего размера,нужно установить модель Huge при компиляции программы и использовать модификатор huge при объявлении массива. (На ТС этот режим не реализован.)

Второе отличие - объявление прототипа функции scal(). Синтаксис объявления прототипа похож на синтаксис объявления функции, но вместо параметров функции могут стоять только их типы и в конце объявления прототипа должна стоять точка с запятой. Появление прототипов связано с особенностями работы компиляторов языка С. К моменту, когда компилятор, последовательно обрабатывающий строки исходного текста, доходит до вызова функции, он уже должен “знать” какое количество памяти нужно зарезервировать в стеке для передачи параметров и возвращаемого функцией значения. В связи с этим, функция либо должна быть определена до вызова, как это сделано в примере 2, либо должен быть описан её прототип как в примере 3. В прототипе обязательно должен указываться тип возвращаемого значения и типы формальных параметров. При вызове функции формальные параметры заменяются фактическими, при этом язык С предусматривает автоматическое преобразование типов в тех случаях, когда тип фактических параметров не совпадает с типом формальных.

Вообще говоря, если вызывающая и вызываемая функции размещаются в одном файле, использование прототипа в языке С в тех случаях, когда вызов функции размещён до её определения, не является обязательным. (В отличие от С++). Например, если в примере 3 и главная функция, вычисляющая угол, и функция scal, перемножающая вектора, будут находится в одном файле, то строку с описанием прототипа можно закоментировать - результат не изменится. Если же вызываемая функция размещается в другом файле использование прототипа обязательно. Это относится и к стандартным библиотечным функциям, прототипы которых описаны в заголовочных файлах. (Они имеют расширение .h и находятся в подкаталоге INCLUDE).

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

Пример 4.

/*Program 10.4*/

/*Функция перемножения двух квадратных матриц A и B размером N на N с вызовом функции mult() перемножения матрицы на вектор. Матрицы A и B формируются в главной функции. В функцию mult() передается указатель на массив указателей на строки матрицы A - ptl_A (point to line of A) и указатель на столбцы матрицы B (на строки транспониованной матрицы B) - ptl_b. Возвращаемое значение - указатель ptl_c на столбцы результирующей матрицы C.*/

#include

#include

#include

#include


void mult(float**,float*,float*,int); // Пототипы функций mult() и

float scal(float*,float*,int); // scal().

void main()

{

static float a[50][50],b[50][50],c[50][50];

float *ptl_A[50], *ptl_b, ptl_c[50], btmp;

int i,j,n; char* str;

system(“cls”); // Функция выполняет команду DOS очистки экрана.

printf(“\nВведите N “); gets(str); n=atoi(str);

// Настройка массива указателей ptl_A на строки массива A.

for(i=0;i

// Формирование матриц A и B.

for(i=0;i

for(j=0;j

// Подготовка (транспонирование) матрицы B к перемножению.

for(i=0;i

for(j=0;j

// Перемножение матрицы на матрицу с вызовом функции умножения // матрицы на вектор.

for(i=0;i

ptl_b = (float*)&b[i]; //Настройка указателя на i-тую строку

//матрицыB

mult(ptl_A, ptl_b, ptl_c, n); // Вызов функции mult.

for(j=0;j

c[j][i] = ptl_c[j]; }} // матрицы.

// Восстановление исходной матрицы B.

for(i=0;i

for(j=0;j

// Вывод результирующей матрицы на экран.

printf(“\n\n Результирующая матрица”);

for(i=0;i

for(j=0;j

printf(“%8.3f”,c[i][j]);

}

}

// Функция перемножения матрицы на вектор.

void mult(float**a,float*b,float*c,int n)

{

float *ptl_A; int i;

for(i=0;i

ptl_A = (float*)&a[i][0];

c[i] = scal(ptl_A,b,n); }

}

Функция scal() описана выше.

Для передачи массива а переменного размера n в качестве параметра в функцию mult() перемножения матрицы на вектор используется промежуточный одномерный массив указателей ptl_A, в котором сохраняются адреса строк масива a. Эта процедура требует некоторых пояснений. В функцию mult() перемножения матрицы на вектор требуется передавать двумерный массив - матрицу A и одномерный массив - очередной вектор-столбец матрицы B. С передачей одномерного массива проблем не возникает. Учитывая, что в памяти машины матрицы хранятся по строкам, транспонируем матрицу B и тогда указатель на j-тую строку транспонированной матрицы будет одновременно адресовать j-тый столбец исходной матрицы. Этот указатель и передается в функцию mult() в качестве второго параметра.

С передачей двумерных массивов переменных размеров возникают некоторые сложности связанные с тем, что компилятор не может распознать по имени массива его размерность и размеры. Чтобы обойти эту трудность можно, например, подменить двумерный массив одномерным и иммитировать доступ внутри функции к двумерному массиву. В нашей программе использован другой способ. Заводится вспомогательный массив указателей *point_A[100], который настраивается на строки исходной матрицы A, т.е. элементам массива *point_A присваиваются адреса, с которых начинаются строки массива a. И именно этот одномерный массив указателей передается в функцию mult() в качестве первого фактического параметра. Так как имя любого массива есть указатель на его нулевой элемент, то в функцию mult() передается указатель на массив указателей.

Задания.

1. Изучите приведенные в примерах 1-4 программы. Скопируйте эти программы к себе в каталог. Убедитесь в правильности их работы.

2*. Напишите пограмму перемножающую по обычному правилу матрицу размера N на N, на вектор-столбец размера N. Матрицу и вектор сформируйте в программе, и выведите их вместе с результирующим вектором на экран.

3*. По аналогии с программой из примера 4 напишите программу перемножения прямоугольных матриц A размера N на M и B размера M на N, оформив транспонирование матрицы B в виде отдельной функции.

4**. Напишите программу непосредственно перемножающую две матрицы без обращения к функциям перемножения матрицы на вектор и вектора на вектор. Оформите ее в виде отдельной функции.

5**. Напишите программу, вычисляющую коммутатор двух квадратных матриц A и B размера N на N, т.е. матрицу равную разности произведения A на B и B на A. Оформите для этого программу перемножения матрицы на матрицу в виде отдельной функции.

1   2   3   4   5   6   7   8

Похожие:

Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconЛабораторная работа №1 36 Лабораторная работа №2 47 введение данное учебно-методическое пособие представляет собой сборник лабораторных работ
Предлагаемый лабораторный практикум является руководством для выполнения лабораторных работ. Практикум охватывает основные темы дисциплины....
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconЛабораторная работа по теме: «Одномерные массивы»
Дан массив целых чисел. Найти максимальный элемент массива и его порядковый номер
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconЛабораторная работа №1 Работа в Oracle Database Express Edition 1 Лабораторная работа №6
Лабораторная работа Выполнение расчетов с использованием программирования в среде Visual Basic for Applications
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconПрактикум по курсу Информатика (раздел Работа с пакетами прикладных программ) для студентов заочной формы обучения
Лабораторная работа №6. Обобщение данных. Создание таблицы подстановки. Подведение итогов 28
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconК ф. м н. А. О. Беляков. Список публикаций
Замечания к статье Л. Д. Акуленко и С. В. Нестерова "Устойчивость равновесия маятника переменной длины". Пмм. 2009. Т. 73. Вып. С....
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconРабочая учебная программа «История и культура страны изучаемого языка»
Форма контроля: 1 курс, второй семестр – зачет; 2 курс, третий семестр – экзамен
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconРабочая учебная программа «История и культура страны изучаемого языка»
Форма контроля: 1 курс, второй семестр – зачет; 2 курс, третий семестр – экзамен
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconПрактикум по гидробиологии Выписка из учебного плана. Форма обучения: очная Курс: IV семестр: VII
Реквизиты составителя. Доцент кафедры зоологии, к б н. Анастасия Михайловна Ларионова
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconЛабораторная работа «Одномерные массивы»
Цели: формирование практических умений и навыков составления блок-схем и записи на языке программирования Паскаль алгоритмов заполнения,...
Практикум по пмм ( 2 курс, 3 семестр ) Волгоград, 1998 Лабораторная работа №1 Массивы и указатели iconПрактикум по герпетологии Выписка из учебного плана. Форма обучения: очная Курс: IV семестр: VIII
Реквизиты составителя. Старший преподаватель кафедры зоологии Василий Егорович Колодезников
Разместите кнопку на своём сайте:
ru.convdocs.org


База данных защищена авторским правом ©ru.convdocs.org 2016
обратиться к администрации
ru.convdocs.org