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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



Синтаксис объявления имеет вид:

char ID [N];

где ID – идентификатор массива, N – длина массива, при этом в памяти для хранения строки выделяется N байт.

Например, для переменной char ST[10] в памяти выделяется 10 байт, что дает возможность сформировать строку из 9 символов. Для таких строк действуют все правила представления и обработки массивов.

Идентификатор массива – константа типа указатель, значение которой равно адресу первого элемента массива.

Инициализация возможна двумя способами:

· посимвольная инициализация char st[10]={'y','e','s','\0'};

при этом оставшиеся 6 позиций не будут заполнены;

· инициализация на основе строковой константы char st [10]="Yes";

при этом в выделенную для строки память будут помещены 3 символа и добавлен четвертый – символ '\0'.

Инициализация и объявление возможны без указания длины массива char st[]={'y','e','s','\0'};

в этом случае будет создан массив из четырех элементов.

Указатель на символьную строку

По форме записи данная конструкция ничем не отличается от указателя на символьную переменную: char *S1;

где char – тип указателя на символ, S1 – переменная-указатель.

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

Существует ряд способов инициализации указателя на строку:

· инициализация строковым литералом char *S1="Yes";

· присваивание значение другого указателя char *S1=S;

где S – идентификатор массива или указатель на другую строку символов.

Указателю можно присваивать значение другого указателя: S1=S;

где S1 – переменная типа указатель; S – строковая константа, идентификатор массива или указатель на другую строку символов.

Например, char *S1, S[10]="Yes"; S1=S;

При этом создаются переменная-указатель S1 и массив символов S, под который выделяется поле длиной 10 символов, 4 из которых будут заполнены. Затем в переменную-указатель записывается адрес символьного массива (рис. 11.1).

Рис. 11.1. Строковая константа и указатель

 

Ввод/вывод символьных строк

Ввод символьных строк с клавиатуры в языке C осуществляется с помощью функций scanf() и gets(), объявленных в заголовочном файле stdio.h. При работе с этими функциями следует помнить, что для строк предварительно должна быть выделена память. Конечный нуль добавляется после завершения ввода строки автоматически.

Существует несколько способов ввода строк:

· scanf ("%s",S1); где S1 – указатель типа char* на предварительно выделенную область. При использовании формата %s аргумент рассматривается как строка. Ввод строки реализуется до пробела или нажатия [Enter]. Несколько слов вводить в одну переменную с помощью scanf нельзя;

· scanf ("%Ns",S1); где N максимальноечисло символов, записываемых в строку S1. Заполнение строки заканчивается при вводе N непробельных символов или выполняется до первого пробельного символа.

· gets (S1);при помощи этой функции можно вводить строку, содержащую пробелы. Ввод прекращается при нажатии [Enter] или при заполнении буфера клавиатуры.

Вывод символьных строк на экран в C осуществляется с помощью функций printf() и puts():

· printf("%s",S1);где S1 указатель типа char*

· puts (S1);

Вывод строки продолжается до символа'/0'.

Пример 1. Что напечатает ЭВМ?

#include <stdio.h>

#define STR "What is your name?"

int main()

{

char *ch;

static char ch1[]="My name is George\n";

ch=STR;

printf("\n%s \t %s",ch,ch1);

/*\t – табуляция – сдвиг на заданное количество позиций*/

for (int i=0;i<6;i++)

{

printf("\n %c", *(ch+i));

printf(" %c", *(ch1+i));

}

return 0;

}

На экране будут выведены строки:

What is your name? My name is George

W M
h y
a  
t n
  a
i m

Пример 2. Задан указатель на символьную строку. Подсчитать, сколько раз в строке встретится буква 'а':

# include <stdio.h>

int main()

{

int k;

char *S2="Ivanov is an engineer";

for (k=0; (*S2)!= '\0'; S2++)

if ((*S2)=='a'||(*S2)=='A') k++;

printf("\n number of \'a\' is %d",k);

return 0;

}

После завершения работы цикла указатель S2 указывает на конец строки, и доступ к этой строке теряется.

Массивы символьных строк

Массив строк есть не что иное, как массив данных определенного типа. Строка сама уже является массивом символов, поэтому массив символьных строк является двумерным.

При определении массива строк используются два индекса:

· первый индекс определяет максимальное количество строк в массиве;

· второй – максимальную длину каждой строки.

Например,

static char massiv[3][8]= {"Ivanov",
  "Petrov",
  "Sidorov"};

Под переменную massiv выделяется область размером 3×8 байт памяти, по 8 байт для каждой строки. Таким образом, указатель на начало массива massiv и указатели на начало строкmassiv[i] представляют собой указатели-константы.

Можно объявить массив символьных строк с помощью указателей:

char *list[N]; где N – количество строк в массиве.

Переменная list представляет собой массив из N указателей, память при этом выделяется для хранения N значений указателей. Таким образом, имя массива list является константой-указателем. Элементы массива list[i] используются для хранения адресов строк и являются переменными величинами.

Инициализация символьных строк с помощью указателей:

char *list[3]={"Ivanov","Petrov","Sidorov"};

Доступ к строке:

list [0] – ссылка на "Ivanov";

Доступ к символу указанной строки:

*list[0] – определяет символ "I"в строке"Ivanov";

*(list[1]+2) – символ 't' в строке "Petrov".

Пример 3. Вывести на экран содержимое массивов строк massiv и list:

#include <stdio.h>

int main()

{

static char massiv[3][8]={"Ivanov","Petrov", "Sidorov"};

char* list[3]={"Ivanov","Petrov","Sidorov"};

printf("\n==================\n");

for(int i=0;i<3;i++)

printf("%s %s\n",massiv[i],list[i]);

list[0]=massiv[1];

list[1]="Rogov";

printf("\n==================\n");

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

printf("%s %s\n",massiv[i],list[i]);

return 0;

}

Результат работы программы:

==================

Ivanov Ivanov
Petrov Petrov
Sidorov Sidorov

==================

Ivanov Petrov
Petrov Rogov
Sidorov Sidorov

 

Язык C определяет строки как особый вид массивов, позволяя осуществлять их ввод/вывод как единого целого. Встроенные средства обработки строк в языке C отсутствуют, но строки настолько широко используются в программировании, что большинство компиляторов имеет специальные функции для работы со строками. Эти функции входят в состав заголовочного файла<string.h>.

Отметим ряд основных функций.

Определение длины строки:

strlen (S1) – длина строки S1, исключая нулевой символ.

Копирование строк:

strcpy (S1,S2), где S1 – указатель,S2 указатель или константа.

Строка S2 копируется посимвольно в строку S1. Необходимо иметь в виду, что размер строк компилятором не сравнивается, и это возлагается на программиста.

Слияние строк (конкатенация):

strcat (S1,S2).

К концу строки S1 подсоединяется строка S2. Нулевой символ в конце строки S1 отбрасывается. Компилятор не следит, хватит ли в S1 места для S1 плюс S2.

Сравнение строк:

strcmp (S1,S2).

Сравниваются коды символов, находящихся на одинаковых позициях в строках S1 и S2, начиная с нулевой. В зависимости от компилятора результат работы функции следующий:

· возвращается нуль, если строки одинаковы, и значение отличное от нуля, если строки не совпадают;

· отрицательное число, если строка S1 «меньше» строки S2 с точки зрения алфавита (ASCII-кодов), и положительное, если «больше».

Данная функция используется для упорядочения по какому-либо критерию.

Пример 4

Упорядочить по алфавиту фамилии в списке:

# include <stdio.h>

# include <string.h>

int main()

{

static char list[4][15]=

{"Ivanov","Petrov","Akimov","Fomin"};

int i,j;

char S1[15]; /*буфер*/

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

{

for (j=0;j<3-i;j++)

{

if (strcmp(list[j],list[j+1])>0)

{

strcpy (S1,list[j]);

strcpy (list[j],list[j+1]);

strcpy (list[j+1],S1);

}

}

}

for (i=0;i<4;puts(list[i]),i++);

return 0;

}

Результат работы программы:

Akimov

Fomin

Ivanov

Petrov

 

Строки в С++ представляются как массивы элементов типа char, заканчивающиеся нуль-терминатором \0 называются С строками или строками в стиле С.

\0 — символ нуль-терминатора.

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

  // пример объявления строки char string[10]; // где string – имя строковой переменной // 10 – размер массива, то есть в данной строке может поместиться 9 символов, последнее место отводится под нуль-терминатор.

Строка при объявлении может быть инициализирована начальным значением, например, так:

  char string[10] = "abcdefghf";

Если подсчитать кол-во символов в двойных кавычках после символа равно их окажется 9, а размер строки 10 символов, последнее место отводится под нуль–терминатор, причём компилятор сам добавит его в конец строки.

  // посимвольная инициализация строки: char string[10] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'f', '\0'}; // десятый символ это нуль-терминатор.

При объявлении строки не обязательно указывать её размер, но при этом обязательно нужно её инициализировать начальным значением. Тогда размер строки определится автоматически и в конец строки добавится нуль-терминатор.

  //инициализация строки без указания размера char string[] = "abcdefghf"; //всё то же самое только размер не указываем.

Строка может содержать символы, цифры и специальные знаки. В С++ строки заключаются в двойные кавычки. Имя строки является константным указателем на первый символ.

Вопрос 34. Файлы и потоки.

Во время работы программа может обмениваться данными с какими-либо внешними устройствами: клавиатурой, монитором, жестким диском и т. д. Для такого обмена данными используется понятие файл [7].

Файл – это информация, размещенная на каком-либо носителе (диске) или в буфере ввода/вывода устройства (клавиатура). Для обмена данными файл должен быть открыт, по завершении этого процесса – закрыт.

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

Стандартные потоки открываются при каждом запуске программы.

Для работы с файлами в программах на C используется заголовочный файл stdio.h, в котором объявлен специальный тип данных – структура FILE, предназначенная для хранения атрибутов (параметров) файлов (указатель текущей позиции файла, признак конца файла, флаги индикации ошибок, сведения о буферизации и др.).

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

Объявление потока – переменной-указателя на структуру типа FILE, в которой будут храниться атрибуты файла

FILE *fl,

где *fl указатель на файл.

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

fl=fopen("путь к файлу","режим работы файла");

Параметр "путь к файлу" указывает размещение файла на диске и обязательно содержит имя файла и может содержать имя логического диска и путь.

Параметр "режим работы файла"показывает, как будет использоваться файл:

"w" – для записи данных (вывод);

"r" – для чтения данных (ввод);

"a" – для добавления данных к существующим записям.

Примеры открытия файлов:

FILE *f_in,*_out;

f_in=fopen("My_file1","r");

f_out=fopen("My_file2","w");

Функция fopen() возвращает значение указателя на структуру типа файл. Если файл по каким-либо причинам не открывается, функция fopen() возвращает значение NULL.

Рассмотрим особенности режимов открытия файлов. Если файл открывается в режиме записи данных "w", то указатель текущей позиции устанавливается на начало файла. Если указанный в функции fopen() файл не существует, то он создается. Необходимо помнить, что открытие существующего файла в режиме "w" приводит к уничтожению его старого содержания.

Открытие файла для чтения в режиме "r" возможно только для созданного ранее файла, при этом указатель текущей позиции устанавливается на начало файла. Если открываемый на чтение файл не существует, функция fopen() возвращает пустой указатель со значением NULL.

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

Также можно указать дополнительные условия режима открытия файла:

"b" – двоичный поток;

"t" – текстовый поток;

"+" – обновление файла.

Пример

"r+" – чтение файла с обновлением, т. е. возможна перезапись данных с усечением;

"w+" – запись в файл и одновременно чтение;

"a+" – добавление данных и чтение.

Для поочередного выполнения чтения и записи в режиме "+" необходимо ручное позиционирование курсора.

Обработка открытого файла

Каким образом можно прочитать уже открытый файл или записать в него информацию? Для этого в языке C существуют специальные функции:

Чтение (ввод) Запись (вывод)
getc() putc()
fscanf() fprintf()
fgets() fputs()
fread() fwrite()

При каждой операции ввода/вывода указатель текущей позиции файла смещается на одну позицию в сторону конца файла.

Проверка признака конца файла

Так как при каждой операции ввода/вывода происходит перемещение указателя текущей позиции в файле, в какой-то момент указатель достигает конца файла. Структура типа FILE имеет поле – индикатор конца файла. Функция feof() проверяет состояние индикатора конца файла и возвращает значение 0, если конец файла не был достигнут, или значение, отличное от нуля, если был достигнут конец файла. Функция имеет единственный аргумент – указатель на поток типа FILE. Вызов функции:

if (! feof(f_in))…

проверяет, что конец файла еще не достигнут.

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

После завершения обработки файла его следует закрыть с помощью функции fclose(). При этом разрывается связь указателя на файл c внешним набором данных. Освободившийся указатель можно использовать для другого файла. Формат вызова функции:

fclose(f_in);

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

Простейший способ выполнить чтение из файла или запись в файл – использовать функции getc() или putc().

Функция getc() выбирает из файла очередной символ; ей нужно только знать указатель на файл, например, char Symb=getc(f_in);

Если при обработке достигается конец файла, то функция getc() возвращает значение EOF(end of file).

Функция putc() заносит значение символа Symb в файл, на который указывает f_out. Формат вызова функции: putc(Symb,f_out);

Пример 1. Текст из файла my_char.txtвыводится на экран. Если файл не найден, на экран выводится сообщение "File not found!":

#include <stdio.h>

int main(void)

{

ch=getc(prt);

FILE *ptr;

unsigned char ch;

if ((ptr=fopen("my_char.txt","r"))!=NULL)

{

ch=getc(ptr);

while (!feof(ptr))

{

printf("%c",ch);

ch=getc(prt);

}

fclose(ptr);

}

else printf("\nFile not found!");

return 0;

}

В этом примере для чтения из файла используется переменная ptr. При открытии файла производится проверка. Если переменной ptr присвоено значение NULL, то файл не найден; на экран выводится соответствующее сообщение, и программа завершается. Если ptr получила ненулевое значение, то файл открыт. Далее выполняется чтение символов из файла до тех пор, пока не будет достигнут конец файла (!feof(ptr)). Прочитанные символы помещаются в переменную ch, а затем выводятся на экран.

Пример 2. Записать в файл буквы, вводимые с клавиатуры. Ввод продолжается до нажатия клавиши F6 или CTRL/z (ввод символа EOF – конца файла):

#include <stdio.h>

int main(void)

{

char c;

FILE *out;

out=fopen("Liter","w");

while ((c=getchar())!=EOF)

fputc(c,out);

fclose(out);

return 0;

}

Функции fscanf() и fprintf() выполняют форматированный ввод/вывод. Чтение из файла выполняет функция fscanf():

fscanf(f_in,[строка формата],[список адресов переменных]);

Функция возвращает количество введенных значений или EOF.

Запись в файл осуществляет функция fprintf():

fprintf(f_out,[строка формата],[список переменных, констант]);

Возвращает количество выведенных байт (символов) или EOF.

Строка формата функций fscanf() и fprintf() формируется так же, как было описано ранее в гл. 5, посвященной консольному вводу/выводу и функциям printf() и scanf().

Следует заметить, что вызов функции

fscanf(stdin,[строка формата],[список адресов переменных]);

эквивалентен вызову

scanf([строка формата],[список адресов переменных]);

Аналогично,

fprintf(stdout, [строка формата],[список переменных, констант]);

эквивалентно

printf([строка формата],[список переменных, констант]);

Рассмотрим примеры программ, использующих эти функции.

Пример 3. В программе создается массив, состоящий из четырех целых чисел. Вывести массив в файл:

#include <stdio.h>

#define n 4

int main()

{

int i=0;

int array[n]={4,44,446,4466};

FILE *out;

out=fopen("num_arr.txt","w");

for(;i<n;i++)

fprintf(out,"%6.2d",array[i]);

fclose(out);

return 0;

}

В результате выполнения программы в файл num_arr.txt будет помещена следующая информация:

                                               

Пример 4. Имеется файл данных, содержащий целые числа, разделенные пробелами. Количество чисел в файле неизвестно. Требуется найти среднее арифметическое значение этих чисел:

#include <stdio.h>

int main()

{

int S=0, count=0, numb;

FILE *in;

if ((in=fopen("num_arr.txt","r"))!=NULL)

{

while (!feof(in))

{

fscanf(in,"%d",&numb);

S+=numb;

count++;

printf("%d\n", numb);

}

double aver=(double)S/count;

printf("Average=%lf\n", aver);

fclose(in);

}

else

printf("\nФайл не найден!");

return 0;

}

Чтение чисел из файла выполняется в переменную numb до тех пор, пока не будет достигнут конец файла. Одновременно ведется подсчет количества прочитанных символов в переменнойcount и накопление суммы прочитанных чисел в переменной S. Переменные S и count целые, поэтому для правильного вычисления среднего арифметического, необходимо выполнить преобразование одной из этих переменных в формат double.

Потоковая функция или макрокоманда Назначение
fopen Открывает поток для чтения и (или) записи
fclose Закрывает поток
fread Читает блок данных из потока
fgets Читает строку текста из потока
fscanf Читает форматированные данные из потока
fwrite Записывает блок данных в поток
fputs Записывает строку текста в поток
fprintf Записывает форматированное данное в поток
fseek Перемещает указатель чтения или записи в потоке
ftell Возвращает текущую позицию в потоке, начиная с которой будет выполнена следующая операция чтения или записи. Возвращаемое значение - это количество байтов смещения относительно начала потока
freopen Повторно использует указатель потока для ссылки на новый файл
fdopen Открывает потоковый файл с указанным дескриптором
feof Макрокоманда, которая возвращает ненулевое значение, если в данном потоке обнаружен символ конца файла, в противном случае - нулевое значение
ferror Макрокоманда, которая возвращает ненулевое значение, если в данном потоке была обнаружена ошибка или символ конца файла, в противном случае - нулевое значение
clearer Макрокоманда, которая сбрасывает флаг наличия ошибок в данном потоке
fileno Макрокоманда, которая возвращает дескриптор данного потокового файла

Функция fseek()

Функция fseek() позволяет нам обрабатывать файл подобно массиву и непосредственно достигать любого определенного байта в файле, открытом функцией fopen(). fseek() имеет три аргумента и возвращает значение типа int.
Покажем на примере работу fseek():

/* использование fseek() для печати содержимого файла */

#include <stdio.h>

main(number,names)

int number; char *names[ ];

{

FILE *fp; long set = 0L;

if(number<2)

puts("Введите имя файла в качестве аргумента.");

else {

if ((fp=fopen(names[1],"r")) == 0)

printf("Нельзя открыть %s\n",names[1]);

else {

while(fseek(fp, set++,0) ==0)

putchar(getc(fp));

fclose(fp);

}

}

}

Первый из трех аргументов функции fseek() является указателем типа FILE на файл, в котором ведется поиск. Файл следует открыть, используя функцию fopen(). Второй аргумент "set". Этот аргумент сообщает, как далеко следует передвинуться от начальной точки (см. ниже). Он должен иметь значение типа long, которое может быть положительным (движение вперед) или отрицательным (движение назад). Третий аргумент является кодом, определяющим начальную точку.
Функция fseek() возвращает 0, если все хорошо, и -1, если есть ошибка. Поскольку переменная set инициализирована нулем, при первом прохождении через цикл

while(fseek(fp,set++,0)==0)

putchar(getc(fp));

мы имеем выражение

fseek(fp,OL,0);

означающее, что мы идем в файл, на который ссылается указатель fp, и находим байт, отстоящий на 0 байт от начала, т.е. первый байт. Затем функция putchar() печатает содержимое этого байта. При следующем прохождении через цикл переменная set увеличивается до 1L, и печатается следующий байт. То есть, переменная set действует подобно индексу для элементов файла. Процесс продолжается до тех пор, пока set не попытается попасть в fseek() после конца файла. В этом случае fseek() возвращает значение -1 и цикл прекращается.

 

Файлы.

Для работы с файлами в языке С++ имеется набор функций, определенных в библиотеке stdio.h. Перед началом работы с файлом его следует открыть, что достигается с помощью функции fopen(), имеющей следующий синтаксис:

FILE *fopen(const char *filename, const char *mode);

 

Здесь filename – строка, содержащая путь и имя файла; mode – строка, определяющая режим открытия файла: на чтение или на запись; FILE – специальный тип данных для работы с файлами. Данная функция возвращает значение NULL, если файл не был успешно открыт, иначе – другое значение. Рассмотрим последовательность действий по созданию простого текстового файла на языке C++ и записи в него текстовой информации.

 

Листинг 5.1. Запись текстовой информации в файл.

 

#include

int main()

{

char str_file[]=”Строка для файла”;

FILE* fp = fopen(“my_file.txt”,”w”);

if(fp!= NULL)

{

printf(“Идет запись информации в файл…\n”);

for(int i=0;i < strlen(str_file);i++)

putc(str_file[i],fp);

}

else printf(“Невозможно открыть файл на запись.\n”);

fclose(fp);

return 0;

}

 

В данном примере задается специализированный указатель fp типа FILE, который инициализируется функцией fopen(). Функция fopen() в качестве первого аргумента принимает строку, в которой задан путь и имя файла. Вторым параметром определяется способ обработки файла, в данном случае, значение “w”, которое означает открытие файла на запись с удалением всей прежней информации из него. Если файл открыт успешно, то указатель fp не будет равен NULL и с ним возможна работа. В этом случае с помощью функции putc() выполняется запись символов в файл, на который указывает указатель fp. Перед завершением программы открытый файл следует закрыть во избежание в нем потери данных. Это достигается функцией fclose(), которая принимает указатель на файл и возвращает значение 0 при успешном закрытии файла, иначе значение EOF.

 

Рассмотрим теперь пример программы считывания информации из файла.

 

Листинг 5.2. Считывание текстовой информации из файла.

 

#include

int main()

{

char str_file[100];

FILE* fp = fopen(“my_file.txt”,”r”);

if(fp!= NULL)

{

int i=0;

char ch;

while((ch = getc(fp))!= EOF)

str_file[i++]=ch;

str_file[i] = ‘\0’;

printf(str_file);

}

else printf(“Невозможно открыть файл на чтение.\n”);

fclose(fp);

return 0;

}

 

В приведенном листинге функция fopen() открывает файл на чтение, что определяется значением второго аргумента равного «r». Это значит, что в него невозможно произвести запись данных, а только считывание. Сначала выполняется цикл while, в котором из файла считывается символ с помощью функции getc() и выполняется проверка: если считанное значение не равно символу конца файла EOF, то значение переменной ch записывается в массив str_file. Данный цикл будет выполняться до тех пор, пока не будут считаны все символы из файла, т.е. пока не будет достигнут символ EOF. После завершения цикла формируется строка str_file, которая выводится на экран с помощью функции printf(). Перед завершением программы также выполняется функция закрытия файла fclose().

 

Работа с текстовыми файлами через функции putc и getc не всегда удобна. Например, если необходимо записать или считать строку целиком, то желательно иметь функции, выполняющие эту работу. В качестве таковых можно воспользоваться функциями fputs() и fgets() для работы со строками. Перепишем предыдущие примеры с использованием данных функций.

 

Листинг 5.3. Использование функций fpust() и fgets().

 

#include

int main()

{

char str_file[]=”Строка для файла”;

FILE* fp = fopen(“my_file.txt”,”w”);

if(fp!= NULL) fputs(str_file,fp);

else printf(“Невозможно открыть файл на запись.\n”);

fclose(fp);

fp = fopen(“my_file.txt”,”r”);

if(fp!= NULL)

{

fgets(str_file,sizeof(str_file),fp);

printf(str_file);

}

fclose(fp);

return 0;

}

 

Аналогичные действия по записи данных в файл и считывания информации из него можно выполнить и с помощью функций fprintf() и fscanf(). Однако эти функции предоставляют большую гибкость в обработке данных файла. Продемонстрируем это на следующем примере. Допустим, имеется структура, хранящая информацию о книге: название, автор, год издания. Необходимо написать программу сохранения этой информации в текстовый файл и их считывания. Пример использования данных функций представлен в листинге 5.4.

 

Листинг 5.4. Использование функций fprintf() и fscanf().

 

#include

#define N 2

struct tag_book

{

char name[100];

char author[100];

int year;

} books[N];

 

int main(void)

{

for(int i=0;i < N;i++)

{

scanf("%s",books[i].name);

scanf("%s",books[i].author);

scanf("%d",&books[i].year);

}

 

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

{

puts(books[i].name);

puts(books[i].author);

printf("%d\n",books[i].year);

}

 

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

fprintf(fp,"%s %s %d\n",books[i].name,books[i].author,

books[i].year);

fclose(fp);

fp = fopen("my_file.txt","r");

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

fscanf(fp,"%s %s %d\n",books[i].name,books[i].author,

&books[i].year);

fclose(fp);

printf("------------------------------------------------\n");

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

{

puts(books[i].name);

puts(books[i].author);

printf("%d\n",books[i].year);

}

return 0;

}

 

При выполнении данной программы вводится информация по книгам в массив структур books и выводится введенная информация на экран. Затем открывается файл my_file.txt на запись, в который заносится информация по книгам в порядке: наименование, автор, год издания. Так как число книг в данном случае равно двум, то выходной файл будет выглядеть следующим образом:

 

Onegin Pushkin 1983

Oblomov Griboedov 1985

 

Затем, файл my_file.txt открывается на чтение и с помощью функции scanf() осуществляется считывание информации в элементы структуры. В заключении считанная информация выводится на экран монитора.

 

Представленный пример показывает возможность структурированной записи информации в файл и ее считывания. Это позволяет относительно просто сохранять разнородные данные в файле для их дальнейшего использования в программах.

 

При внимательном рассмотрении предыдущих примеров можно заметить, что функции считывания информации из файла «знают» с какой позиции следует считывать очередную порцию данных. Действительно, в последнем примере функция fscanf(), вызываемая в цикле, «знает» что нужно считать сначала первую строку из файла, затем вторую и т.д. И программисту нет необходимости задавать позицию для считывания данных. Все происходит автоматически. Вследствие чего появляется такая особенность работы? Дело в том, что у любого открытого файла в программе написанной на С++ имеется указатель позиции (номера), с которой осуществляется считывание данных из файла. При открывании файла на чтение номер этой позиции указывает на начало файла. Поэтому функция fscanf(), вызванная первый раз, считывает данные первой строки. По мере считывания информации из файла, позиция сдвигается на число считанных символов. И функция fscanf() вызванная второй раз будет работать уже со второй строкой в файле. Несмотря на то, что указатель позиции в файле перемещается автоматически, в языке С++ имеются функции fseek() и ftell(), позволяющие программно управлять положением позиции в файле. Синтаксис данных функций следующий:

 

int fseek(FILE *stream, long offset, int origin);

long ftell(FILE *stream);

 

где *stream – указатель на файл; offset – смещение позиции в файле (в байтах); origin – флаг начального отсчета, который может принимать значения: SEEK_END – конец файла, SEEK_SET – начало файла; SEEK_CUR – текущая позиция. Последняя функция возвращает номер текущей позиции в файле.

 

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

 

Листинг 5.5. Использование функций fseek() и ftell().

 

#include

int main(void)

{

FILE* fp = fopen("my_file.txt","w");

if(fp!= NULL)

{

fprintf(fp,"It is an example using fseek and ftell functions.");

}

fclose(fp);

fp = fopen("my_file.txt","r");

if(fp!= NULL)

{

char ch;

fseek(fp,0L,SEEK_END);

long length = ftell(fp);

printf("length = %ld\n",length);

for(int i = 1;i <= length;i++)

{

fseek(fp,-i,SEEK_END);

ch = getc(fp);

putchar(ch);

}

}

fclose(fp);

return 0;

}

 

В данном примере сначала создается файл, в который записывается строка “It is an example using fseek and ftell functions.”. Затем этот файл открывается на чтение и с помощью функции fseek(fp,0L,SEEK_END) указатель позиции помещается в конец файла. Это достигается за счет установки флага SEEK_END, который перемещает позицию в конец файла при нулевом смещении. В результате функция ftell(fp) возвратит число символов в открытом файле. В цикле функция fseek(fp,-i,SEEK_END) смещает указатель позиции на –i символов относительно конца файла, после чего считывается символ функцией getc(), стоящий на i-й позиции с конца. Так как переменная i пробегает значения от 1 до length, то на экран будут выведены символы из файла в обратном порядке.

 

Имя Что делает эта функция
fopen() Открывает файл
fclose() Закрывает файл
putc() Записывает символ в файл
fputc() То же, что и putc()
getc() Читает символ из файла
fgetc() То же, что и getc()
fgets() Читает строку из файла
fputs() Записывает строку в файл
fseek() Устанавливает указатель текущей позиции на определенный байт файла
ftell() Возвращает текущее значение указателя текущей позиции в файле
fprintf() Для файла то же, что printf() для консоли
fscanf() Для файла то же, что scanf() для консоли
feof() Возвращает значение true (истина), если достигнут конец файла
ferror() Возвращает значение true (истина), если произошла ошибка
rewind() Устанавливает указатель текущей позиции в начало файла
remove() Стирает файл
fflush() Дозапись потока в файл

 

 

Потоки.

Концепция потоков С++ нацелена на решение нескольких

проблем, решаемых стандартными библиотечнымифункциями ввода/

вывода С, такими какprintfи scanf. Последние, разумеется ос-

таются доступными для программиста, работающего в С++, но

улучшенная гибкость и элегантность потоков С++ уменьшают

привлекательность функций библиотеки stdio.h. Классы, свя-

занные с потоками С++, предлагают вам расширяемые библиоте-

ки, позволяющие вам выполнять форматированный ввод/выводс

контролемтипов какдля предопределенных, так и для определяе-

мых пользователем типов данных спомощью перегруженных опера-

цийи прочих объектно-ориентированных методов.

 

Для обращения к вводу/выводу потоком ваша программа

должна включать файл iostream.h. Для некоторых функций пото-

ков требуются и другие файлы заголовка. Например, для выпол-

нения форматирования в оперативной памяти с использованием

классов istrstream и ostrstream необходим файл strstream.h.

Файл заголовка strstream.h включает также iostream.h. Если

вам требуется класс fstream, включите файл fstream.h,так-

жевключающий iostream.h. И разумеется, можно включить однов-

ременно и fstream.h, и strstream.h.

 

Что такое поток?

 

Потоком называется абстрактное понятие, относящееся к

любому переносу данных от источника (или поставщика данных)

к приемнику (или потребителю) данных. Также используются си-

нонимы извлечение, прием и получение, когда речь идет о вво-

де символов от источника, и вставка, помещение или запомина-

ние, когда речь идет о выводе символов на приемник.

 

Несмотря на свое имя, класс потока может быть

использован для форматирования данных в ситуациях, не подра-

зумевающих реального выполнения ввода/вывода. Вы увидите,

что форматирование в памяти можно применять к символьным

массивам и прочим структурам.

 

Библиотека iostream

 

Библиотека iostream имеет два параллельных класса:

streambuf и ios. Оба они являются классами низкого уровня и

каждый выполняет свой круг задач.

 

 

streambuf

___________________________________________________________

 

Класс streambufобеспечивает общие правила буферизации и

обработки потоков в тех случаях, когда не требуется значи-

тельного форматирования этих потоков. streambuf представляет

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

библиотеки iostream, хотя он доступен также и для производ-

ных классов в ваших функциях и библиотеках. Большинство

функций-компонентов (правил) streambuf являются встраиваемы-

ми для обеспечения максимальной эффективности. Классы

strstreambuf и filebuf являются производными от streambuf.

 

ios

___________________________________________________________

 

Класс ios (и следовательно, производные от него классы)

содержит указатель на streambuf.

 

ios имеет два производных класса: istream (для ввода) и

ostream (для вывода). Другой класс, iostream, является про-

изводным классом сразуот istream иostream вследствие мно-

жественного наследования:

 

class ios;

class istream: virtual public ios;

class ostream: virtual public ios;

classiostream: public istream, public ostream;

 

Кроме того, существуеттри класса withassign, являющихся

производными классами от istream, ostream и iostream:

 

class istream_withassign: public istream;

class ostream_withassign: public ostream;

class iostream_withassign: public iostream;

 

Классы потоков

___________________________________________________________

 

- Класс ios содержит переменные состояния для интерфей-

са с streambuf и обработки ошибок.

 

- Класс istream поддерживает как форматированные, так и

неформатированные преобр



Поделиться:


Последнее изменение этой страницы: 2016-08-15; просмотров: 883; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.217.144.32 (0.466 с.)