
- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор 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
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Использование feof()
Как утверждалось ранее, файловая система С может оперировать двоичными данными. Когда файл открыт для двоичного ввода, может быть прочитано целочисленное значение, равное EOF. В результате getc() будет отображать состояние наличия конца файла, хотя физический конец еще не достигнут. Для разрешения данной проблемы в С имеется функция feof(), используемая для определения конца файла при чтении двоичных данных. Она имеет следующий прототип: int feof(FILE *fp); где fp идентифицирует файл. Функция feof() возвращает не 0, если достигнут конец файла, в противном случае она возвращает 0. Следовательно, следующий код читает двоичный файл, пока не встретится метка конца файла: while(!feof(fp)) ch = getc(fp); Данный метод может применяться не только к двоичным, но и к текстовым файлам.
Следующая программа копирует файл любого типа. Следует обратить внимание, что файлы открываются в двоичном режиме, и feof() используется для проверки наличия конца файла: /* данная программа копирует один файл в другой */ #include <stdio.h> int main(int argc, char *argv[]) { FILE *in, out; char ch; if (argc!=3) { printf("You forgot to enter a filename."); return 1; } if( (in=fopen(argv[1] , "rb")) == NULL)} printf ("Cannot open source file."); return 1; } if((out=fopen(argv[ 2 ] , "wb")) == NULL) { printf ("Cannot open destination file."); return 1; } /* копирование файла */ while (!feof (in)) { сh = getc(in); if ( !feof(in)) putc(ch, out); } fclose(in); fclose(out); return 0; }
Две расширенные функции: getw() и putw()
В дополнение к функциям getc() и putc() Borland С++ поддерживает две дополнительные функции буферизированного ввода/вывода - getw() и putw(). (Хотя эти функции не определены в ANSI- стандарте, их можно найти в большинстве библиотек других компиляторов.) Они используются для чтения и записи чисел в файл. Эти функции работают точно так же, как и getc() и putc(), за тем исключением, что вместо чтения или записи одного символа они читают или записывают целые числа. Например, следующий фрагмент кода записывает целое число в файл, на который указывает fp:
putw(100, fp);
Работа со строками: fgets() и fputs()
Файловая система ввода/вывода С содержит две функции, которые могут читать или писать стро¬ки в поток - fgets() и fputs(). Они имеют следующие прототипы: int fputs(const char *str, FILE *fp); char *fgets(char *str, int длина, FILE *fp);
Функция fputs() во многом подобна puts(), за тем исключением, что она записывает строку в указанный поток. Функция fgets() читает строку из указанного потока, пока не встретится сим¬вол новой строки или не будет прочитано (длина - 1) символов. Если прочитан символ новой строки, то он станет частью строки (в противоположность gets()). В обоих случаях результирую¬щая строка завершается нулевым символом. Функция возвращает str в случае успеха и нулевой указатель - в случае ошибки. Можно использовать fgets() как альтернативу gets(). Чтобы сделать это, надо просто указать stdin как указатель на файл. Например, следующая про¬грамма читает до 79 символов, полученных из стандартного ввода: #include <stdio.h> int main(void) { char s[80]; printf("Enter a string: "); fgets(s, 80, stdin); printf ("Here is your string: %s", s); return 0; }
Преимущество использования fgets() над gets() состоит в том, что можно предотвратить перепол¬нение массива ввода. Массив может содержать символ новой строки.
fread() и fwrite()
Файловая система ANSI С предоставляет две функции, позволяющие читать и писать блоки дан¬ных - fread() и fwrite(). Они имеют следующие прототипы: size_t fread(void *буфер, size_t число_байту size_t объем, FILE *fp); size_t fwrite(const void *буфер, size_t число_байт, size_t объем, FILE *fp); В случае fread() буфер - это указатель на область памяти, которая получает данные из файла. В случае fwrite() буфер - это указатель на информацию, записываемую в файл. Длина каждого элемента в байтах определяется в число_байт. Аргумент объем определяет, сколько элементов (каж¬дый длиной число_байт) будет прочитано или записано. Наконец, fp - это файловый указатель на ранее открытый поток.
Функция fread() возвращает число прочитанных элементов. Данное значение может быть мень¬ше, чем объем, если был достигнут конец файла или произошла ошибка. Функция fwrite() возвра¬щает число записанных элементов. Данное значение равно объем, если не возникла ошибка.
Если файл был открыт для двоичных данных, то fread() и fwrite() могут читать и писать любой тип информации. Например, следующая программа записывает float в файл: /* запись вещественных чисел в файл */ #include <stdio.h> int main(void) { FILE *fp; float f = 12.23; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file."); return 1; } fwrite(&f, sizeof (float), 1, fp); fclose (fp); return 0; } Как иллюстрирует данная программа, буфер может быть (а чаще всего это так и есть) простой переменной.
Одно из наиболее полезных применений fread() и fwrite() - это чтение и запись блоков данных типа массивов или структур. Например, следующий фрагмент записывает содержимое массива ве¬щественных чисел balance в файл balance, используя один оператор fwrite(). Далее она читает мас¬сив, используя один оператор fread(), и выводит его содержимое. #include <stdio.h> int main(void) { register int i; FILE *fp; float balance[100]; /* открытие на запись */ if((fp=fopen("balance", "wb"))==NULL) { printf("Cannot open file."); return 1; } for(i=0; i<100; i++) balance[i] = (float) i; /* сохранение за раз всего массива balance */ fwrite(balance, sizeof balance, 1, fp) ; fclose(fp); /* обнуление массива */ for(i=0; i<100; i++) balance[i] = 0.0; /* открытие для чтения */ if((fp=fopen("balance","rb"))==NULL) { printf("cannot open file"); return 1; } /* чтение за раз всего массива balance */ fread(balance, sizeof balance, 1, fp); /* вывод содержимого массива */ for(i=0; i<100; i++) printf("%f ", balance [i]); fclose(fp); return 0; }
Использование fread() и fwrite() для чтения или записи сложных данных более эффективно, чем использование повторяющихся вызовов getc() и putc().