КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Как вводить строки или выводить их на экран?
Выводиться строка может или уже известной вам функцией printf() со спецификатором ввода "%s ", либо специальной функцией int puts (char *string), которая выводит строку string на экран и возвращает некоторое ненулевое значение в случае успеха. Зачем нужен спецификатор " %s "? Это делается для того, чтобы можно было выводить строки с любыми символами. Сравните: Пример: char str [] = "Захотелось мне вывести %d..."; printf ("%s", str); /* Правильный вариант */ printf ("\n"); /* Разделитель новой строки */ printf (str); /* Неправильный вариант */ В первом случае функция напечатает именно то, что от нее требуется. А вот во втором случае printf(), встретив в строке str спецификатор "%d" (ведь теперь эта строка – первая, значит, она задает формат вывода), сделает вывод, что за ней должно следовать число. А так как оно не следует, то вместо " %d " будет напечатан некоторый мусор – число, находящееся в тот момент в стеке. Последствия могут быть и более серьезными, если в строке находится последовательность "%s", то сочтет ее за строку, и будет выводить ее до тех пор, пока не встретит нулевой символ. А где она его встретит, сколько успеет напечатать и не crash'нется ли из-за обращения не к своей памяти – не знает никто. Cоглашение о признаке окончания строки нужно соблюдать, формируя в программах строки из отдельных символов. В качестве примера рассмотрим следующую
Пример: Необходимо сохранить введенную строку. /*чтение строки с терминала*/ int getline(char s, / *введенная строка*/ int lim) /*ее максимальная длина*/ { int c, i; /* с – вводимый символ*/
for (i=0; i<lim && (c = getchar())!=EOF && c!=’\n’; i++) { s[i]=c; } s[i] = ’\0’; return i; }
9.5 Ввод–вывод строк. Основные функции работы со строками
Одной из наиболее популярных операций ввода-вывода является операция ввода-вывода строки символов. В библиотеку языка СИ для обмена данными через стандартные потоки ввода-вывода включены функции ввода-вывода строк gets() и puts(), которые удобно использовать при создании диалоговых систем. Для ввода строки существует функция с прототипом char *gets (char *string), которая считывает строку с клавиатуры и помещает ее в буфер string, указатель на который и возвращает. Если произошла ошибка, то возвращается EOF. Функция имеет только один аргумент – указатель s на массив символов. Прототип функции описан в файле <stdio.h>. Функция gets() завершает свою работу при вводе символа ‘\n’, который автоматически передается с клавиатуры в ЭВМ при нажатии клавиши <Enter>. При этом сам символ ‘\n’ во вводимую строку не записывается. Вместо него в строку помещается нуль–символ ‘\0’. Таким образом, функция gets() производит ввод “правильной” строки, а не просто последовательности символов. Здесь следует обратить внимание на следующую особенность ввода данных с клавиатуры. Функция gets() начинает обработку информации от клавиатуры только после нажатия клавиши <Enter>. Таким образом, она “ожидает”, пока не будет набрана нужная информация и нажата клавиша < Enter >. Только после этого начинается ввод данных в программу. Пример: #include <stdio.h> int main (void) { char string[80]; printf ("Input a string:"); gets (string); printf ("The string input was: %s\n", string); return 0; } Функция puts() (вывод строки на экран) в случае успешного завершения возвращает последний выведенный символ, который всегда является символом ‘\n', если произошла ошибка, то возвращается из функции EOF. Прототип этой функции имеет следующий вид: int puts (char*s); /*функция вывода строки*/ Функция имеет только один аргумент – указатель s на массив символов. Прототип функции описан в файле <stdio.h>. Приведем простейший пример использования этих функций.
#include<stdio.h> char strl[ ] = ”введите фамилию сотрудника:”; int main () { char name[80]; puts(strl0; gets(name); return 0; } Напомним, что любая строка символов в языке СИ должна заканчиваться нуль–символом ‘\0’. В последний элемент массива strl нуль–символ будет записан автоматически во время трансляции при инициализации массива. Для функции puts() наличие нуль-символа в конце строки является обязательным. В противном случае, т.е. при отсутствии в символьном массиве символа ‘\0’, программа может завершиться аварийно, т.к. функция puts() в поисках нуль-символа будет перебирать всю доступную память байт за байтом, начиная, в нашем примере, с адреса strl. Об этом необходимо помнить, если в программе происходит формирование строки для вывода ее на экран дисплея. Пример: #include <stdio.h> int main (void) { char string[] = "This is an example output string\n"; puts(string); return 0; }
9.5 Функции манипуляции со строками
Так как в Cи нет предопределенного типа для строки, то нет и столь привычных многим операций, как сравнения и склеивания строк, реализованных во многих языках как операторы сложения и сравнения. Здесь сложение массивов недопустимо, а при сравнении будут сравниваться не сами строки, а только указатели на них, что нам, конечно же, неинтересно. Для манипуляций со строками существует набор функций, объявленных в файле <string.h> (те, кто пишет под Windows, могут включать вместо него файл < windows.h >). Наиболее важные функции: I. int strcmp (char *string1, char *string2) осуществляет сравнение двух строк. Возвращает отрицательное число, если первая строка меньше второй, 0, если строки равны и положительное число, если первая строка больше второй. Более детально, функция возвращает разницу между кодами первых встретившихся неодинаковых символов (если строки неодинаковы по длине, то когда-то ненулевой символ будет сравниваться с нулем). Пример: #include <string.h> #include <stdio.h> int main (void) { char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc"; int ptr; ptr = strcmp (buf2, buf1); if (ptr > 0) printf("buffer 2 is greater than buffer 1 \n"); else printf("buffer 2 is less than buffer 1 \n"); ptr = strcmp(buf2, buf3); if (ptr > 0) printf("buffer 2 is greater than buffer 3\n"); else printf("buffer 2 is less than buffer 3\n"); return 0; } На экране появится: buffer 2 is greater than buffer 1
buffer 2 is less than buffer 3
II. char *strcpy (char *dest, char *source) осуществляет копирование строки source на место строки dest. Опять-таки позаботьтесь о том, чтобы вся строка поместилась в отведенном для нее месте. Функция возвращает указатель на строку-приемник. Пример: #include <stdio.h> #include <string.h> int main (void) { char string[10]; char *str1 = "a b c d e f g h i"; strcpy (string, str1); printf("%s \n", string); return 0; } На экране появится: a b c d e f g h I
III. char *strcat (char *string1, char *string2) осуществляет склеивание двух строк. Вторая строка добавляется в конец первой. Функция не проверяет (да и не может проверять технически) наличие необходимого количества памяти в конце первой строки – об этом должны позаботиться вы. Функция возвращает указатель на первую строку. Пример: #include <string.h> #include <stdio.h> int main(void) { char destination[25]; char *blank = " ", *c = "C++", *turbo = "Turbo"; strcpy (destination, turbo); //Копирование строки "turbo" на место destination strcat (destination, blank); // Склеивание destination … strcat (destination, c); // сначала с blank, потом с c printf("%s\n", destination); return 0; } На экране появится: Turbo C ++
IV. int strlen (char *string) возвращает длину строки string (не считая нулевого символа).
V. char *strdup (char *string) создает дубликат строки string и возвращает указатель на него. Учтите, что в отличие от остальных функций, strdup сама создает строку и поэтому после того, как она стала вам не нужна, не забывайте ее освободить.
VI. char *strncpy (char *dest, char *source, int count) VII. char *strncat (char *string1, char *string2, int count) аналогично strcpy и strcat, но копируются только первые count символов. Функции не добавляют к строке завершающего нуля – вам придется сделать это самим.
VIII. char *strchr (char *string, int c) IX. char *strstr (char *string, char *substring) ищут первое вхождение в строку string соответственно символа c и подстроки substring. Обе функции возвращают адрес первого вхождения или NULL, если такового не найдено. Пример: int main (void) { char string[15]; char *ptr, c = 'r'; //Создаем строку strcpy (string, "This is a string"); ptr = strchr(string, c); if (ptr) printf("The character %c is at position: %d\n", c, ptr-string); else printf("The character was not found\n"); return 0; } На экране появится: The character r is at position: 12 Глава 10 ФAйлы
Файл характеризуется именем, расширением, версией. MS DOS: длина имени <=8 символов, длина расширения <=3 символов. Файл: = <имя> [.<расширение>] Proba.c
Устройство внешней памяти, строго говоря, является устройством поблочного обмена, т.е. за одно обращение к устройству производится считывание или запись фиксированной порции данных. Чаще всего минимальной порцией данных, участвующих в обмене с внешней памятью, являются блоки в 512 или 1024 байтов. При вводе с диска (при чтении из файла) данные помещаются в буфер операционной системы, а затем побайтно или определенными порциями передаются программе пользователя. При вводе данных в файл они накапливаются в буфере, а при заполнении буфера они записываются в виде единого блока на диск за одно обращение к последнему.
Буферы операционной системы реализуются в виде участков основной памяти. Поэтому пересылка между буферами ввода–вывода и выполняемой программой происходит достаточно быстро в отличие от реальных обменов с физическими устройствами. Функции библиотеки ввода-вывода языка СИ, поддерживающие обмен данными с файлом на уровне потока, позволяют обрабатывать данные различных размеров и форматов, обеспечивая при этом буферизированный ввод и вывод. Таким образом,
поток – это файл вместе с предоставляемыми средствами буферизации. Файл + средства_буферизации = поток При работе с потоком можно производить следующие действия: · Открывать и закрывать потоки (связывать указатели на потоки с конкретными файлами). · Вводить и выводить: символ, строку, форматированные данные, порцию данных произвольной длины. · Анализировать ошибки потокового ввода–вывода и условие достижения конца потока (конца файла). · Управлять буферизацией потока и размером буфера. · Получать и устанавливать указатель (индикатор) текущей позиции в потоке. Для того, чтобы можно было использовать функции библиотеки ввода–вывода языка СИ, в программу необходимо включить заголовочный файл stdio.h (#include<stdio.h>), который содержит прототипы функций ввода–вывода, а также описания констант, типов и структур, необходимых для работы функций обмена с потоком.
12.1 Открытие и закрытие потока
Подготовительные операции перед обменом программы с файлом: 1. Проверка наличия файла с данным именем при чтении. 2. Наличие свободного пространства на диске при создании файла. 3. Позиционирование файла. При благополучном открытии файла ОС возвращает целое число, характеризующее этот поток и называемое ДЕСКРИПТОМ файла (потока). FORTRAN READ(5,…) WRITE(6,…) Процесс отсоединения файла от программы после окончания операций с ним называется закрытием файла. При этом освобождаются ресурсы (в основном память). С каждым потоком связан системный буфер, который для MS DOS составляет 512 байтов. Дескриптор – это тоже ресурс, поскольку их число для MS DOS ограничено 255. Также для каждого файла в памяти хранится его описание в виде структуры типа FILE, описанного в файле stdio.h. РЕКОМЕНДАЦИЯ. Желательно закрывать файл явно по причинам: 1. Случайной порчи открытого файла. 2. Возможного повторного открытия того же файла с другим способом обработки. 3. При аварийном завершении программы информация, хранимая в системном буфере пропадает. 4. Возможность сэкономить на количестве открываемых потоков.
Прежде чем начать работать с потоком, его необходимо инициализировать, т.е. открыть. При этом поток связывается в исполняемой программе со структурой предопределенного типа FILE. Для каждого файла в памяти хранится его описание в виде структуры типа FILE. Определение структурного типа FILE находится в заголовочном файле stdio.h. В структуре FILE находятся компоненты, с помощью которых ведется работа с потоком, в частности: указатель на буфер, указатель (индикатор) текущей позиции в потоке и друга информация. При открытии потока в программу возвращается указатель на поток, являющийся указателем на объект структурного типа FILE. Этот указатель идентифицирует поток во всех последующих операциях. Указатель на поток, например fp, должен быть (1) объявлен в программе следующим образом: #include <stdio.h> FILE *fp; Указатель на поток (2) приобретает значение в результате выполнения функцией открытия потока: Формат: <указатель_на_поток> = fopen (<имя_файла>, <режим_открытия>);
Параметры <имя_файла> и <режим_открытия> являются указателями на массивы символов (строки!), содержащие, соответственно, имя файла, связанного с потоком, и строку режимов открытия. Однако, эти параметры могут задаваться и непосредственно в виде строк при вызове функции открытия файла. Например: fp = fopen (“t.txt”, ”r”); где t.txt –имя некоторого файла, связанного с потоком; r – обозначение одного из режимов работы с файлом (тип доступа к потоку). Стандартный текстовый файл можно открыть в одном из следующих шести режимов: “w” –новый текстовый (см. ниже) файл открывается для записи. Если файл уже существовал, то предыдущее содержимое стирается и файл создается заново. “r” – существующий текстовый файл открывается только для чтения. “a” – текстовый файл открывается (или создается, если файла нет) для добавления в него новой порции информации (добавление в конец файла). В отличие от режима “w” режим “a” позволяет открывать уже существующий файл, не уничтожая его предыдущей версии, и писать в продолжение файла. “w+” – новый текстовый файл откравается для записи и последующих многократных исправлений. Если файл уже существует, то предыдущее содержимое стирается. Последующие после открытия файла запись и чтение из него допустимы в любом месте файла, в том числе запись разрешается и в конец файла, т.е. файл может увеличиваться (“расти”). “r+” – существующий текстовый файл открывается как для чтения, так и для записи в любом месте файла, однако в этом режиме невозможна запись в конец файла, т.е. недупустимо увеличение размеров файла. “a+” – текстовый файл открывается или создается (если файла нет) и становится доступным для изменений, т.е. для записи и для чтения в любом месте; при этом в отличие от режима “w+” можно открыть существующий файл и не уничтожать его содержимое; в отличие от режима “r+” в режиме “a+” можно ввести запись в конец файла, т.е. увеличивать его размер.
Поток можно открыть в текстовом или двоичном (бинарном) режиме. В текстовом режиме прочитанная из потока комбинация символов CR (значение 13) и LF (значение 10), т.е. управляющие коды операции “возврат каретки” и “перевод строки”, преобразуется в один новый символ ‘\n’ (значение 10, совпадающее с LF). При записи в поток в текстовом режиме осуществляется обратное преобразование, т.е. символ новой строки ‘\n’ (LF) заменяется последовательностью CR и LF. Если файл, связанный с потоком, хранит не текстовую, а произвольную двоичную информацию, то указанные преобразования не нужны и могут быть даже вредными. Обмен без такого преобразования выполняется при выборе двоичного или бинарного режима, который обозначается буквой b. Например “r+b ” или “ wb ”. В некоторых компиляторах текстовый режим обмена обозначается буквой t, т.е. записывают “a+t” или “rt”. Если поток открыт для изменений, т.е. в параметре режима присутствует символ “ + ”, то разрешены как чтение из потока так и запись в него. Однако смена режима (переход от записи к чтению и обратно) должна происходить только после установки указателя потока в нужную позицию. При открытии потока могут возникнуть следующие ошибки: 1. Указанный файл, связанный с потоком, не найден (для режима чтения). 2. Диск заполнен или защищен от записи и т.п. 3. Необходимо также отметить, что при выполнении функции fopen() происходит выделение динамической памяти. При ее отсутствии устанавливается признак ошибки ” Not entough memory ” (недостаточно памяти). В перечисленных случаях указатель на поток приобретает значение NULL. Заметим. Что указатель на поток в любом режиме, отличном от аварийного, никогда не бывает равным NULL. Приведем типичную последовательность операторов, которая используется при открытии файла, связанного с потоком: if ((fp=fope(“t.txt”,”w”)) = = NULL) { perror(“ошибка при открытии файла t.txt \n”); exit (0); } где NULL – нулевой указатель, определенный в файле stdio.h. Для вывода на экран дисплея сообщения об ошибке при открытии потока используется стандартная библиотечная функция perror(), прототип которой в stdio.h имеет вид: void perror (const char *s); Функция perror() выводит строку символов, адресуемую указателем s, за которой размещаются: двоеточие, пробел и сообщение об ошибке. Содержимое и формат сообщения определяются реализацией системы программирования. Текст сообщения об ошибке выбирается функцией perror() на основании номера ошибки. Номер ошибки заносится в переменную int erno (определяется в заголовочном файле erno.h) рядом функций библиотеки языка СИ, в том числе и функциями ввода-вывода. После того, как файл открыт, с ним можно работать, записывая в него информацию или считывая ее (в зависимости от режима). Открытые на диске файлы рекомендуется закрывать явно. Для этого используется библиотечная функция. int fclose (<указатель_на_поток>);
Открытый файл можно открыть повторно (например, для изменения режима работы с ним) только после того, как файл будет закрыт с помощью функции fclose(). Пример: FILE *f, *fp; if ((f=fopen (“inp3.txt”,”rt”)) = = NULL) { printf(“cannot open input file.\n”); return 1; } fscanf (f, ”%d”, &count); fclose (f); if (!(fp = fopen ("inp3.txt", "r"))) exit 0; fscanf (fp, ”%d”, &razruad); fclose (fp); 12.2 Работа с файлами на диске
Аналогичным образом, как это делается со стандартными потоками ввода–вывода, можно осуществлять работу с файлами на диске. Для этой цели в библиотеке языка СИ включены следующие функции: fgetc() –ввод (чтение) одного символа из файла. fputc() –запись одного символа в файл. fprintf() –форматированный вывод в файл. fscanf() –форматированный ввод (чтение) из файла. fgets() –ввод (чтение) строки из файла. int fgets(FILE *stream); fputs() –запись одной строки в файл. 1. int fgetc(FILE *stream) –чтение одного символа из файла. int fputc(int c, FILE *stream) – запись одного символа в файл. Например: void main(void) { FILE *stream; char ch; stream=fopen(“DYMMY.FIL”, “+w”); do{ ch=fgetc(stream); putch(ch); } while (ch!= EOF);
fclose(stream); } Например: #include<stdio.h> void main(void) { char msg[]=“hello, world”; int i=0; while(msg[i]) fputc(msg[i], stdout); }
2. fprintf() –форматированный вывод в файл. fscanf() –форматированный ввод (чтение) из файла. Например: #include<stdio.h> void main(void) { FILE *stream; int i=100; float f= 1.2345; char c=‘C’; stream=fopen(“DYMMY.FIL”, “w+”); fprintf(stream, “%d %c %.4f”, i, c, f); fclose(stream); } 3. char *fgets(char *s, int n, FILE *stream) – функция чтения строки из файла. int fputs(const char *s, FILE *stream) – функция записи строки в поток. Например: void main (void) {FILE *stream; char msg[20]; stream=fopen(“DYMMY.FIL”, “w+”); fputs(“\nHello, WORLD”, stream); fclose(stream); stream=fopen(“DYMMY.FIL”, “r”); fgets(msg, strlen(str)+1, stream); printf(“%s”, msg); fclose(stream); }
В качестве примера использования функций getс() и putс() рассмотрим программы ввода данных в файл с клавиатуры и программу вывода их на экран дисплея из файла. Программа ввода читает символы с клавиатуры и записывает их в файл. Пусть признаком завершения ввода служит поступивший от клавиатуры символ “#”. Имя файла запрашивается у пользователя. Если при вводе последовательности символов была нажата клавиша <Enter>, служащая разделителем строк при вводе с клавиатуры, то в файл записываются коды “возврат каретки” (CR – значение 13) и “перевод строки” (LF – значение 10). Код CR в дальнейшем при вызове вызывает перевод маркера (курсора) в начало строки экрана дисплея. Код LF служит для перевода маркера на новую строку дисплея. Значения этих кодов в тексте программы обозначены соответственно идентификаторами CR и LF, т.е. CR и LF – именованные константы. Запись управляющих кодов CR и LF в файл позволяет при последующем вызове файла на экран отделить строки друг от друга.
Пример: /*программа записи (ввода) символов в поток (файл)*/ #include<stdio.h> int main() { FILE *fp; /*указатель на поток*/ char c, fname[20]; /*массив для имени файла*/ const char CR=‘\015’, /*восьмиричный код возврата каретки*/ LF=‘\012’; /*восьмеричный код перевода строки*/ /*запрос имени файла*/ puts (“Введите имя файла:\n”); gets(fname); /*открыть файл для записи*\ if ((fp=fopen(fname, “w”)) = = NULL) { perror(fname); return 1; } /*цикл ввода и записи в файл символов*\ while ((c=getch())!= ‘#’) { if (c == ‘\n’) { fputc(CR,fp); fputc(LF,fp); } else { fputc(c,fp); putc(c); } } /* цикл ввода завершен; закрыть поток: */ fclose (fp); return 0; } Пример: /*программа вывода потока (файла) на экран дисплея*/ #include<stdio.h> int main(void) { FILE *fp; /*указатель на поток*/ char c; char fname[20]; /*массив для имени файла*/ /*запрос имени файла*/ puts(“введите имя файла:\n”); gets (fname); /*открыть файл для чтения*/ if ((fp=fopen(fname, “r”)) == NULL) { perror(fname); return 1; } /*цикл чтения из файла и вывода символов на экран*/ while ((c=fgetc(fp))!= EOF) putchar (c); fclose(fp); } /*закрыть файл*/
ЗАКЛЮЧИТЕЛЬНЫЙ ПРИМЕР ПО ТЕМЕ "ФАЙЛЫ" // Дан символьный файл f.dat. Записать в файл: // h_otr.dat все отрицательные компоненты исходного файла, // h_por.dat компоненты исходного файла, упорядоченные по возрастанию,
Дата добавления: 2014-01-05; Просмотров: 1580; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |