Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
shpory_si.docx
Скачиваний:
33
Добавлен:
25.09.2019
Размер:
205.61 Кб
Скачать
  1. Основы файловой системы. Стандартные потоки. Указатель файла. Открытие файла. Закрытие файла.

Потоки

Потоки представляют собой удобный переносимый способ чтении и записи данных. Они обеспечивают гибкие и эффективные средства для ввода/вывода.

Поток - это байтовая последовательность, передаваемая в процессе ввода, которая управляется через указатель на поток.

Потоковый ввод/вывод - буферизированный: это означает, что блок данных фиксированного размера читается/пишется в файл не посредственно, а через временную область хранения (буфер).

Это повышает эффективность ввода/вывода, но будьте осторожны: данные, записанные в буфер, не появятся в файле или на устройстве, пока буфер не будет очищен. Всякое неуспешное завершение программы может вызвать проблемы. Потоковый ввод/вывод эффективен для символов и строк.

Основы файловой системы

Основным понятием, связанным с информацией на внешних устройствах ЭВМ, является понятие файла. Всякая операция ввода/вывода трактуется как операция обмена с файлами: Ввод- это чтение из файла в оперативную память; вывод - это запись из оперативной памяти в файл. Сначала нужно открыть поток перед выполнением каких-либо операций ввода/вывода, затем выполнить операции доступа (чтения/записи) и потом закрыть.

В языке Си файл - это байтовая последовательность, заканчивающаяся EOF.

В языке Си отсутствует понятие типа файла.

Указатель файла

Работа с файлами начинается с объявления указателя на поток:

FILE *имя_указателя;

FILE *fp;

FILE внутренняя C-структура данных языка Си,которая используется для работы с потоками и определена в stdio.h. Стуктура FILE содержит следующую информацию: указатель на буфер, указатель текущей позиции в потоке.

Открытие файла

Открыти файла возможно при помощи функции fopen(), синтаксис которой следующий:

FILE *fopen(char *name, char *mode)

fopen возвращает указатель на структуру FILE. Строка name содержит имя файла. Строка mode определяет способ доступа. Если файл не может быть открыт по какой-либо причине, функция возвращает NULL.

Способы доступа включают:

"r" - чтение,

"w" - запись,

"a" - добавление в конец.

Также способ доступа может включать:

"t" - текстовый,

"b" - бинарный.

Для открытия файла myfile.dat на чтение необходимо:

FILE *stream, *fopen();

/* описание потока и прототипа fopen */

stream = fopen("myfile.dat","r");

Необходимо проверять, что файл открылся:

if ((stream = fopen("myfile.dat", "r")) == NULL)

{ printf("Нельзя открыть %s\n", "myfile.dat");

exit(1);

}

......

Закрытие файла

Для того, чтобы закрыть файл, используется функция fclose. Ее синтаксис:

fclose(FILE *stream)

Пример. Ввести матрицу из файла inputfile.dat.Файл входных данных имеет следующую структуру:

n - количество строк

m - количество столбцов

a a ... a

...

a a ... a,

где

n - количество строк

m - количество стобцов

a - элементы матрицы.

И вывести ее в файл outputfile.dat.

#include <stdio.h> void main(){ int A[100][100]; // массив 100х100 int i,j; // индексы для перемещения по массиву int n; // кол-во строк int m; // кол-во столбцов FILE *fp;

// открытие файла на чтение if ((fp = fopen("inputfile.dat", "r")) == NULL) { printf("Нельзя открыть %s\n", "inputfile.dat"); return; } // ввод размеров матрицы fscanf(fp,"%d",&n); fscanf(fp,"%d",&m); // ввод значений матрицы for (i=0;i<n;i++) for (j=0;j<n;j++){ fscanf(fp,"%d",&A[i][j]); } fclose(fp); // открытие файла на запись if ((fp = fopen("outputfile.dat", "w")) == NULL) { printf("Нельзя открыть %s\n", "outputfile.dat"); return; } // вывод значение матрицы for (i=0;i<n;i++){ for (j=0;j<n;j++) fprintf(fp,"%d ",A[i][j]); fprintf(fp,"\n"); } fclose(fp);

}

  1. Форматированный ввод-вывод в файл.

С помощью функции форматного вывода можно формировать на диске текстовый файл с результатами вычислений, представленными в символьном виде. В дальнейшем этот файл может быть просмотрен на экране, распечатан на принтере, отредактирован с помощью текстового редактора. Общий вид функции форматного вывода:

int fprintf (указатель_на_поток, форматная_строка, список_переменных);

Использовавшаяся нами ранее функция printf () для организации вывода на экран является частным вариантом функции fprintf (). Функция printf () работает лишь со стандартным потоком stdin, который всегда связывается системой с дисплеем. Не будет ошибкой, если в программе вместо printf () написать fprintf (stdin, …).

Правила использования спецификаторов форматов при записи в файлы на диске точно такие же, как и при выводе на экран.

Пример 5. Составим программу, по которой будет рассчитана и записана в файл таблица квадратных корней для целых чисел от 1 до 10. Для контроля эта же таблица выводится на экран.

//Таблица квадратных корней

#include <stdio.h>

#include <iostream.h>

#include <math.h>

void main()

{ FILE *fp;

int x;

fp = fopen(“test.dat”, “w”);

//Вывод на экран и в файл шапки таблицы

printf(“\t Таблица квадратных корней \n”);

fprintf(fp, “\t Таблица квадратных корней \n ”);

printf(“\t x\t\tsqrt(x) \n”);

fprintf(fp, “\t x\t\tsqrt(x) \n ”);

\\Вычисление и вывод таблицы квадратных корней

\\на экран и в файл

for(x = 1; x<=10; x++)

{ printf(“\t%f\t%f\n”, float(x), sqrt(float(x)));

fprintf(fp, “\t%f\t%f\n”, float(x), sqrt(float(x)));

}

fclose(fp);

}

Форматный ввод из текстового файла осуществляется с помощью функции fscanf (), общий формат которой выглядит следующим образом:

int fscanf(указатель_на_поток, форматная_строка, список_адресов_переменных);

Данной функцией удобно пользоваться в тех случаях, когда исходные данные заранее подготавливаются в текстовом файле.

  1. Запись и чтение символов. Ввод/вывод строк. Стирание файлов.

Запись и чтение символа

Функции записи и чтения символа подобны fprintf и fscanf, только пишут и читают не в поток/из потока, а в строку/из строки:

int sprintf(char *string, char *format, args..)

int sscanf(char *string, char *format, args..)

Пример:

float full_tank = 47.0;

float miles = 300;

char miles_per_litre[80];

sprintf( miles_per_litre,"Miles per litre = %2.3f", miles/full_tank);

Ввод/вывод строк

Стандартная библиотека содержит функцию fgets. В результате обращения

fgets(line, maxline, fp)

следующая строка ввода (включая символ новой строки) считывается из файла fp в символьный массив line; самое большое maxline_1 символ будет прочитан. Результирующая строка заканчивается символом \0. Нормально функция fgets возвращает line; в конце файла она возвращает null.

Предназначенная для вывода функция fputs записывает строку (которая не обязана содержать символ новой строки) в файл:

fputs(line, fp)

Очистка буфера потока

Функция fflush очищает буфер потока:

fflush(FILE *stream)

  1. Понятия очереди, стеков, связанных списков и деревьев.

Понятия очереди, стеков, связанных списков и деревьев

В зависимости от метода доступа к элементам линейного списка различают разновидности линейных списков называемые стеком, очередью и двусторонней очередью.

Стек – это конечная последовательность некоторых однотипных элементов – скалярных переменных, массивов, структур или объединений, среди которых могут быть и одинаковые. Стек обозначается в виде: S= и представляет динамическую структуру данных; ее количество элементов заранее не указывается и в процессе работы, как правило, изменяется. Если в стеке элементов нет, то он называется пустым и обозначается S=< >.

Допустимыми операциями над стеком являются:

- проверка стека на пустоту S=< >,

- добавление нового элемента Sn+1 в конец стека - преобразование < S1,...,Sn> в < S1,...,Sn+1>;

- изъятие последнего элемента из стека - преобразование < S1,...,Sn-1,Sn> в < S1,...,Sn-1>;

- доступ к его последнему элементу Sn, если стек не пуст.

Таким образом, операции добавления и удаления элемента, а также доступа к элементу выполняются только в конце списка. Стек можно представить как стопку книг на столе, где добавление или взятие новой книги возможно только сверху.

Очередь – это линейный список, где элементы удаляются из начала списка, а добавляются в конце списка (как обыкновенная очередь в магазине).

Двусторонняя очередь – это линейный список, у которого операции добавления и удаления элементов и доступа к элементам возможны как вначале так и в конце списка. Такую очередь можно представить как последовательность книг стоящих на полке, так что доступ к ним возможен с обоих концов.

Реализация стеков и очередей в программе может быть выполнена в виде последовательного или связанного хранения. Рассмотрим примеры организации стека этими способами.

Одной из форм представления выражений является польская инверсная запись, задающая выражение так, что операции в нем записываются в порядке выполнения, а операнды находятся непосредственно перед операцией.

Например, выражение

(6+8)*5-6/2

в польской инверсной записи имеет вид

6 8 + 5 * 6 2 / -

Особенность такой записи состоит в том, что значение выражения можно вычислить за один просмотр записи слева направо, используя стек, который до этого должен быть пуст. Каждое новое число заносится в стек, а операции выполняются над верхними элементами стека, заменяя эти элементы результатом операции. Для приведенного выражения динамика изменения стека будет иметь вид

S = < >; <6>; <6,8>; <14>; <14,5>; <70>;

<70,6>; <70,6,2>; <70,3>; <67>.

Ниже приведена функция eval, которая вычисляет значение выражения, заданного в массиве m в форме польской инверсной записи, причем m[i]>0 означает неотрицательное число, а значения m[i]<0 - операции. В качестве кодировки операций сложения, вычитания, умножения и деления выбраны отрицательные числа -1, -2, -3, -4. Для организации последовательного хранения стека используется внутренний массив stack. Параметрами функции являются входной массив a и его длина l.

float eval (float *m, int l)

{ int p,n,i;

float stack[50],c;

for(i=0; i < l ;i++)

if ((n=m[i])<0)

{ c=st[p--];

switch(n)

{ case -1: stack[p]+=c; break;

case -2: stack[p]-=c; break;

case -3: stack[p]*=c; break;

case -4: stack[p]/=c;

}

}

else stack[++p]=n;

return(stack[p]);

}

Рассмотрим другую задачу. Пусть требуется ввести некоторую последовательность символов, заканчивающуюся точкой, и напечатать ее в обратном порядке (т.е. если на входе будет "ABcEr-1.", то на выходе должно быть "1-rEcBA"). Представленная ниже программа сначала вводит все символы последовательности, записывая их в стек, а затем содержимое стека печатается в обратном порядке.

Это основная особенность стека - чем позже элемент занесен в стек, тем раньше он будет извлечен из стека. Реализация стека выполнена в связанном хранении при помощи указателей p и q на тип, именованный именем STACK.

#include

typedef struct st /* объявление типа STACK */

{ char ch;

struct st *ps; } STACK;

main()

{

STACK *p,*q;

char a;

p=NULL;

do // заполнение стека

{ a=getch();

q=malloc(sizeof(STR1));

q->ps=p; p=q;

q->ch=a;

} while(a!= ’. ’);

do // печать стека

{ p=q->ps;free(q);q=p;

printf("%c",p->ch);

} while(p->ps!=NULL);

}

Упорядоченные списки А и В длин М и N сливаются в один упорядоченный список С длины М+N, если каждый элемент из А и В входит в С точно один раз. Так, слияние списков А=<6,17,23,39,47> и В=<19,25,38,60> из 5 и 4 элементов дает в качестве результата список С=<6,17,19,23,25,38,39,47, 60> из 9 элементов.

Для слияния списков А и В список С сначала полагается пустым, а затем к нему последовательно приписывается первый узел из А или В, оказавшийся меньшим и отсутствующий в С.

Составим функцию для слияния двух упорядоченных, расположенных рядом частей массива s. Параметром этой функции будет исходный массив s с выделенными в нем двумя расположенными рядом упорядоченными подмассивами: первый с индекса low до индекса low+l, второй с индекса low+l+1 до индекса up, где переменные low, l, up указывают месторасположения подмассивов. Функция merge осуществляет слияние этих подмассивов, образуя на их месте упорядоченный массив с индексами от low до up.

/* слияние списков */

double *merge(double *s, int low, int up, int l)

{

double *b,*c,v;

int i,j,k;

b=calloc(l,sizeof(double));

c=calloc(up+1-l,sizeof(double));

for(i=low;i< low+l;i++)

b[i-low]=s[i];

for(i=0;i< up-l;i++)

c[i]=s[i+l+low];

v=(b[l]=(c[up-l]=(s[low+l-1]>s[up-1]) ? (s[low+l-1]+1) : (s[up-1]+1)));

i=(j=0);

k=low;

while(b[i]< v||c[j]< v)

{ if(b[i]< c [j]) s[k]=b[i++];

else s[k]=c[j++];

k++;

}

return (s);

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]