Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование на языке Си. Учебное пособие для СПО
.pdf
Есть также аналоги функций printf и scanf для работы с файлами.
fprintf(f,”формат”, значение)
fscanf(f,”формат”, адрес)
Пример вывода таблицы Пифагора в файл.
#include <stdio.h>
main(){
FILE*f;
int i, j;
f=fopen("a.txt", "w");
for (i=1; i<10; i++) {
for (j=1; j<10; j++) fprintf(f,"%5d",i*j);
fputs("\n",f);
}
fclose(f);
}
Можно использовать
fscanf(stdin, ...)
fprintf(stdout, ...)
Вместо файла используются стандартные потоки ввода-вывода.
переход в начало файла
rewind(f);
Пример: удалить лишние пробелы в файле.
#include <stdio.h>
int main(){
FILE *f1, *f2;
int i; char st[80];
f1=fopen("a.txt","r");
f2=fopen("b.txt","w");
while(fgets(st,80,f1)) {
for(i=0; i<strlen(st); i++) {
if(st[i]!=' ' || st[i+1]!=' ') fputc(st[i],f2);
} }
fclose(f2);
}
Пример создания массива строк из слов, содержащихся в файле. Разбиение
строки на слова.
#include <stdio.h>
#include <string.h>
81

int main(){
FILE *f1;
int i,j=0,n=0; char st[80], m[200][40];
f1=fopen("a.txt","r");
while(fgets(st,80,f1)) {
for(i=0; i<strlen(st); i++) {
if(st[i]!=' '&&st[i]!='\n') m[n][j++]=st[i];
if((st[i+1]==' ' || st[i+1]=='\n') && st[i]!=' ') {m[n][j]=0; n++; j=0;}
}
}
fclose(f1);
for(i=0;i<n;i++) puts(m[i]);
}
Функция очистки буфера ввода-вывода
int fflush(FILE *)
Если f – файл, открытый для записи, то вызов fflush() приводит к физической
записи содержимого буфера в файл. Если же f указывает на файл, открытый для
чтения, то очищается входной буфер. В обоих случаях файл остается
открытым.
Возврат 0 означает успех, а возврат ненулевой величины указывает на наличие
ошибки по записи. Закрытие файла также приводит к очистке буферов.
Функции для работы с файлами на диске
int remove(“name”)
удаление заданного файла на внешнем носителе
int rename(“oldname”, “newname”)
переименование заданного файла на внешнем носителе
возвращается 0 если успешно.
если файлы открыты – необходимо закрыть.
Пример
fclose(f1);
fclose(f2);
if (remove("a.txt") == 0)
printf("Removed \n");
else
printf("error remove");
if (rename("a.tmp","a.txt") == 0)
printf("Rename \n");
else
printf("error rename");
Работа с каталогами <dir.h>
82

int mkdir(const char *path);
создание каталога
int rmdir(const char *path);
удаление каталога
int chdir(const char *path);
смена текущего каталога
0 – если успешно
удаляется только пустой каталог.
Пример
if (!mkdir("111")) printf("Directory created\n");
else printf("Unable to create directory\n");
getch();
system("dir/p"); //вывод содержимого каталога
if (!rmdir("111")) printf("Directory removed\n");
else printf("Unable remove directory\n");
getch();
system("dir/p");
getch();
chdir("d:\\");
system("dir/p");
Двоичные файлы
Чтение и запись
int fwrite(void *p, int size, int n, FILE *f);
int fread(void *p, int size, int n, FILE *f);
возвращают число реально считанных или записанных элементов.
р – область памяти для чтения-записи, size – размер элемента, n – количество
элементов, f – файловая переменная.
Пример программы записи массива в файл, и вывода его из файла на экран.
#include <stdio.h>
int main(){
FILE *f;
int m[80]={65, 120, 70, 40, 10, 45, 155};
f=fopen("a.dat","wb");
fwrite(m, sizeof(int), 7, f);
fclose(f);
int p[80], n, i;
f=fopen("a.dat","rb");
83

i=0;
for( ;fread(p+i, sizeof(int), 1, f); i++)
printf("%4d", p[i]);
}
программа копирования файлов, использующая параметры
//debug - paramerers
#include <iostream.h>
#include <conio.h>
int main(int argc, char *argv[]){
FILE *f1, *f2;
char p[512], st1[80], st2[80];
int n, i;
if(argc <=1) {cout<<"name1 "; cin>>st1;}
else strcpy(st1,argv[1]);
if(argc <=2) {cout<<"name2 "; cin>>st2;}
else strcpy(st2,argv[2]);
cout<<st1<<"->"<<st2<<endl;
if((f1=fopen(st1,"rb"))==NULL) { cout<<"error "<<st1; getch(); return 1; }
if((f2=fopen(st2,"wb"))==NULL) { cout<<"error "<<st2; getch(); return 2; }
i=0;
do {
n=fread(p, 1, 512, f1);
fwrite(p, 1, n, f2);
i+=n;
} while(n==512);
fclose(f2);
cout<<"copy bait "<<i<<endl;
getch();
}
перемещение по файлу
int fseek(FILE *f, long n, int w);
0- если успешно
n – на сколько байт, w – откуда
0 – on начала, 1 – от тек позиции, 2 – от конца.
n – может быть отрицательным.
fseek(f,0,0) – переход в начало файла
fseek(f,0,2); - переход в конец файла
fseek(f,-1,1); - переход к предыдущему элементу в файле
long ftell(FILE *f)
возвращает текущее положение указателя в файле.
84

Пример функции определения длины файла
long filesize(FILE *f)
{
long curpos, length;
curpos = ftell(f);
fseek(f, 0, 2);
length = ftell(f);
fseek(f, curpos, 0);
return length;
}
Файл из структур – база данных
Пример записной книжки.
struct zap {
char fam[15];
char name[10];
char tel[13];
}b;
zap a[N]={{"petrova","ira","2665522"},{"ivanov","ivan","9139204512"},
{"sidorov","andrd","123456"}};
f1=fopen("a.dat","wb");
fwrite(a, sizeof(zap), 3, f1);
fclose(f1);
f2=fopen("a.dat","rb+");
while(fread(&b, sizeof(zap), 1, f2)) {
cout<<b.fam<<endl;
}
Пример поиска и изменения записей в БД.
fseek(f1,0,0);
while(fread(&b, sizeof(zap), 1, f1)) {
if (strcmp(b.fam,"petrova")==0) {
fseek(f1,-sizeof(zap),1);
strcpy(b.fam,"sergeeva");
fwrite(&b, sizeof(zap), 1, f1);
fflush(f1);
}
cout<<b.fam<<endl;
};
fclose(f1);
85

Удаление элементов из файла – два варианта:
1. Пометка записей как удаленных. Быстро, но место на диске не
освобождается.
2. Перезапись в другой файл. Медленно, но файл в этом случае
уменьшается.
На практике комбинируют оба метода.
Пример 1 варианта
fseek(f1,0,0);
while(fread(&b, sizeof(zap), 1, f1)) {
if (strcmp(b.fam,"sergeeva")==0) {
fseek(f1,-sizeof(zap),1);
b.fam[0]=0;
fwrite(&b, sizeof(zap), 1, f1);
fflush(f1);
}
}
fseek(f1,0,0);
while(fread(&b, sizeof(zap), 1, f1))
if(b.fam[0]!=0) printf("%s\n",b.fam);
Пример 2 варианта
fseek(f1,0,0);
f2=fopen("b.dat","wb+");
while(fread(&b, sizeof(zap), 1, f1)) {
if (strcmp(b.fam,"sidorov")!=0)
fwrite(&b, sizeof(zap), 1, f2);
}
fclose(f1); fclose(f2);
remove("a.dat");
rename("b.dat","a.dat");
f1=fopen("a.dat","rb+");
while(fread(&b, sizeof(zap), 1, f1))
if(b.fam[0]!=0) printf("%s\n",b.fam);
Сортировка элементов в файле
Если файл достаточно большой, и его элементы затруднительно считать в
массив для последующей сортировки, приходиться сортировать
непосредственно элементы файла на внешнем носителе. В этом случае, чтобы
минимизировать количество перемещений по файлу, можно использовать
метод слияния.
86

Пример:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
const int N=33;
main(){
FILE *f,*f1,*f2;
int i,i1,i2,n=1,k,j,n1,n2,flag;
unsigned char x,y;
srand(2);
f=fopen("f.tmp","wb+");
for(i=0;i<N;i++) {
x=rand()%256;
printf("%8d",x);
fwrite(&x,sizeof(x),1,f);
}
printf("\n");
for(n=1; n<N; n*=2) {
rewind(f);
f1=fopen("f1.tmp","wb+");
f2=fopen("f2.tmp","wb+");
for(i=j=0;i<N;i++){
fread(&x,sizeof(x),1,f);
if(j++ < n)fwrite(&x,sizeof(x),1,f1);
else fwrite(&x,sizeof(x),1,f2);
if(j==n*2) j=0;
}
rewind(f); rewind(f1); rewind(f2);
n1=fread(&x,sizeof(x),1,f1);
n2=fread(&y,sizeof(x),1,f2);
while(n1||n2) {
for(i1=i2=i=0;i<n*2&&(n1||n2);i++) {
if(x<y && i1<n && n1 || i2>=n || !n2)
fwrite(&x,sizeof(x),1,f),n1=fread(&x,sizeof(x),1,f1),i1++;
else fwrite(&y,sizeof(x),1,f),n2=fread(&y,sizeof(x),1,f2),i2++;
}
}
}
printf("\n");
rewind(f);
while(fread(&x,sizeof(x),1,f)) printf("%8d",x);
}
87

Контрольные вопросы
65 40 120
10 45 70 155
Какие типы файлов вы знаете?
Чем отличается файл от массива?
Особенности организации текстовых и двоичных файлов.
Что понимается под чтением, и что под записью в файл?
12. Деревья
Дерево – это совокупность узлов и соединяющих их ветвей, причем в
каждый узел (за исключением одного – корня) ведет ровно одна ветвь. Корень –
это начальный узел дерева, в который не ведет ни одной ветви.
Предком для узла x называется узел дерева, из которого существует путь
в узел x (потомок – наоборот).
Родителем для узла x называется узел дерева, из которого существует
непосредственная ветка в узел x (сын – наоборот).
Листом дерева называется узел, не имеющий потомков.
Рассмотрим двоичное дерево. Двоичным деревом называется дерево,
каждый узел которого имеет не более двух сыновей. Полным двоичным
деревом называется дерево, у которого каждая внутренняя вершина имеет
непустые левое и правое поддеревья.
Опишем следующую структуру для создания дерева:
struct tree {
int key;
tree *l, *r;
};
где tree *l, *r ссыдки на правого и левого сына данного узла.
Деревья очень удобны для поиска в них информации. Однако для
быстрого поиска требуется предварительная подготовка – дерево надо
построить специальным образом. Дерево строится таким образом, что значения
всех вершин левого поддерева вершины x меньше x, а значения всех вершин
правого поддерева x больше или равно вершины x.
Построим дерево для последовательности 65, 120, 70, 40, 10, 45, 155
88

Алгоритм построения дерева
Сравниваем очередной элемент массива с ключом корня. Если новый
элемент меньше, включаем его в левое поддерево, если больше или равен, то в
правое. Если текущее дерево пустое, создаем новую вершину (корень) и
включаем в дерево.
Удобно строить деревья с помощью рекурсии. В параметрах функции
add(tree * &t, int data) ставить & обязательно, через него возвращается адрес
ссылки.
Функция для добавления в дерево новых узлов.
void add (tree * &t, int data) {
if ( !t ) {
t = new tree;
t->key = data;
t->l = t->r = NULL;
return;
}
if ( data < t->key )
add( t->l, data );
else add ( t->r, data );
}
Одной из необходимых операций при работе с деревьями является обход
дерева, во время которого надо посетить каждый узел по одному разу и
(возможно) вывести информацию, содержащуюся в узлах. Пример – левое
поддерево, корень, правое поддерево (ЛКП обход) – узлы будут пройдены в
порядке возрастания. ПКЛ обход – узлы будут пройдены в порядке убывания.
ЛКП обход
void print_t(tree *t){
if ( !t ) return;
print_t(t->l);
printf("%d ", t->key);
print_t(t->r);
}
ПКЛ обход
void print_t(tree *t){
if ( !t ) return;
print_t(t->r);
printf("%d ", t->key);
print_t(t->l);
}
89

КЛП обход
void print_t(tree *t){
if ( !t ) return;
printf("%d ", t->key);
print_t(t->l);
print_t(t->r);
}
ЛПК обход
void print_t(tree *t){
if ( !t ) return;
print_t(t->l);
print_t(t->r);
printf("%d ", t->key);
}
Алгоритм поиск по дереву. Сначала проверяем ключ корня, если он равен
искомому, то поиск заканчиваем. Если он меньше искомого, ищем в левом
поддереве от узла, если больше – то в правом. Приведенная функция
возвращает адрес нужной вершины, если поиск успешный, и NULL, если
требуемый элемент не найден.
tree * search (tree * t, int x) {
if ( ! t ) return NULL;
if ( x == t->key ) return t;
if ( x < t->key )
return search ( t->l, x );
return search ( t->r, x );
}
Пример программы с использованием дерева.
int main(){
tree *p=NULL, *t;
int m[80]={65, 120, 70, 40, 10, 45, 155};
int i;
for(i=0; i<7; i++) add(p,m[i]);
print_t(p);
cout<<endl;
t=search(p,45);
if(t) cout<<"found "<<t->key;
else cout<< "no found";
}
90
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
