Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Практикум по программированию на языке Си

..pdf
Скачиваний:
24
Добавлен:
12.11.2023
Размер:
3.53 Mб
Скачать

ЗАДАНИЕ. Преобразуйте программу 06_16.с, сделав n и m глобальными переменными по отношению к функции main().

Задачу решает программа 06_16_2.c.

Все предложенные варианты программ, в которых создаются двумерные массивы с переменными размерами, не удовлетворяют требованиям традиционного (не стандартного) языка Си.

ЗАДАНИЕ. Напишите программу, решающую поставленную задачу с учетом ограничений традиционного Си.

Будем отдельно определять размеры (предельные) двумерного массива и той матрицы, которая должны быть размещена в этом массиве. Размеры массива зададим с помощью препроцессорных констант N и M. Размеры формируемой матрицы (значения n и m) будем вводить с клавиатуры. Ошибкой в исходных данных следует считать условие N<n или M<m. Заданию соответствует следующая программа:

/* 06_16_3.c - двумерный массив для матрицы переменных размеров */

#include <stdio.h> #define N 10 #define M 10

int main ()

{

int i, j;

int matr[N][M]; int n, m;

printf("n="); scanf("%d",&n); printf("m="); scanf("%d",&m); if (m>M || n>N)

{ printf("Error! (m>M || n>N)"

"\nm=%d, M=%d, n=%d, N=%d,",m,M,n,N); return 0;

}

for (i=0; i<n; i++) for (j=0; j<m; j++)

matr[i][j]=(i+1)+(j+1); for (i=0; i<n; i++)

{printf("\n");

for (j=0; j<m; j++)

201

printf ("matr[%d,%d]=%d\t",i+1,j+1,matr[i][j]);

}

return 0;

}

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

Вариант с ошибкой в исходных данных:

n=23<ENTER>

m=5<ENTER>

Error! (m>M || n>N) m=5, M=10, n=23, N=10,

Правильный ввод исходных данных:

n=4<ENTER>

m=3<ENTER>

matr[1,1]=2 matr[1,2]=3 matr[1,3]=4 matr[2,1]=3 matr[2,2]=4 matr[2,3]=5 matr[3,1]=4 matr[3,2]=5 matr[3,3]=6 matr[4,1]=5 matr[4,2]=6 matr[4,3]=7

ЗАДАЧА 06-17. Введите предельные значения вещественных

величин xmin, xmax, ymin, ymax и количества значений nx, ny, принимаемых соответственно переменными xi, yi, равномерно разме-

щенными на интервалах:

xi (xmin xi xmax ), i = 1,nx ;

yi ( ymin yi ymax ), i = 1, ny ;

Сформируйте в виде двумерного массива матрицу aijс размерами nx, ny и присвойте ее элементам значения

aij = F(xi , y j ) = sin y j cos xi .

Распечатайте по строкам полученную матрицу.

Решение, соответствующее Стандарту 99 языка Си, предлагается в следующем виде:

202

/* 06_17.c - вещественная матрица с переменными размерами */

#include <stdio.h> #include <math.h>

#define READD(VARIABLE) \ {printf(#VARIABLE"=");scanf("%le",&VARIABLE);}

#define READI(VARIABLE) \

{printf(#VARIABLE"="); scanf("%d",&VARIABLE);} int main ()

{

int nx, ny;

double xmin,xmax,ymin,ymax,x,y; READI(nx);

READI(ny);

READD(xmin);

READD(xmax);

READD(ymin);

READD(ymax);

{int i, j;

double a[nx][ny]; for (i=0; i<nx; i++) for (j=0; j<ny; j++)

{x=xmin+i*(xmax-xmin)/(nx-1); y=ymin+j*(ymax-ymin)/(ny-1); a[i][j]=sin(y)-cos(x);

}

for (i=0; i<nx; i++) { printf("\n");

for (j=0; j<ny; j++) printf("a[%d,%d]=%8.5f\t",i+1,j+1,a[i][j]);

}

}

return 0;

}

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

nx=5<ENTER>

ny=3<ENTER>

xmin=2.0<ENTER>

xmax=4.0<ENTER>

ymin=0.12<ENTER>

ymax=8.0<ENTER>

203

a[1,1]= 0.53586

a[1,2]=-0.37849

a[1,3]= 1.40551

a[2,1]= 0.92086

a[2,2]= 0.00651

a[2,3]= 1.79050

a[3,1]= 1.10970

a[3,2]=

0.19536

a[3,3]= 1.97935

a[4,1]=

1.05617

a[4,2]=

0.14182

a[4,3]=

1.92581

a[5,1]=

0.77336

a[5,2]=-0.14099

a[5,3]=

1.64300

Для удобного ввода исходных данных использованы макросы, предложенные в задаче 03-11 темы 3. Обратите внимание на применение библиотечных математических функций sin() и cos(). Чтобы они были доступны, в программу включен заголовочный файл math.h.

ЭКСПЕРИМЕНТ. Откомпилируйте программу 06_17.с с помощью классического компилятора, не соответствующего требованиям Стандарта 99. Убедитесь в появлении ошибок трансляции, связанных с не константными выражениями в определении размеров массива.

ЗАДАНИЕ. Модифицируйте программу 06_17.с, приведя ее в соответствие с требованиями традиционного языка Си. Например, используйте препроцессорные константы для задания размеров двумерного массива. Размеры матрицы введите с клавиатуры и выполните проверку допустимости их значений. В качестве прототипа используйте программу 06_16_3.с.

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

ЗАДАЧА 06-18. В прямоугольной вещественной матрице с размерами n на m (где n<10 и m<10) определите индексы и значение элемента, который по модулю наименее отличается от среднего арифметического всех элементов матрицы. Размеры матрицы вводите с клавиатуры, а значения ее элементов формируйте в диапазоне от –1000 до +1000 с помощью датчика псевдослучайных чисел. Решение оформите в виде двух программ: про-

204

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

Программа генерации может использовать следующие средства стандартной библиотеки (описаны в заголовке stdlib.h): rand() и

RAND_MAX.

Функция rand() при каждом обращении возвращает псевдослучайное значение типа int из диапазона от 0 до RAND_MAX.

RAND_MAX – препроцессорная константа, определяющая предельное значение псевдослучайных целых чисел, формируемых функцией rand(). Конкретное значение RAND_MAX зависит от реализации (конкретного компилятора), но не может быть менее 32767 (требование Стандарта языка Си).

По условию задачи числовые значения элементов матрицы должны находиться в диапазоне от –1000 до +1000. Следовательно, очередное значение элемента можно вычислять по формуле:

rand()*(1000+1000)/RAND_MAX-1000

Вычисление элементов матрицы будем выполнять по "строкам", т.е. для матрицы ║xij║ последовательно определяются значения x11,

x12, …,x1m, x21,…,xn,m-1, xnm.

Программа генерации данных для формирования матрицы:

/* 06_18A.c - формирование значений элементов матрицы */

#include <stdio.h>

#include <stdlib.h> //для RAND_MAX и rand() #define N 10

#define M 10 int main ()

{

int i, j; int n, m;

double element;

printf("n="); scanf("%d",&n); printf("m="); scanf("%d",&m); if (m>M || n>N)

{ printf("Error! (m>M || n>N)"

"\nm=%d, M=%d, n=%d, N=%d,",m,M,n,N);

205

return 0;

}

printf("\n%d",n);

printf("\n%d",m); for (i=0; i<n; i++) for (j=0; j<m; j++)

{ element=2000*(double)rand()/RAND_MAX - 1000; printf("\n%8.2f",element);

}

return 0;

}

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

Вариант с ошибкой в исходных данных:

n=18<ENTER>

m=22<ENTER>

Error! (m>M || n>N) m=22, M=10, n=18, N=10,

Правильный ввод исходных данных:

n=2<ENTER>

m=3<ENTER>

2

3

-755.77 -806.25 -254.75 -600.99 -955.56

670.75

В тексте программы обратим внимание на следующие особенности. Чтобы были доступны функция rand() и препроцессорная константа RAND_MAX, включена директива #include<stdlib.h>. После ввода желаемых размеров матрицы выполняется сравнение значений переменных n (число строк), m (число столбцов) с препроцессорными константами N и M, которые определяют предельные размеры двумерного массива для представления матрицы в программе обработки.

206

После ввода и проверки допустимости значений переменных n и m, они выводятся в стандартный выходной поток stdin функцией printf().

Вычисление значений элементов будущей матрицы выполняются по строкам в двойном цикле. Целое значение, возвращаемое функцией rand(), явно преобразуется к типу double. Затем выполняется приведение к диапазону 1000÷ +1000. Каждое вычисленное значение (переменная element) сразу же в теле цикла выводится в стандартный выходной поток stdin. При выводе в форматной строке функции printf() использована спецификация преобразования %8.2f. В ней f – спецификатор вывода вещественного числа в форме с фиксированной точкой. Поле вывода – 8 позиций, из них 2 позиции для цифр после десятичной точки (2 знака в дробной части числа). При этом для представления целой части со знаком отводится 5 позиций. Этого вполне достаточно, так как значения элементов матрицы по условию задачи должны быть в диапазоне от 1000 до +1000.

Варианты выполнения программы при умалчиваемых назначениях потоков stdin, stdout показаны выше вслед за текстом программы. Переназначение стандартного выходного потока stdout, выполняемое по команде

…>test.exe>result<ENTER>

приведет к таким результатам:

на экране:

4<ENTER>

3<ENTER>

в файле result:

n=m=

4

3

-755.77 -806.25 -254.75 -600.99 -955.56

670.75

207

437.24

168.87

160.36 -582.69 714.84 -21.36

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

/* 06_18B.c -поиск в матрице элемента с заданными свойствами */

#include <stdio.h>

#include <math.h> // для fabs() #define N 10

#define M 10 int main ()

{

int i, j;

double matr[N][M];

double sum=0.0, middle,min; int n, m, imin, jmin; scanf("%*s%d",&n); scanf("%d",&m); printf("\nn=%d",n); printf("\tm=%d",m);

if (m>M || n>N)

{ printf("Error! (m>M || n>N)"

"\nm=%d, M=%d, n=%d, N=%d,",m,M,n,N); return 0;

}

for (i=0; i<n; i++) for (j=0; j<m; j++)

{scanf("%lf",&matr[i][j]);

sum+=matr[i][j];

printf("%c[%d,%d]=%8.2f",

j == 0 ?'\n':'\t',i+1,j+1,matr[i][j]);

}

middle=sum/(n*m);

printf("\nmiddle=%8.2f",middle); min=fabs(matr[0][0]-middle);

208

for (i=0, imin=jmin=0; i<n; i++) for (j=0; j<m; j++)

if (fabs(matr[i][j]-middle)<min)

{imin=i;

jmin=j;

min=fabs(matr[i][j]-middle);

}

printf("\nimin=%d, jmin=%d, min=%8.2f", imin+1,jmin+1,matr[imin][jmin]);

return 0;

}

Результаты выполнения программы при чтении данных из файла result:

n=4

m=3

[1,2]= -806.25

[1,3]= -254.75

[1,1]= -755.77

[2,1]= -600.99

[2,2]= -955.56

[2,3]=

670.75

[3,1]=

437.24

[3,2]=

168.87

[3,3]=

160.36

[4,1]= -582.69

[4,2]=

714.84

[4,3]=

-21.36

middle=

-152.11

min= -254.75

 

 

imin=1,

jmin=3,

 

 

В программе используется библиотечная функция fabs(), вычисляющая абсолютное значение аргумента типа double. Для обеспечения доступа к ней включен заголовочный файл <math.h>. Далее определены препроцессорные константы N и M, использованные затем в определении вещественного массива для матрицы. Переменные: sum – для суммы элементов матрицы; middle – для среднего значения элементов; min - текущее значение модуля разности между средним и очередным элементом; imin, jmin – индексы элемента со значением, ближайшим к среднему; n, m – реальные размеры матрицы, считываемые из входного потока, роль которого выполняет файл result.

В первом обращении к функции scanf() с помощью спецификации преобразования "%*s" реализуется пропуск последовательности "n=m=", затем по спецификации "%d" вводятся значения переменных n и m. После ввода значений n и m выполняется проверка допустимо-

209

сти введенных размеров матрицы. Если матрица с заданными размерами может разместиться в массиве matr[N][M], то во вложенных циклах выполняется считывание из stdin (из файла result) вещественных значений элементов матрицы. При чтении используется спецификация преобразования "%lf", предусмотренная для типа double. В том же цикле подсчитывается сумма элементов матрицы и выполняется печать ее элементов.

При выводе значений элементов каждому отводится 8 позиций, из которых две – для дробной части (спецификация %8.2f). Матрица выводится "по строкам", выравнивание расположения элементов достигается с помощью табуляции. Выбор символа ‘\n’ или ‘\t’ выполняет условное (тернарное) выражение. При истинности условия "j==0" выводится ‘\n’, т.е. выполняется переход на новую строку. Вывод выбранного символа '\n' или '\t' осуществляется по спецификации %c. Для наглядности выводятся не индексы элементов массива (начинающиеся с 0), а номера строк (i+1) и столбцов (j+1). Далее после вычисления среднего значения элементов матрицы (переменная middle) в двойном цикле анализируются значения всех элементов. Для элемента, минимально уклоняющегося от среднего значения, запоминаются уклонение (min) и индексы (imin, jmin). Значение выбранного элемента матрицы и номера строки и столбца, в которых он находится, выводятся как результат.

ЭКСПЕРИМЕНТ. В программе, формирующей значения элементов матрицы, (06_18A.с) замените спецификацию %8.2f на спецификацию %f. Оцените результат при выводе.

ЭКСПЕРИМЕНТ. В программе 06-18A.с удалите приведение типов (double) из выражения для вычисления значения переменной element. Объясните результаты исполнения.

ЭКСПЕРИМЕНТ. Подготовьте в текстовом файле с произвольным именем исходные данные, пригодные для чтения программой формирования и обработки матрицы (06_18B.с). Выполните программу, читая данные из созданного файла.

210