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

Программирование на языке Си. Учебное пособие для СПО

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
Есть также аналоги функций 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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]