Лекция 2 (13.09.2021)
Файл — последовательность данных, имеющая имя.
Работа с файлом: (ограниченный ресурс — таблица дескрипторов файлов) (дескриптор — англ. Describe – описывать, в дескрипторе находится информация о том, в каком состоянии находится в файл)
1. Начать работу с файлом <вх: имя файла, тип работы с файлом — на чтение или на запись, вых: успех/неуспех, указатель на дескриптор файла> (открыть файл)
2. Читать из файла <вх: указатель на дескриптор файла>. Указатель на данные продвигается при этом вперед. В начале работы указатель находится в начале файлы.
3. Писать в файл (в конец файла) <вх: указатель на дескриптор файла>. Указатель сдвигается на положение после записанных данных.
4. Закончить работу с файлом (закрыть файл)
1. fopen(“tmp.dat”, “r”) - начать работу с файлом “tmp.dat”, читать (Read)
fopen(“tmp.res”, “w”) - начать работу с файлом «tmp.res”, писать (Write)
Проверка результат открытия файла:
а) Почему файл может не открыться? Его нет, ошибка на диске, кто-то его уже захватил на запись, …
б) Как проверить, успешно ли файл открылся?
#include <stdio.h>
int main(void) {
FILE *IN; /* FILE - не базовый тип, введен в библиотеке ввода/вывода */
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
...
}
IN – это имя переменной, которой присваивается указатель на дескриптор файла
Операторы в C: +, -, *, /, % (остаток от деления), == (проверка равенства — выражение A==B истинно, если A равно B), != (проверка неравенства), > (больше), < (меньше), >= (больше или равно), <= (меньше или равно), ! (отрицание: !A истинно <=> А ложно), && (логическое И: A&&B истинно <=> A истинно и B истинно), || (логическое ИЛИ: A||B истинно <=> A истинно или B истинно)
2. Чтение данных:
int x, y;
fscanf(IN, “%d%d”, &x, &y);
Проверка результата:
1)
Почему надо проверять? Данные могли не прочитаться по
следующим причинам:
a) нет данных;
б) недостаточно данных
в) данные в файле есть, но они не в том формате (например, хотели прочитать числа, а в файле лежат не числа, а, например, слова или какие-то символы)
Как проверить, что данные успешно прочитались?
!!!ФУНКЦИЯ FSCANF ВОЗВРАЩАЕТ КОЛИЧЕСТВО ПРОЧИТАННЫХ ОБЪЕКТОВ!!!
int main(void) {
int n, m, res;
...
res = fscanf(IN, "%d%d", &n, &m);
if (res != 2) {
printf("Not enough data in the file\n");
fclose(IN);
return -1;
}
…
return 0;
}
Другие способы проверить, прочитались ли данные (функция feof(), сравнение res c -1) – работают не всегда.
3. Запись данных:
FILE *OUT;
OUT = fopen(“tmp.res”, “w”);
if (OUT == NULL) {
printf(“File not opened\n”);
return -1;
}
fprintf(OUT, “Result: %d\n”, res);
4. Закрыть файл:
fclose(IN);
fclose(OUT); /* Записываемая информация не сохранится, если файл не закрыть */
Задача 1. Найти сумму целых чисел в файле "tmp.dat" и вывести на экран
#include <stdio.h>
int main(void) {
FILE *IN;
int sum = 0, n;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
while (fscanf(IN, "%d", &n) == 1) {
sum += n;
}
fclose(IN);
printf("Summa: %d\n", sum);
return 0;
}
Программа должна правильно работать для правильных входных данных и не ломаться (не «падать») для неправильных входных данных.
Задача 2. Переписать из файла tmp.dat в файл tmp.res все положительные числа (в tmp.dat – целые числа)
#include <stdio.h>
int main(void) {
FILE *IN, *OUT;
int sum = 0, n;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
OUT = fopen("tmp.res", "w");
if (OUT == NULL) {
fclose(IN);
printf("File not opened\n");
return -1;
}
while (fscanf(IN, "%d", &n) == 1) {
if (n > 0) {
fprintf(OUT, "%d\n", n);
}
}
fclose(IN);
fclose(OUT);
return 0;
}
В 1 семестре задачи:
1) Задачи на последовательности. Дан файл с данными в неизвестном количестве. Получить выходной файл или какую-то характеристику данных
2) Задачи на массивы (вектор, таблица, …) - array
Как мы работаем с последовательностями?
Задачи: обработать файл за одно прочтение файла. Например, найти сумму чисел.
Пусть xi принадлежат множеству X
Последовательности x1, x2, ..., xn - принадлежат множеству Z (множество последовательностей)
f: Z -> Y
Y – множество неких значений для последовательности
Определение. Функция f называется индуктивной, если при добавлении элемента к последовательности можно вычислить значение f на новой последовательности, зная значение f на старой последовательности и зная добавленный элемент.
То есть существует функция g(Y, X) такая, что
f(x1, x2, ..., xn) = g(f(x1, x2, ..., xn-1), xn)
Иначе: Например: пусть f(z) – сумма чисел в последовательности z = (x1x2...xn)
f(z xn+1) - ?
Для суммы f(z xn+1) = f(z) + xn+1
Вопрос 1. В задаче 1 (сумма чисел в файле) функция “сумма” индуктивна?
Ответ. Да, так как существует функция g: g(y, x) = y + x, то есть
при добавлении в последовательность нового числа сумма новой последовательности вычисляется значение f() для новой последовательности
Примеры индуктивных функций: сумма чисел в последовательности
Примеры неиндуктивных функций:
Задача 3. Найти максимальный элемент последовательности
Вопрос 2. Функция "количество максимальных элементов последовательности" индуктивна?
Примеры последовательностей:
1) 1 2 3 4 5 4 3 2 1 - количество максимальных элементов == 1
2) 4 4 4 - количество максимальных элементов == 3
Добавим число 4 к обеим последовательностям
1) y==1, x==4
2) y==3, x==4
Чему равна функция f на новых последовательностях?
1) 1
2) 4 (так как в новой последовательности 4 4 4 4 — 4 максимальных элемента)
Этот ответ невозможно получить только из значений f на старой последовательности и значения добавленного элемента
Ответ на вопрос 2. Функция не индуктивна
Определение. Индуктивным расширением функции f называется функция h(Z)
h: Z -> (Y, W)
такая, что h индуктивна и f(x) = p(h(x))
где p(y, w) = y
Пример h(x) – (количество максимальных и значение максимального)
1) y==1, h = (1, 5), x==4 => f == 1
2) y==3, h = (3, 4), x==4 => f == 4
Задача 4. Найти количество максимальных элементов последовательности
Решение.
Функция «количество максимальных элементов последовательности» не индуктивная.
Индуктивное расширение — функция « количество максимальных элементов последовательности и значение максимального элемента»
/* задача 4 */
#include <stdio.h>
int main(void) {
FILE *IN;
int maks, nmaks = 0, n;
IN = fopen("tmp.dat", "r");
if (IN == NULL) {
printf("File not opened\n");
return -1;
}
if (fscanf(IN, "%d", &maks) != 1) {
printf("Empty\n");
fclose(IN);
return -1;
}
nmaks = 1;
while (fscanf(IN, "%d", &n) == 1) {
if (n > maks) {
maks = n;
nmaks = 1;
} else if (n == maks) {
++nmaks;
}
}
fclose(IN);
printf("Number of max: %d\n", nmaks);
return 0;
}
Пример:
В последовательности — 1 число, например, 17.
Сколько максимальных чисел в последовательности? 1
17, 18 → nmaks = 1, maks = 18
Работа программы 4 по шагам:
Прочитанное число |
maks |
nmaks |
17 |
17 |
1 |
18 |
18 |
1 |
25 |
25 |
1 |
25 |
25 |
2 |
25 |
25 |
3 |
26 |
26 |
1 |
26 |
26 |
2 |
26 |
26 |
3 |
15 |
26 |
3 |
Результат для последовательности (17, 18, 25, 25, 25, 26, 26, 26, 15): 3
Литература:
А.Г.Кушниренко, Г.В.Лебедев «Программирование для математиков»