Лекция 3 (20.09.2021)
над последовательностями чисел в файле.
Задача 1. Является ли последовательность постоянной?
Не использовать feof()!!!
#include <stdio.h>
int main(void) {
FILE *IN;
int first, num;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
if (fscanf(IN, "%d", &first) != 1) {
printf("File empty\n");
fclose(IN);
return -1;
}
while (fscanf(IN, "%d", &num) == 1) {
if (num != first) {
printf("No\n");
fclose(IN);
return 0;
}
}
printf("Yes\n");
fclose(IN);
return 0
}
Вопрос. Зачем закрывать файлы?
Ответ.
1. В файлах, открытых на запись, не сохранятся изменения.
2. Все открытые файлы заносятся в таблицу открытых файлов
в операционной системе, общая для всех процессов
(таблица дескрипторов).
Размер таблицы ограничен, поэтому
ненужные файлы надо закрывать, чтобы таблица не
переполнилась.
Пример 1. Найти максимальный размер таблицы дескрипторов
(в файлах)
#include <stdio.h>
int main(void) {
FILE *IN;
int i = 0;
while (1) { /* Inifinite loop */
IN = fopen("tmp.dat", "r");
if (IN == NULL)
break;
++i;
}
printf("Files opened: %d\n", i);
return 0;
}
Выполнение этой программы:
Результат 3197 открытых файлов.
Задача 2. Найти значение многочлена, коэффициенты
которого находятся в файле "tmp.dat" в порядке возрастания
степеней, в точке x, задаваемой с клавиатуры.
Пример 2. В файле - числа:
1
0
-1
Значение этих чисел:
1 - это коэффициент при нулевой степени многочлена
0 - при первой
-1 - при второй степени
Получается, что файле записан многочлен:
y = -x*x + 0 * x +1
#include <stdio.h>
int main(void) {
double res = 0;
double a;
double x;
double xn = 1; /* This is x in degree of current n */
FILE *IN;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
printf("Input x\n");
scanf("%lf", &x);
while (fscanf(IN, "%lf", &a) == 1) {
res += a * xn;
xn *= x;
}
fclose(IN);
printf("Res: %lf\n", res);
return 0;
}
Сомерсет Моэм: "Главное в программе - чтобы она была выполнена"
Выполнения программы-решения задачи 2:
Форматы (ответ на вопрос из зала):
%lf – формат чтения/записи вещественного числа двойной точности (Long Float)
%d - формат чтения/записи десятичного целого числа (Decimal)
man printf – можно посмотреть все форматы (команда man – команда Линукса, которая выдает короткую документацию по функциям). Выход — командой «q”.
info printf – более полная документация. Выход — командой «:q”.
Вычисление производной для задачи 2:
#include <stdio.h>
int main(void) {
double val = 0, proizv = 0;
double a;
double x;
double xn = 1; /* This is x in degree of current n */
int n = 0;
FILE *IN;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
printf("Input x\n");
scanf("%lf", &x);
if (fscanf(IN, "%lf", &a) != 1) {
printf(“File empty\n”);
fclose(IN);
return -1;
}
val +=a;
++n;
while (fscanf(IN, "%lf", &a) == 1) {
proizv += n * a * xn; /* xn == x^(n-1) */
xn *= x;
val += a * xn; /* xn == x^n because already multiplied by x in the line above */
++n;
}
fclose(IN);
printf("Val: %lf, proizv: %lf\n", val, proizv);
return 0;
}
Результат выполнения этой программы:
Задача 3. Найти значение многочлена, коэффициенты
которого находятся в файле "tmp.dat" в порядке убывания
степеней, в точке x, задаваемой с клавиатуры
(за одно прочтение файла, нельзя пользоваться дополнительной
памятью)
Пример 2. В файле - числа:
1
0
-1
1 - это коэффициент при второй степени многочлена
0 - при первой
-1 - при нулевой степени
Получается многочлен:
y = 1*x*x + 0 * x - 1
y = an * xn + a(n-1) * x(n-1) + ... + a1 * x1 + a0 * x0
y = ((...(((an)*x + a(n-1))*x + a(n-2))*x + ...)*x+a1)*x+a0
Решение задачи 3:
#include <stdio.h>
int main(void) {
double res = 0;
double a;
double x;
FILE *IN;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
printf("Input x\n");
scanf("%lf", &x);
while (fscanf(IN, "%lf", &a) == 1) {
res = res*x + a;
}
fclose(IN);
printf("Res: %lf\n", res);
return 0;
}
Выполнение этой программы:
Упражнение: найти значение многочлена и его производной, если многочлен задан, как в задаче 2 (коэффициентами по убыванию степеней)
Задача 4. Считать целое число с клавиатуры и найти
число с теми же цифрами, что и исходного, но
идущими в обратном порядке, и вывести его
Пример 3. 1234 -> 4321
(((4)*10 + 3)*10 + 2)*10 + 1 == 4321 (каждая цифра — коэффициент при 10n)
Подсказка: найти последнюю цифру целого числа можно при помощи операции «%» - остаток от деления. Например, 21%6 == 3
1234%10 → 4, 1234/10 ->123
123%10 → 3, 123/10 →12
12%10 → 2, 12/10 → 1
1%10 → 1, 1/10 → 0 - выход
Результат - 4321
#include <stdio.h>
int main(void) {
int n, last_digit, res = 0;
printf("Input integer number\n");
scanf("%d", &n);
while(n > 0) {
last_digit = n % 10;
res = res * 10 + last_digit;
n /= 10;
}
printf("Res: %d\n", res);
return 0;
}
Приведение типов:
Например, если все операнды в выражении целые,
то результат тоже будет целый (неявное приведение типов в языке C).
while:
last_digit res n
1234
1. 4 4 123
2. 3 43 12
3. 2 432 1
4. 1 4321 0
while(n) - n==0 => условие цикла не выполнено => выход
из цикла
Выполнение этой программы:
Пример 4. Как в языке C поделить целые числа, чтобы результат был вещественный?
Результат выполнения программы с явным преобразованием типов:
Задача 5. В последовательности чисел, записанных в файле
"tmp.dat", найти количество локальных максимумов
(за одно прочтение файла).
Определение. Локальный максимум в последовательности
чисел - это число, которое не меньше своих соседей.
Пример:
5
0
5
-1
2
5
5
Вопрос: Сколько локальных максимумов? Ответ: 4
#include <stdio.h>
int main(void) {
int res = 0;
int a, b, c;
FILE *IN;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
if (fscanf(IN, "%d", &a) != 1) {
printf("File empty\n");
fclose(IN);
return -1;
}
if (fscanf(IN, "%d", &b) == 1) {
if (a >= b)
++ res;
while (fscanf(IN, "%d", &c) == 1) {
if ((b >= a) && (b >= c))
++res;
a = b;
b = c;
}
if (b >= a)
++res;
} else {
res = 1;
}
fclose(IN);
printf("Res: %d\n", res);
return 0;
}
tmp.dat:
5
0
5
-1
2
5
5
Протокол выполнения программы по шагам:
|
a |
b |
c |
res |
|
5 |
|
|
|
|
|
0 |
|
1 |
|
|
|
5 |
1 |
|
0 |
5 |
-1 |
2 |
|
5 |
-1 |
2 |
2 |
|
-1 |
2 |
5 |
2 |
|
2 |
5 |
5 |
3 |
После конца цикла |
5 |
5 |
|
4 |
Результат выполнения программы 5: