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



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

/*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. Оформите для этого программу перемножения матрицы на матрицу в виде отдельной функции.


Лабораторная работа 12

1. Ввод и вывод символов. Копирование файла.

Стандартная библиотека включает функции для чтения и записи по одному символу за один раз: getchar(); putchar(). Функция getchar() извлекает следующий вводимый символ каждый раз, когда к ней обращаются, и возвращает этот символ в качестве своего значения. Это значит, что после c = getchar() переменная 'c' содержит следующий символ из входных данных. Символы обычно вводятся с клавиатуры. Функция putchar(c) является дополнением к getchar() : в результате обращения putchar (c) содержимое переменной 'c' выдается на некоторый выходной носитель, обычно на монитор.

Как и функция printf , функции getchar и putchar не содержат ничего экстраординарного.Они не входят в состав языка "C", но к ним всегда можно обратиться, если подключить библиотеку. Имея в своем распоряжении только функции getchar и putchar Вы можете, не зная ничего более об операциях ввода–вывода, написать удивительное количество полезных программ. Простейшим примером может служить программа посимвольного копирования вводного файла в выводной. Общая схема имеет вид:

ввести символ

while (символ не является признаком конца файла)

вывести только что прочитанный символ

ввести новый символ

Пpимеp 1. Программа, написанная на языке "C", выглядит следующим образом:

main() /* copy input to output; 1st version */

{ int c;

c = getchar();

while (c != EOF)

{ putchar (c);

c = getchar(); }

}
Основная проблема заключается в том, чтобы зафиксировать конец файла ввода. Обычно, когда функция getchar наталкивается на конец файла ввода, она возвращает значение, не являющееся действительным символом; таким образом, программа может установить, что файл ввода исчерпан. Единственное осложнение, являющееся значительным неудобством, заключается в существовании двух общеупотребительных соглашений о том, какое значение фактически является признаком конца файла. Мы отсрочим решение этого вопроса, использовав cимволическое имя EOF для этого значения, каким бы оно ни было. На практике EOF будет либо –1, либо 0, так что для правильной работы перед программой должно стоять собственно либо

#define EOF -1

либо #define EOF 0

Использовав символическую константу EOF для представления значения, возвращаемого функцией getchar при выходе на конец файла, мы обеспечили, что только одна величина в программе зависит от конкретного численного значения. Мы также описали переменную 'c' как int , а не char, с тем чтобы она могла хранить значение, возвращаемое getchar (эта величина действительно int, так как она должна быть в состоянии в дополнение ко всем возможным символам представлять и EOF).

Программистом, имеющим опыт работы на "C", программа копирования была бы написана более сжато. В языке "C" любое присваивание, такое как c = getchar() может быть использовано в выражении; его значение – просто значение, присваиваемое левой части. Если присваивание символа переменной 'c' поместить внутрь проверочной части оператора while, то программа копирования файла запишется в виде:
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