- •Содержание
- •Как пользоваться данной книгой
- •Благодарности
- •Введение
- •Что вам даст эта книга
- •Программные средства
- •Глава 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
Puts("Введите сведения о диске
printf("Введите название: "); gets(disc[index].name); printf("Введите описание: "); gets(disc[index].description); printf("Введите категорию: "); gets(disc[index].category); printf("Введите цену: "); scanf("%f", &dics[index].cost); printf("Введите номер ячейки: "); scanf("%d", &disc[index].number); index++;
if(index < 10)
{
printf("Желаете ввести
данные о следующем диске? Да -Y, нет -N");
scanf("%C", &flag);
}
}
while (index < 10 && (flag == 'Y' || flag == 'y')); puts("Название Номер п/п"); for (repeat = 0; repeat < index; repeat++)
disc[repeat].number);
}
printf("%s %d\n", disc[repeat].name,
Рис. 11.7. Массив структур
Определение массива, включающего 10 элементов disc, является частью определения структуры:
} disc[10];
Переменная flag ведена для того, чтобы пользователь мог указать, хочет ли он продолжить ввод инфор- мации, если заполнено меньше 10«карточек». Цикл do обеспечивает ввод элементов массива: пять пунк- тов (членов структуры) для каждого элемента массива (регистрационной карточки в картотеке коллек- ции). Переменная index используется как индекс в процессе создания картотеки.
После ввода значений каждого элемента массива, программа спрашивает пользователя, хочет ли он за- полнить следующую карточку. После ввода значений всех 10элементов массива запрос больше не предъ- является.
В цикле do используется следующее условие:
while (index < 10 && (flag == 'Y' || flag == 'y'));
Логический оператор И указывает на то, что оба условия должны выполняться одновременно: значение переменной index должно быть меньше десяти, и переменная flag должна иметь значение 'Y' или 'y'. Если бы в условии не были поставлены внутренние скобки, компилятор Си скомбинировал бы первые два усло- вия и трактовал всю инструкцию как условие ИЛИ (рис.11.8). И если в
Рис. 11.8. Интерпретация условия при отсутствии внутренних круглых скобок
этом случае переменная flag примет значение 'y', цикл будет повторяться и после ввода значений всех элементов.
Когда будут введены данные последнего элемента массива (карточки), значение переменной index ока- жется на единицу больше количества элементов массива. Эта переменная в дальнейшем используется в
цикле for, в котором на дисплей выводится информация о содержании компакт-дисков и их местонахож- дении.
Обратите внимание на то, что все обращения к членам структуры включают имя переменной c указанием индекса массива.
Структуры и функции
В исходном K&R-стандарте языка Си использование структур ограничено. Структуры могут передаваться в качестве аргументов только с использованием указателей, о которых мы будем говорить дальше в этой главе. Кроме того, отсутствует возможность прямого присваивания одной структуры другой, например, следующим образом:
cdrom = disc;
В современных компиляторах Си и Си++ такая возможность существует. Теперь можно непосредственно присваивать одну структурную переменную другой.
Большинство компиляторов Си++ и компиляторы Си, поддерживающие стандарт ANSI, позволяют переда- вать и возвращать структуру целиком. В Листинге11.3 продемонстрировано, как можно передать структу- ру функции. Значения членов структуры вводятся в main(), затем вся структура передается функции putdisc() для вывода. При вызове функции используется структурная переменная disc:
putdisc(disc);
Таким образом, структура целиком передается функции. Функция содержит переменную (формальный ар- гумент), которая будет получать передаваемую структуру. Получающая переменная определяется с тем же типом структуры:
putdisc(disk) struct CD disk;
Теперь функция может использовать отдельную структурную переменную с именем disk, которая содер- жит передаваемые члены структуры disc. Внутри функции обращение к членам структуры происходит с использованием структурной переменной disk, то есть имени получающей переменной.
Листинг 11.3. Передача структуры.
/*CD3.c*/ struct CD
main()
{
char name[20];
char description[40]; char category[12]; float cost; int number;
} disc;
{
puts("Введите сведения о диске\n\n"); printf("Введите название: "); gets(disc.name); printf("Введите описание: "); gets(disc.description); printf("Введите категорию: "); gets(disc.category); printf("Введите цену: ");
scanf("%f", &dics.cost); printf("Введите номер ячейки: "); scanf("%d", &disc.number);
putdisc(disc);
}
putdisc(disk) struct CD disk;
{
puts("Введена следующая информация о диске:\n\n"); printf("Название: %s\n", disc.name); printf("Описание: %s\n", disc.description); printf("Категория: %s\n", disc.category);
printf("Цена: %6.2f\n", disc.cost); printf("Номер п/п: %d\n", disc.number);
}
В Листинге 11.4 демонстрируется, как функция возвращает структуру. Члены структуры вводятся в функ- ции getdisc(), а затем передаются назад в main() с помощью инструкции
return(inputdisc);
Обратите внимание, что тип записи структуры (CD) используется и в определении функции, и в определе- нии переменных функции getdisc(). Это вызвано тем, что при возврате переменных, отличных от типов int или char, тип переменной следует указать в определении функции. Типом возвращаемой переменной в данном случае является структура CD, так что функция определяется следующим образом:
struct CD getdisc();
Структура, используемая в функции, также относится к типу CD, поэтому она определяется как:
struct CD inputdisc;
Обратите также внимание на то, что функция getdisc() определяется как глобальная, вместе со структур- ной переменной disc. Такой тип определения требуется в тех случаях, когда функция возвращает структу- ру.
Листинг 11.4. Возвращение структуры.
/*CD4.c*/ struct CD
main()
{
char name[20];
char description[40]; char category[12]; float cost; int number;
} disc, getdisc();
{
disc = getdisc();
puts("Введена следующая информация о диске:\n\n"); printf("Название: %s\n", disc.name); printf("Описание: %s\n", disc.description); printf("Категория: %s\n", disc.category);
printf("Цена: %6.2f\n", disc.cost); printf("Номер п/п: %d\n", disc.number);
}
struct CD getdisc()
{
struct CD inputdisc;
puts("Введите сведения о диске\n\n"); printf("Введите название: "); gets(inputdisc.name); printf("Введите описание: "); gets(inputdisc.description); printf("Введите категорию: "); gets(inputdisc.category); printf("Введите цену: ");
scanf("%f", &inputdiscdics.cost); printf("Введите номер ячейки: "); scanf("%d", &inputdisc.number); return(inputdisc);
}
Указатели
В то время как функции можно передавать столько аргументов, сколько требуется (в том числе и структу- ры), с помощью инструкции return() возвращается только один параметр. Иными словами, функция может вернуть вызывающей процедуре только одно значение. В качестве альтернативы можно использовать глобальные переменные, однако в этом случае зачастую теряется контроль над программой и затрудняет- ся поиск ошибок. Когда возникает необходимость передать назад больше одного значения, можно исполь- зовать указатели.
К переменной можно обратиться одним из двух способов. Используя имя переменной, вы обращаетесь к значению переменной, которое хранится в памяти. Используя оператор получения адреса (&), вы обра- щаетесь к тому адресу в памяти, где хранится значение переменной.
Когда вы используете оператор присваивания
tax = 35;
вы, тем самым, вносите в элементы памяти некое значение. По адресу, соответствующему области памяти, отведенной для переменной tax, будет содержаться значение 35. Можно вывести на дисплей адрес эле- мента памяти переменной, если использовать оператор получения адреса. Инструкция
printf("%d", &tax);
отобразит адрес, по которому хранится значение переменной tax, но не само значение, присвоенное пе- ременной и хранящееся в элементах памяти по этому адресу. Однако оператор получения адреса вместе с именем переменной (&tax) может быть использован только в выражении. Он не является переменной, и поэтому инструкция типа
&tax = 25;
будет ошибочной.
Указателем называется переменная, которая содержит значение адреса элемента памяти, где хранится значение другой переменной. Если значение переменной tax хранится в элементе, расположенном по ад- ресу 21260, то и указатель на переменную tax будет иметь значение 21260*.
Чтобы создать указатель, используйте синтаксис, показанный на рис.11.9. Начать следует с определения типа данных, которые хранятся в элементах памяти, определяемых указателем. Символ «звездочка» гово- рит компилятору, что вы создаете указатель. В конце указывается имя переменной. Например, инструкция
int *taxptr;
создаст переменную типа указатель (об этом говорит звездочка перед именем) с именем taxptr, которая будет содержать адрес некой целочисленной переменной. Инструкция
float *net;
Рис. 11.9. Определение указателя
создаст указатель с именем net, который будет содержать адрес переменной типа float.
Если переменная типа указатель определена, она должна на что-то указывать. Для этого следует присво- ить указателю значение в виде адреса соответствующей переменной:
taxptr = &tax;
В этих инструкциях мы помещаем адрес, по которому содержится значение переменной tax, в переменную taxptr (рис.11.10). Если значение переменной tax хранится по адресу 21260, переменная taxptr получит значение 21260.
* Здесь имеется в виду только смещение переменной относительно начала сегмента данных (при работе в больших моделях памяти). Чтобы отобразить на экране полный адрес, нужно воспользоваться указателем формата "%p", а не "%d", как в приведенном примере. (Прим.перев.)
Рис. 11.10. Присваивание адреса указателю
В качестве примера рассмотрим программу:
main()
{
int *taxptr; int tax;
taxptr = &tax; tax = 35;
printf("Значение переменной tax равно %d\n", tax); printf("Указатель переменной tax
имеет значение %d\n", taxptr);
}
Эта программа выведет на дисплей сообщения:
