/*Program 9.2*/
#include
void main()
{
char C[5]; int I[5];
float F[5]; double D[5];
int i,j,k,n;
i = sizeof(C) / sizeof(char) ;
j = sizeof(I) / sizeof(int) ;
k = sizeof(F) / sizeof(float) ;
n = sizeof(D) / sizeof(double) ;
printf(“\n\n\n\n\ Размеp массива C - %d байт(ов)”/
“\n Число элементов в массиве C = %d”, sizeof(C), i);
printf(“\n\n Размеp массива I - %d байт(ов)”/
“\n Число элементов в массиве I = %d”, sizeof(I), j);
printf(“\n\n Размеp массива F - %d байт(ов)”/
“\n Число элементов в массиве F = %d”, sizeof(F), k);
printf(“\n\n Размеp массива D - %d байт(ов)”/
“\nЧисло элементов в массиве D = %d”, sizeof(D), n);
} Многомерный массив в языке С - это массив, элементами которого являются массивы. Синтаксис определения многомерного массива следующий:
Тип Имя_массива [][]...[];
В квадратных скобках - константы или константные выражения целого типа. Например, предложение:
double B[10][5];
определяет массив B, состоящий из 10 элементов, каждый из которых в свою очередь является одномерным массивом, состоящим из пяти переменных типа double. В памяти элементы многомерных массивов располагаются в порядке возрастания самого правого индекса. Для массив B это означает, что самый младший адрес имеет элемент B[0][0] за ним идет B[0][1], потом B[0][2], и т.д. до B[0][4]; потом располагаются B[1][0], B[1][1] и т.д. до B[1][4] и т.д. до B[9][0], B[9][1], ..., B[9][4].
В вычислительных задачах двумерные массивы часто используются для хранения матриц, поэтому иногда говорят, что массивы в языке С хранятся по строкам. Как и в случае одномерных массивов, доступ к элементам многомерных массивов возможен и с помощью индексированных переменных, и с помощью указателей. Возможно объединение этих двух способов в одном выражении. Так, например, *(B+2) адресует начал третьей строки массива B, а выражения:
*(*(B+1)) *(B[1]+1) *(1+1[B]) *(B+1)[1] B[1][1] - эквивалентны.
Доступ к элементам массива осуществляется с помощью адресной арифметики, т.е. с помощью указателей и операции разыменования. Чтобы получить доступ к элементу B[i][j], описанному выше массива B, компилятор выполнит следующие действия:
1. Для вычисления адреса i-той строки к адресу начала массива добавит смещение равное i*5*sizeof(double).
2. Для вычисления адреса j-того элемента в этой строке добавит смещение равное j*sizeof(double). Общее смещение становится равным (i*5+j)*sizeof(double).
3. К полученному адресу применит операцию разыменования, т.е. обеспечит доступ к содержимому элемента по его адресу.
В следующей программе проиллюстрированы различные способы доступа к элементам двумерного массива B, который предварительно формирутся и выводится на экран. Пример 3.
/*Program 9.3*/
#include
void main()
{
double B[10][5]; int i,j;
for (i=0; i<10; i++) {
for (j=0; j<5; j++)
B[i][j] = i*10 + (j+1);
}
for (i=0; i
printf (“\n”);
for (j=0; j
printf (“%8.2f “, B[i][j] );
}
printf(“\n\n B = %X”, B);
printf(“\n *B = %X”, *B);
printf(“\n **B = %G”, **B);
printf(“\n *(B+1) = %X”, *(B+1));
printf(“\n *(B+2) = %X”, *(B+2));
printf(“\n *(*(B+1)+2) = %G”, *(*(B+1)+2));
printf(“\n B[1][2] = %G”, B[1][2] );
} В С допускается использовать массивы указателей. Например, предложение float *C[10]; вводит массив из 10 указателей на элементы типа float.
И указатели на массивы, например, предложение float(*D)[10]; вводит указатель на массив из 10 элементов.
Выражение (C+1) соответствует перемещению в памяти на sizeof(float*) байт от начала массива. (D+1) перемещает на 10*sizeof(float) байтов т.е. на длину всего массива.
Применение массивов указателей позволяет эффективно решать проблему передачи в функции многомерных масссивов с переменными размерами. Или рационально использовать память при сортировке объектов с неодинаковыми размерами. Следующая программа демонстрирует использование одномерных массивов указателей при сортировке элементов матрицы, для хранения которой заводится двумерный массив. Строки располагаются в порядке уменьшения суммы аболютных значений элементов этой строки. Используется линейный механизм сортировки. Вводится массив указателей, который настраивается на строки исходной матрицы. Вместо перестановки строк осуществляется перестановка элементов в массиве указателей т.е. адресов строк. Результирующая матрица выводится на экран с помощью косвенной адресации (идексирования) массива указателей. Исходная матрица преобразованиями не затрагивается. Пример 4
/*Program 9.4*/
#include
#include
void main()
{
float a[10][10], *p_a[10], *pa, as[10], s;
int i,j,n;
// Задание с консоли матрицы a.
printf (“\n Введите размер матрицы a “);
scanf ( “%d”,&n);
printf (“\n Введите элементы матрицы a по строкам\n”);
for (i=0; i
for (j=0; j
scanf (“%f”,&a[i][j]); }
// Настройка элементов массива указателей p_a на строки матрицы a
for (i=0; i
// Вычисление сумм элементов в каждой строке.
for (i=0; i
for (s=0.,j=0; j
s += fabs(a[i][j]); }
as[i] = s; }
// Сортировка
for (j=0; j
for (i=j+1; i
if (as[j] < as[i]) { s=as[j]; as[j]=as[i]; as[i]=s;
pa = p_a[i]; p_a[i]=p_a[j]; p_a[j]=pa;
}
}
}
// Вывод результирующей матрицы и суммы элементов в каждой //строке на экран
printf (“\n\n”);
for (i=0; i
for (j=0; j
printf (“%7.2f”,p_a[i][j]); }
printf (“%12.2f\n”,as[i]); } }
Задания. 1. Откомпилируйте программы примеров и запустите их на выполнение. Изучите результаты работы этих программ.
2*. Напишите программу, заносящую все простые числа, лежащие между 2 и N, в одномерный массив и выводящую на экран по требованию простые числа находящиеся между задаваемыми L и M. N должно быть не менее 10000.
Указание. Начните с числа 2 как первого простого. Следующее число I будет простым, если оно не делится нацело на ранее найденные простые числа до SQRT(I) включительно. (Решето Эратосфена).
3*. Напишите программу, которая сортирует в порядке возрастания абсолютных значений вещественные переменные типа double, хранящиеся в одномерном массиве и найдите медиану. Медиана - это число, расположенное в середине упорядоченной последовательности чисел. Если число элементов этой последовательности четно, то нужно взять среднее арифметическое двух чисел, расположенных в середине. Исходная последовательность вводится с консоли. Алгоритм сортировки выберите самостоятельно.
4*. Напишите программу, выполняющую транспонирование исходной матрицы. Организуйте вывод обеих матриц - исходной и транспонированной на экран
5*. Напишите программу для ввода с консоли по строкам матрицы размера N на M. Прочтите и занесите в двумерный массив с ее помощью таблицу распределения Стьюдента. Ограничтесь числом измерений 2-11, 16, 21, 26, 51 и надежностью 0.6, 0.8, 0.9, 0.95, 0.98. Таблицу Стьюдента наберите и отредактируйте в файле. Для чтения используйте функцию перенаправления DOS << .
6.* Пусть в эксперименте получена серия прямых наблюдений величины A - { } Среднее квадратичное отклонение ряда измерений вычисляется по формуле :
,
где - погрешность i-того измерения, - среднее.
Доверительный интервал вычисляется как , где -коэффициент распределения Стьюдента с надежностью при числе наблюдений . Тогда с этой надежностью величина лежит в пределах - < < +
Напишите программу, обрабатывающую результаты измерений и выводящую на экран пределы доверительного интервала [ - , + ] и относительную погрешность ( / )*100% . Величины { }и надежность задаются с консоли. Коэффициент Стьюдента выбирается автоматически из таблицы, которая строится в предыдущем задании.
7*. Напишите программу для вычисления биномиальных коэффициентов :
a) по формуле

б) используя определение треугольника Паскаля

Занесите значения этих коэффициентов в двумерный массив. Для задаваемого с консоли N выведите на экран и запишите в файл, используя функцию перенаправления DOS >>, треугольник Паскаля. 8*. Получите первые 20 чисел последовательности Каталана (1,2,5,14, ...), занесите их в массив и выведите на экран. Последовательность постройте одним из двух способов :
а) Опускаясь по центральному столбцу треугольника Паскаля, построенного в предыдущем задании и вычитая из каждого центрального элемента соседний справа или слева.
b) Используя нерекуррентную формулу для n-го числа последовательности

9**. Напишите программу, выполняющую перестановку строк исходной матрицы. Строки нужно переставить таким образом, чтобы на главной диагонали оказались элементы большие по абсолютному значению элементов стоящих под ними в этом же столбце. Исходную матрицу сформируйте в программе и выведите ее и отсортированную матрицу на экран.
10**. Напишите программу, которая по запрашиваемым с консоли коэффициентам и правым частям системы линейных алгебраических уравнений (СЛАУ) :




решает ее подстановками снизу вверх. Из последнего уравнения находится , из предпоследнего, зная , можно найти и т.д. до . Проверьте правильность работы Вашей программы на каком-нибудь конкретном примере с числом уравнений в системе не менее четырех.
11**. Напишите программу, переставляющую строки исходной матрицы таким образом, чтобы след получающейся матрицы был максимально возможным. След матрицы - это сумма диагональных элементов.
Лабораторные работа № 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-ый - нулевыми. Однако при таком способе задания координат векторов каждое их изменение потребует перекомпиляции программы.
Используем полученную программу перемножения векторов для нахождения угла между ними. Косинус угла вычисляется по формуле
, где , - нормы векторов.
Для определения угла необходимо трижды вычислить скалярные произведения , и Оформим вычисление скалярного произведения в виде отдельной функции.
Пример 2.
|