- •Содержание
- •Как пользоваться данной книгой
- •Благодарности
- •Введение
- •Что вам даст эта книга
- •Программные средства
- •Глава 1
- •Компьютерная программа
- •Пройти два квартала на север; повернуть налево на 90 градусов; пройти 50 футов прямо; повернуть налево на 90 градусов; подняться на четыре ступеньки; открыть дверь и войти.
- •Языки программирования
- •Компиляторы
- •Интерпретатор
- •Скорость
- •Переносимость
- •Структурирование
- •Библиотеки функций
- •Необходимые пояснения
- •Что такое объектно-ориентированное программирование
- •Карточка члена клуба
- •Взять карточки
- •Клубная Карточка
- •Клубная карточка: Изменить адрес (Смит, Западная Авеню, 12)
- •Что Си может и чего не может
- •Этапы программирования
- •План программы
- •Текст программы
- •Компиляция программы
- •Компоновка программы
- •Тестирование программы
- •Изучение основ программирования
- •Что нужно, чтобы писать программы
- •Вопросы
- •Упражнения
- •Глава 2
- •Структура программы
- •Main() Функция, означающая начало программы— точку входа
- •(Прим.Перев.)
- •Прописные и строчные символы
- •Инструкция return
- •Использование комментариев
- •/*Эта программа выводит сообщение на экран*/ main()
- •/*Эта программа выводит сообщение на экран */ main()
- •/*Эта программа выводит сообщение на экран, она содержит инструкцию return(0) для совместимости с компиляторами, не имеющими автоматического возврата в систему
- •/*Эта программа выводит сообщение на экран, она содержит
- •//Эта программа выводит сообщение на экран
- •//Эта программа выводит сообщение на экран, она содержит
- •Понятие параметров
- •Puts("Привет");
- •Директива #include
- •Вопросы
- •Упражнения
- •Добро пожаловать в мой мир. Командовать парадом буду я.
- •Глава 3
- •Символьные данные
- •Целочисленные величины
- •Вещественные числа
- •Почему надо использовать целые числа?
- •Константы и переменные
- •Имена констант и переменных
- •Определение констант
- •#Define my_friend "Марина"
- •Определение переменных
- •Присваивание значения
- •Определение строковой переменной
- •#Define client "Кейт Тиммонс"
- •Типы данных и функции
- •Литералы
- •Проектирование программы
- •Упражнения
- •Глава 4
- •Функция puts()
- •Puts("Всем привет!");
- •#Define message "Всем привет"
- •Функция putchar()
- •Двойственность символьных переменных
- •Управляющие коды
- •Код «новая строка»
- •Код «табуляция»
- •Код «возврат каретки»
- •Код «возврат на шаг»
- •Код «перевод страницы»
- •Отображение специальных символов на экране монитора
- •Мы зовем ее "Наташа"
- •Puts("Мы зовем ее "Наташа"");
- •#Define message "Привет!" main()
- •Вывод чисел
- •Моими счастливыми номерами являются 12 и 21
- •Моими счастливыми номерами являются 21 и 12
- •17 Равно 11 в шестнадцатеричной и 21
- •Printf("Стоимость составляет %8.2f", amount);
- •Стоимость составляет 45.58
- •Printf("Стоимость составляет %2.2f", amount);
- •Стоимость составляет 45.58
- •Printf("Стоимость составляет %-8.2f
- •Стоимость составляет 45.58 в долларах сша
- •Printf("я позвонил, чтобы сказать %8s", message);
- •Я позвонил, чтобы сказать Привет
- •Выбор правильных средств вывода информации
- •Вам исполнилось 43 года.
- •Проектирование программы
- •(Прим.Перев.)
- •Puts("Пожалуйста, введите сумму полученного займа:");
- •Упражнения
- •Наименование товара: Гибкий диск Цена за 1 упаковку: 3.55
- •Внимание! Внимание! Внимание! Внимание! Нежелательное отклонение параметров среды.
- •Глава 5
- •Функция gets()
- •Пожалуйста, введите Ваше имя:
- •Пожалуйста, введите Ваше имя: Петр Иванов Подтвердите, Ваше имя: Петр Иванов
- •Функция getchar()
- •«Для продолжения нажмите Enter»
- •Printf("Для продолжения нажмите Enter"); getchar();
- •Оператор получения адреса &
- •Функция scanf()
- •Входной поток
- •Использование функции scanf()
- •Пожалуйста, введите целое число и нажмите Enter:
- •Выбор соответствующих средств ввода данных
- •Будьте осторожны при использовании scanf()
- •Неинициализированные переменные
- •Вопросы
- •Упражнения
- •Глава 6
- •Арифметические операторы
- •Для того чтобы дать 57 долларов сдачи, используйте: 2 банкнот(ы) достоинством 20 долларов
- •Типы данных и операторы
- •Выражения
- •Значение равно 24
- •Приоритет операторов и порядок вычислений
- •40 * Rate /* обычный недельный заработок */ hours - 40 /* сверхурочные часы */
- •Счетчики
- •Новое значение переменной равно старому значению плюс 1
- •Операторы инкремента
- •Первое значение переменной count равно 0
- •Printf("Второе значение переменной
- •Первое значение переменной count равно 0
- •Первое значение переменной count равно 0
- •Аккумуляторы
- •Присваивание начального значения
- •Остерегайтесь логических ошибок
- •Ищите образцы
- •Диагностические проблемы
- •Значение regular равно 400 значение extra равно -2 значение d_time равно 40
- •Вопросы
- •Глава 7
- •Как использовать функции
- •Puts("Сколько байтов в одном килобайте?"); puts("Для получения ответа нажмите Enter");
- •Переменные в функциях
- •Автоматические (локальные) переменные
- •Внешние (глобальные) переменные
- •Статические переменные
- •Значение autovar равно 0 значение statvar равно 0 значение autovar равно 0 значение statvar равно 0 значение autovar равно 0 значение statvar равно 0 значение autovar равно 0 значение statvar равно 0
- •Передача параметров
- •Puts("Привет!");
- •Фактических параметров. (Прим.Перев.)
- •Введите стоимость единицы товара: 100
- •Возвращаемые значения
- •Возврат значений типа float
- •Использование return() в функции main()
- •Использование макроопределений
- •#Define enter printf("Пожалуйста, введите число: ")
- •#Define enter printf("Пожалуйста, введите число: ") main()
- •#Define enter printf("Пожалуйста,
- •Проектирование программы
- •Автоматические или внешние переменные?
- •Неправильный ввод
- •Введите размер скидки (в виде десятичной дроби):
- •Вопросы
- •Упражнения
- •Глава 8
- •Условия
- •Составные инструкции
- •Дополненный Опросник
- •Вложенные инструкции if
- •Конструкция switch/case/default
- •Проектирование программы
- •Проверка правильности ввода
- •Вопросы
- •Упражнения
- •Глава 9
- •Цикл for;
- •Использование цикла for
- •Создание паузы в программе
- •Использование переменных
- •Вложенные циклы
- •Использование цикла do...While
- •Вложенные циклы do
- •Использование цикла while
- •Printf("Введите размер скидки: "); scanf("%f", &discount);
- •Проектирование программы
- •Использование флагов
- •Использование инструкции break
- •Вопросы
- •Упражнения
- •3. Цена Налог Итого
- •Глава 10
- •Массивы
- •Определение массива
- •Ввод значений в массив
- •Введите значение температуры #n
- •Работа с массивами
- •Просмотр массива
- •Поиск в массиве
- •Передача массива функции
- •Использование массивов
- •Сравнение двух строк
- •Слияние строк
- •Массивы строк
- •Вопросы
- •Упражнения
- •Глава 11
- •Использование структур
- •Определение структуры
- •Определение структурных переменных
- •Присвоение начального значения
- •Puts("Введите сведения о диске
- •Структуры и функции
- •Значение переменной tax равно 35
- •Указатели и функции
- •Вопросы
- •Упражнения
- •Глава 12
- •Что такое файловая структура
- •Указатель на файл
- •R Указывает на то, что будет выполняться
- •Как закрыть файл
- •Функции ввода и вывода
- •Работа с символами
- •Посимвольное чтение из файла
- •Работа со строками
- •Printf("Пожалуйста, введите имя: "); gets(name);
- •Форматированный ввод и вывод
- •Дискеты 1.120000 100
- •Дискеты 1.120000 100лента 7.340000 150картридж 75.000000 3
- •Дискеты 1.120000 Memoryexлента
- •Дискеты 1.120000 Memoryexлента
- •Чтение форматированных файлов
- •Текстовый и двоичный форматы
- •Двоичный формат
- •Печать данных
- •Инструкции
- •Проектирование программы
- •Вопросы
- •Упражнения
- •Глава 13
- •Прикладная программа
- •Глобальные определения
- •Добавление записей: функция addcd()
- •Удаление записи: функция delcd()
- •Printf("Введите название диска: "); gets(delname);
- •Редактирование данных: функция chcd()
- •Printf("Введите название диска: "); gets(disc.Name);
- •Вывод записи на экран: функция locate()
- •Нажмите Enter");
- •Печать записей: функция plist()
- •Приложение I
- •Глава 1
- •Глава 2
- •Добро пожаловать в мой мир.Командовать парадом буду я.
- •Глава 3
- •Для вещественных чисел:
- •Глава 4
- •Printf("%80s","Страница");
- •Наименование товара: Гибкий диск Цена за 1 упаковку: 3.55
- •Внимание! Внимание! Внимание! Внимание! Нежелательное отклонение параметров среды.
- •Глава 5
- •Переменная initial определена как символьная.
- •Глава 6
- •В программе используется переменная shipping, которая не была определена. Вторая инструкция scanf() оканчивается апострофом, вместо точки с запятой.
- •Глава 7
- •Puts("Это первое"); main(); return(0);
- •Собственная функция может помещаться только после функции main(), а не перед ней.
- •Puts("Это первое"); dothis();
- •Глава 8
- •В первой инструкции printf() литерал
- •Глава 9
- •Переменные row и column определены с типом float, но если вы хотите использовать их в цикле, они должны относиться к типу int.
- •Глава 10
- •Индексы всех элементов массива temps заключены в круглые скобки, вместо квадратных. Переменные high и low не определены. Переменная total определена,
- •Глава 11
- •Ко всем переменным, используемым в инструкциях ввода и вывода, обращение происходит без использования имени структурной переменной.
- •Глава 12
- •Файл заголовков называется stdio.H, а не stdio.C. Указатель на файл должен определяться со звездочкой перед именем: *fp. В цикле while
- •Приложение II
Дискеты 1.120000 100
лента 7.340000 150
картридж 75.000000 3
Если бы код «новая строка» не был записан на диск, текст выводился бы подряд, в одну строку на экране, и выглядел примерно так:
Дискеты 1.120000 100лента 7.340000 150картридж 75.000000 3
Заметьте, что при этом отсутствует пробел между числом, показывающим количество единиц одного това- ра, и наименованием следующего. Даже при таком способе записи можно без проблем осуществлять чте- ние из этого файла, так как компилятор в состоянии различить конец числового значения и начало стро- ки, но что произойдет, если последним значением для каждого наименования товара окажется строка с названием фирмы-производителя? Информация в файле будет выглядеть примерно таким образом:
Дискеты 1.120000 Memoryexлента
7.340000 Okaydataкартридж 75.000000 HP
и тогда при чтении данных из файла программа присоединит начало данных о следующем товаре к концу описания предыдущего. Например, данные о первом наименовании товара при этом выглядели бы так:
Дискеты 1.120000 Memoryexлента
Все выведенные на диск данные, даже значения типа int или float, хранятся в виде текстовых символов. Об этом мы будем говорить чуть позже.
Чтение форматированных файлов
Ввод информации из форматированного файла осуществляется с использованием функции fscanf(). Она работает аналогично функции scanf() за исключением того, что fscanf() осуществляет ввод данных не с клавиатуры, а из
файла. К несчастью, использование fscanf() имеет те же ограничения, что и применение scanf(). Эта функция не может читать строки, содержащие пробелы, и если данные во входном потоке не будут соот- ветствовать указателям в строке формата, она вернет ошибочные значения.
В Листинге 12.4 приводится текст программы, которая читает данные из форматированного файла, со- держащего сведения об инвентарной описи. Заметьте, что цикл while повторяется до тех пор, пока функ- ция fscanf() не возвратит значение EOF, которое будет свидетельствовать о достижении конца файла.
Листинг 12.4. Чтение форматированного текста из файла.
/*fscanf.c*/
#include "stdio.h" main()
{
FILE *fp; char name[20]; int quantity; float cost;
if ((fp = fopen("MYFILE", "r")) == NULL)
{
puts("Невозможно открыть файл"); exit();
}
while (fscanf(fp, "%s%f%d", name, &cost, &quantity) != EOF)
{
printf("Наименование товара:
%s\n", name);
printf("Цена:
%.2f\n", cost);
printf("Количество единиц:
%d\n", quantity);
}
fclose(fp);
}
Работа со структурами
Одним из способов преодолеть ограничения функции scanf() является объединение элементов данных в структуру с тем, чтобы впоследствии осуществлять ввод и вывод структур целиком. Структуру можно за- писать на диск с помощью функции fwrite() и прочитать из файла с помощью функции fread().
Синтаксис функции fwrite() такой: fwrite(&structure_variable, structure_size, number_of_structures, file_pointer);
На первый взгляд, эта инструкция выглядит несколько устрашающей, но на самом деле использовать ее очень легко:
&structure_variable— имя структурной переменной с оператором получения адреса, сообщающим компилятору стартовый адрес информации, которую мы хотим записать на диск;
structure_size— это количество символов в структуре; не обязательно подсчитывать его самому, для этого можно использовать библиотечную функцию sizeof(), записанную следующим образом:
sizeof(structure_variable)
которая автоматически определит размер указанной структуры;
number_of_structures— это целое число, определяющее количество структур, которые мы хотим записать в один прием; здесь всегда следует указывать число 1, если только вы не собираетесь создать массив структур и записать его одним большим блоком;
file_pointer— указатель на файл.
В качестве примера предположим, что вы хотите записать на диск сведения о своей коллекции компакт- дисков. Используя структуру CD, которую мы подробно разбирали в главе 11, пишем инструкцию:
Рис. 12.5. Синтаксис функции fwrite() в инструкции записи структуры CD
fwrite(&disc, sizeof(disc), 1, fp);
Выполнение этой инструкции иллюстрирует рис.12.5.
Текст программы, которая вводит данные в структуру CD, а затем сохраняет ее на диске, приведен в Лис- тинге12.5. Для ввода имени создаваемого файла используется функция gets(). Переменная, в которой хранится имя файла, используется функцией fopen() для того, чтобы открыть файл.
Информация о каждой структуре CD вводится с клавиатуры, после чего структура целиком записывается на диск.
Листинг 12.5. Запись структуры CD.
/*fwrite.c*/
#include "stdio.h" main()
{
FILE *fp; struct CD
{
char name[20];
char description[40]; char category[12]; float cost; int number;
} disc; char filename[25];
printf("Введите имя файла, который вы желаете создать: ");
gets(filename);
if ((fp = fopen(filename, "w")) == NULL)
{
printf("Невозможно открыть файл
%s\n", filename);
exit();
}
puts("Введите сведения о диске\n"); printf("Введите название диска: "); gets(disc.name);
while (strlen(disc.name) > 0)
{
printf("Введите описание: "); gets(disc.description); printf("Введите категорию: "); gets(disc.category); printf("Введите цену: "); scanf("%f", &disc.cost); printf("Введите номер ячейки: "); scanf("%d", &disc.number); fwrite(&disc, sizeof(disc), 1, fp); printf("Введите название: ");
gets(disc.name);
}
fclose(fp);
}
Чтение структур
Для того чтобы прочитать структуру целиком, используется функция fread(). Она имеет следующий син- таксис:
fread(&structure_variable, structure_size, number_of_structures, file_pointer);
За исключением имени функции эта инструкция полностью совпадает с записью функции fwrite(). Про- грамма, в которой из файла считывается структура CD, приведена в Листинге12.6. Для чтения данных ис- пользуется цикл while:
¶a++ae æepcue u+uru æɵuyye+a sneuwpo++ɵu usgawenacwæou "Books-shop".
Pacupocwpa+e+ue, upogaua, uepesauuca ga++on u+uru unu ee ¬acwen 3AMPE[EHª.
O æcex +apyue+uex upoca6a coo6yawa uo agpecy piracy@books-shop.com
while (fread(&disc, sizeof(disc), 1, fp) == 1)
Функция fread() возвращает значение, соответствующее количеству успешно прочитанных структур. Так как в аргументе функции мы указали, что читать следует по одной структуре, функция возвращает значе- ние 1. Цикл while будет выполняться до тех пор, пока считывание структур с диска проходит успешно.
Если чтение структуры становится невозможным, например потому, что достигнут конец файла, функция возвращает значение 0, и выполнение цикла прекращается.
Листинг 12.6. Чтение структуры CD с диска.
/*fread.c*/
#include "stdio.h" main()
{
FILE *fp; struct CD
{
char name[20];
char description[40]; char category[12]; float cost; int number;
} disc;
char filename[25];
printf("Введите имя файла, который желаете открыть: ");
gets(filename);
if ((fp = fopen(filename, "r")) == NULL)
{
printf("Невозможно открыть файл
%s\n", filename);
}
exit();
while (fread(&disc, sizeof(disc), 1, fp) == 1)
{
puts(disc.name); putchar('\n'); puts(disc.description); putchar('\n'); puts(disc.category); putchar('\n');
printf("%f", disc.cost);
putchar('\n'); printf("%d", disc.number);
}
fclose(fp);
}
В табл. 12.1 собраны все описанные способы ввода и вывода данных и показаны значения, которые воз- вращает каждая функция при невозможности продолжения чтения или записи данных.
Таблица 12.1. Функции ввода в файл и вывода из файла.
Чтение в массив
Во всех программах, приведенных до настоящего момента в качестве примера, выполнялось чтение дан- ных из файла и отображение вводимой информации на экране. Однако если считывать данные в пере- менные, с ними можно выполнять любые операции, например, использовать их для записи в массив.
В Листинге 12.7 приведен текст программы, осуществляющей чтение информации из файла, содержащего данные о коллекции компакт-дисков, в массив структур CD (предполагается, что их количество не пре- вышает20). Индекс используется для того, чтобы каждая считанная из файла структура сохранялась в от- дельном элементе массива disc. После того как очередная структура прочитана и выведена на экран, стоимость очередного диска добавляется к сумме, отражающей общую стоимость коллекции, а значение индекса и счетчика увеличивается за счет выполнения следующих инструкций:
total = total + disc[index].cost; index++;
count++;
Если бы нас интересовала только информация об общей стоимости и количестве экземпляров коллекции, можно было бы читать данные в структурную переменную, не используя массив, и просто подсчитывать значения переменных total и count. Однако если данные будут считаны в массив, вы сможете произволь- ным образом обращаться к структурам и печатать любую информацию.
Заметьте, что запрос о вводе имени файла в программе повторяется до тех пор, пока не будет введено имя файла, который действительно можно открыть.
Листинг 12.7. Чтение структуры в массив.
/*rarray.c*/
#include "stdio.h" main()
{
FILE *fp; struct CD
{
char name[20];
char description[40]; char category[12]; float cost; int number;
} disc[20];
int index, count; float total; count = 0;
total = 0;
char filename[25];
printf("Введите имя файла данных: "); gets(filename);
while ((fp = fopen(filename, "r")) == NULL)
{
printf("Невозможно открыть файл
%s\n", filename);
index = 0;
printf("Введите имя файла данных: "); gets(filename);
}
while (fread(&disc[index], sizeof(disc[index]), 1, fp) == 1)
{
puts(disc[index].name); putchar('\n'); puts(disc[index].description); putchar('\n'); puts(disc[index].category); putchar('\n'); printf("%f", disc[index].cost); putchar('\n'); printf("%d", disc[index].number); total = total + disc[index].cost; index++;
count++;
}
fclose(fp);
printf("Общая стоимость коллекции составляет %.2f\n", total);
printf("Коллекция содержит %.d дисков\n", count);
}
Дополнение файла новыми данными
Если файл, который уже существует на диске, открыть с режимом доступа "w", вся информация, имевшая- ся в нем на текущий момент, будет уничтожена. Для того чтобы добавить данные в уже существующий на
диске файл, следует открывать его с режимом доступа "a". Фактически, большинство компиляторов по- зволяет в одной программе и создавать файл, и добавлять в него данные. Если режим доступа "a" исполь- зуется для файла, которого нет на диске, он будет создан, а если файл существует, в него будет добавле- на новая информация.
Когда вы добавляете данные в файл, вы сами должны позаботиться о том, чтобы новые данные соответст- вовали формату уже имеющейся в файле информации. Например, вы можете открыть файл, содержащий некую последовательность символов, и записать туда структуру. Она действительно будет записана в файл, так как предполагается, что вы знаете, что делаете, но при следующих попытках прочитать инфор- мацию из этого файла вы получите ошибку выполнения или какие-нибудь непонятного вида данные.
