Лекция 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: