- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор sizeof
- •Оператор «запятая»
- •Операторы [ ] u ()
- •Приоритеты в с
- •Выражения
- •Преобразование типов в выражениях
- •Принудительные преобразования
- •Пробелы и круглые скобки
- •Сокращенные операторы в с
- •Операторы управления программой
- •Истина и ложь в с
- •Операторы выбора
- •Вложенные if
- •Лесенка if-else-if
- •Оператор ?
- •Вложенные операторы switch
- •Вариации цикла for
- •Бесконечный цикл
- •Циклы for без тела
- •Метки и goto
- •Функции
- •Оператор return
- •Выход из функции
- •Возвращаемые значения
- •Значения, возвращаемые функцией main()
- •Правила видимости для функций
- •Аргументы функции
- •Передача по значению и передача по ссылке
- •Создание передачи по ссылке
- •Передача массивов в функции
- •Аргументы функции main()
- •Функции, возвращающие нецелые значения
- •Использование прототипов функции
- •Прототипы стандартных библиотечных функций
- •Создание прототипов функций, не имеющих параметров
- •Возврат указателей
- •Рекурсия
- •Сопоставление классического и современного объявления параметров
- •Указатели на функции
- •Особенности реализации
- •Параметризированные функции и функции общего назначения
- •Эффективность
- •Массивы
- •Одномерный массив
- •Создание указателя на массив
- •Передача одномерных массивов в функции
- •Двумерные массивы
- •Массивы строк
- •Многомерные массивы
- •Индексация с помощью указателей
- •Размещение массивов
- •Инициализация массива
- •Инициализация безразмерных массивов
- •Пример программы игры в крестики-нолики
- •Указатели
- •Указатели - это адреса
- •Переменные-указатели
- •Операторы для работы с указателями
- •Выражения с указателями
- •Присваивание указателей
- •Арифметические действия с указателями
- •Сравнение указателей
- •Динамическое выделение и указатели
- •Указатели на константы
- •Указатели на константы
- •Указатели на константы
- •Указатели и массивы
- •Указатели на символьные массивы
- •Массивы указателей
- •Указатели на указатели - многочисленное перенаправление
- •Инициализация указателей
- •Указатели на функции
- •Проблемы, связанные с указателями
- •Структуры, объединения и определяемые пользователем типы
- •Структуры
- •Доступ к членам структуры
- •Присваивание структур
- •Массивы структур
- •Программа инвентаризации
- •Передача структур в функции
- •Передача членов структур в функции
- •Передача всей структуры в функцию
- •Указатели на структуры
- •Объявление указателя на структуру
- •Использование указателей на структуру
- •Массивы и структуры в структурах
- •Битовые поля
- •Объединения
- •Перечисления
- •Использование sizeof для обеспечения переносимости
- •Ввод, вывод, потоки и файлы
- •Потоки и файлы
- •Текстовые потоки
- •Двоичные потоки
- •Консольный ввод/вывод
- •Чтение и запись символов
- •Чтение и запись строк: gets() и puts()
- •Форматированный консольный ввод/вывод
- •Печать символов
- •Вывод чисел
- •Вывод адресов
- •Спецификатор %n
- •Модификаторы формата
- •Спецификатор минимума ширины поля
- •Спецификатор точности
- •Выровненный вывод
- •Работа с другими типами данных
- •Модификаторы * u #
- •Спецификаторы формата
- •Ввод чисел
- •Ввод беззнаковых целых
- •Чтение отдельных символов с помощью scanf()
- •Чтение строк
- •Ввод адреса
- •Спецификатор %n
- •Использование множества сканирования
- •Пропуск нежелательных специальных символов
- •Обычные символы в управляющей строке
- •В scanf() следует передавать адреса
- •Модификаторы формата
- •Подавление ввода
- •Файловая система ansi с
- •Указатель на файл
- •Открытие файла
- •Запись символа
- •Чтение символа
- •Использование fopen(), getc(), putc() и fclose()
- •Использование feof()
- •Две расширенные функции: getw() и putw()
- •Работа со строками: fgets() и fputs()
- •Fseek() и произвольный доступ
- •Удаление файлов
- •Работа с консолью
- •Препроцессор и комментарии
- •Директивы условной компиляции
- •Использование defined
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Fseek() и произвольный доступ
Можно выполнять операции произвольного чтения и записи, используя систему буферизированного ввода/вывода, с помощью fseek(), устанавливающей текущую файловую позицию. Она имеет следующий прототип:
int fseek(FILE *fp long нисло_байт, int начало);
где fp - это указатель на файл, возвращенный fopen(), число_байт - это длинное целое, содержащее число байт от начала до позиции маркера, а начало - это одно из следующих макроопределений (определенных в stdio.h):
Макроопределение |
Смысл |
SEEK_SET SEEK_CUR SEEK_END |
Начало файла Текущая позиция Конец файла |
Макроопределения определены как целочисленные значения, причем SEEK_SET соответствует 0, SEEK_CUR - 1, a SEEK_END - 2. Следовательно, для перехода на число_байт от начала файла следует установить начало в SEEK_SET. Для перехода от текущей позиции надо использовать SEEK_CUR, а для перехода от конца файла - SEEK_END. Функция fsee() возвращает 0 в случае удачи или ненулевое значение в случае ошибки. Например, можно использовать следующий код для чтения 234-го байта файла test: int func1(void) { FILE *fp; if((fp=fopen("test", "rb")) == NULL){ printf("Cannot open file."); exit(1); } fseek(fp, 234L, O); return getc(fp); /* чтение одного символа в 234-й позиции */ } }
Другим примером, использующим функцию fseek(), является следующая программа dump, позволяющая просмотреть содержимое, как в ASCII, так и в шестнадцатиричных форматах. Можно смотреть на файл 128-байтными «секторами», причем двигаться можно в произвольном направлении. Для выхода из программы следует набрать -1, когда будет предложено ввести номер сектора. Обратим внимание на использование fread() для чтения файла. Если остается прочитать меньше чем SIZE байт, то число, передаваемое в display(), как раз и определяет, сколько символов необходимо вывести. (Надо помнить, что fread() возвращает число прочитанных элементов.) Введем программу в компьютер и основательно с ней разберемся: /* dump: простая дисковая утилита для просмотра, использующая fseek. */ #include <stdio.h> #include <ctype.h> #define SIZE 128 void display(int numread); char buf[SIZE]; void display(); int main(int argc, char *argv[]) { FILE *fp; int sector, numread; if(argc!=2) { printf("Usage: dump filename"); return 1; } if((fp=fopen(argv[1], "rb"))==NULL) { printf("Cannot open file."); return 1; } do { printf("Enter sector: "); scanf("%d", §or); if(sector >= 0) { if(fseek(fp, sector*SIZE, SEEK_SET)) { printf("seek error"); } if((numread=fread(buf, 1, SIZE, fp)) != SIZE) printf("EOF reached."); display(numread); } } while(sector>=0); return 0; }
/* вывод содержимого файла */ void display(int numread) { int i, j; for(i=0; i<numread/16; i++) { for (j=0; j<16; j++) printf("%3X", buf[i*16+j]); printf(" "); for(j=0; j<16; j++) { if(isprint(buf[i*16+j])) printf("%c", buf[i*16+j]); else printf("."); } printf("\n"); } }
Надо обратить внимание, что библиотечная функция isprint() используется для определения выводимых символов. Функция isprint() возвращает истину, если символ можно вывести, и ложь - если нельзя. Для ее использования необходимо подключить заголовочный файл ctype.h. Пример работы dump можно увидеть на рис.
Рисунок: Пример работы дисковой утилиты просмотра |
|
fprintf() и fscanf()
Помимо основных функций ввода/вывода, система буферизированного ввода/вывода содержит fprintf() и fscanf(). Данные функции ведут себя так же, как и printf() и scanf(), за тем исключением, что работают с дисковыми файлами. Они имеют следующие прототипы:
int fprintf(FILE *fp, const char *форматная_строка, ...);
int fscanf(FILE *fp, const char * форматная_строка, ...);
где fp - это указатель на файл, возвращаемый fopen(). Если не принимать во внимание, что они перенаправляют вывод в файл, то можно считать, что работа данных функций полностью идентична printf() и scanf() соответственно.
Для демонстрации использования данных функций следующая программа содержит в файле простой телефонный справочник. Можно ввести имена и номера или узнать, какой номер соответствует определенному имени.
/* простой телефонный справочник */ #include <conio.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> void add_num(void), lookup(void); char menu(void); int main(void) { char choice; do { choice = menu(); switch(choice) { case 'a': add_num(); break; case '1': lookup(); break; } } while (choice!='q'); return 0; }
/* вывод меню и получение запроса */ char menu(void) { char ch; do { printf("(A)dd, (L)ookup, or (Q)uit: "); ch = tolower(getche()); printf("\n"); } while(ch != 'q' && ch != 'a' && ch != '1'); return ch; }
/* добавление имени и номера в справочник */ void add_num(void) { FILE *fp; char name[80]; int a_code, exchg, num;
/* открытие для присоединения */ if((fp=fopen("phone", "a")) == NULL) { printf("Cannot open directory file."); exit(1); } printf("Enter name and number: "); fscanf(stdin, "%s%d%d%d", name, &a_code, &exchg, &num); fscanf(stdin, "%*c"); /* удаление возврата каретки из потока ввода */
/* запись в файл */ fprintf(fp,"%s %d %d %d\n", name, a_code, exchg, num); fclose(fp); }
/* поиск числа по имени */ void lookup(void) { FILE *fp; char name[80], name2[80]; int a_code, exchg, num;
/* открытие для чтения */ if((fp=fopen ("phone","r")) == NULL) { printf("Cannot open directory file."); exit(1); } printf("name? "); gets(name);
/* поиск числа */ while(!feof(fp)) { fscanf(fp,"%s%d%d%d", name2, &a_code, &exchg, &num); if (!strcmp(name, name2)) { printf("%s: (%d) %d-%d\n",name, a_code, exchg, num); break; } } fclose(fp); }
Введем и запустим данную программу. После введения нескольких имен и чисел просмотрим файл phone. Как и следовало ожидать, он будет иметь вид как и обычная информация, посылаемая на экран с помощью функции printf().
|
ЗАМЕТКА: Хотя fprintf() u fscanf() часто являются наиболее простым способом записи и чтения данных из файла, они далеко не всегда являются наиболее эффективным решением. Поскольку отформатированные ASCII-данные сохраняются так же, как они выглядят на экране (а не в двоичном представлении), появляются дополнительные расходы при каждом вызове. Если скорость работы программы или размер создаваемых файлов играют важную роль, то, возможно, лучше использовать fread() и fwrite() |
