- •А. Нейбауэр.
- •Глава 1. Основы программирования 11
- •Глава 3. Переменные и константы 39
- •Глава 6. Операторы 103
- •Глава 13. Как собрать все вместе 253
- •Благодарности
- •Введение
- •Что вам даст эта книга
- •Программные средства
- •Глава 1. Основы программирования
- •Компьютерная программа
- •Языки программирования
- •Компиляторы
- •Интерпретатор
- •Скорость
- •Переносимость
- •Структурирование
- •Библиотеки функций
- •Необходимые пояснения
- •Что такое объектно-ориентированное программирование
- •Что Си может и чего не может
- •Этапы программирования
- •План программы
- •Текст программы
- •Компиляция программы
- •Компоновка программы
- •Тестирование программы
- •Изучение основ программирования
- •Что нужно, чтобы писать программы
- •Структура программы
- •Прописные и строчные символы
- •Инструкция return
- •Использование комментариев
- •Понятие параметров
- •Директива #include
- •Проектирование программы
- •Глава 3. Переменные и константы
- •Символьные данные
- •Целочисленные величины
- •Вещественные числа
- •Почему надо использовать целые числа?
- •Константы и переменные
- •Имена констант и переменных
- •Определение констант
- •Почему используют константы?
- •Определение переменных
- •Присваивание значения
- •Определение строковой переменной
- •Типы данных и функции
- •Литералы
- •Проектирование программы
- •Функция puts()
- •Функция putchar()
- •Двойственность символьных переменных
- •Управляющие коды
- •Код «новая строка»
- •Код «табуляция»
- •Код «возврат каретки»
- •Код «возврат на шаг»
- •Код «перевод страницы»
- •Отображение специальных символов на экране монитора
- •Многогранная функция printf()
- •Вывод чисел
- •Перевод строки
- •Преобразование типов данных
- •Форматированный вывод
- •Выбор правильных средств вывода информации
- •Проектирование программы
- •Функция gets()
- •Функция getchar()
- •«Для продолжения нажмите Enter»
- •Оператор получения адреса &
- •Функция scanf()
- •Входной поток
- •Использование функции scanf()
- •Выбор соответствующих средств ввода данных
- •Будьте осторожны при использовании scanf()
- •Неинициализированные переменные
- •Используемые алгоритмы ввода
- •Глава 6. Операторы
- •Арифметические операторы
- •Деление нацело
- •Типыданныхи операторы
- •Выражения
- •Приоритет операторов и порядок вычислений
- •Используемые алгоритмы обработки данных
- •Счетчики
- •Операторы инкремента
- •Аккумуляторы
- •Операторы присваивания
- •Присваивание начального значения
- •Проектирование программы
- •Остерегайтесь логических ошибок
- •Ищите образцы
- •Диагностические проблемы
- •Глава 7. Для чего нужны функции
- •Как использовать функции
- •Переменные в функциях
- •Автоматические (локальные) переменные
- •Внешние (глобальные) переменные
- •Статические переменные
- •Передача параметров
- •Возвращаемые значения
- •Возврат значений типа float
- •Использование return() в функции main()
- •Использование макроопределений
- •Проектирование программы
- •Автоматические или внешние переменные?
- •Неправильный ввод
- •Глава 8. Позвольте компьютеру принимать решения
- •Условия
- •Составные инструкции
- •Конструкция if...Else
- •Дополненный Опросник
- •Логические операторы
- •Вложенные инструкции if
- •Конструкция switch/case/default
- •Проверка чисел с плавающей точкой и строк
- •Проектирование программы
- •Проверка правильности ввода
- •Глава 9. Циклы
- •Использование цикла for
- •Создание паузы в программе
- •Составные инструкции
- •Использование переменных
- •Вложенные циклы
- •Использование цикла do...While
- •Вложенные циклы do
- •Использование цикла while
- •Комбинирование циклов разных типов
- •Проектирование программы
- •Использование флагов
- •Использование инструкции break
- •Глава 10. Массивы и строки
- •Массивы
- •Определение массива
- •Ввод значений в массив
- •Работа с массивами
- •Просмотр массива
- •Поиск в массиве
- •Передача массива функции
- •Использование массивов
- •Сравнение двух строк
- •Определение длины строки
- •Присваивание строк
- •Слияние строк
- •Массивы строк
- •Проектирование программы
- •Глава 11. Структуры и указатели
- •Использование структур
- •Определение структуры
- •Определение структурных переменных
- •Присвоение начального значения
- •Использование структуры
- •Массивы структур
- •Структуры и функции
- •Указатели
- •Указатели и функции
- •Глава 12. Вывод на диск и принтер
- •Что такое файловая структура
- •Указатель на файл
- •Как открыть файл
- •Как избежать ошибок выполнения
- •Как закрыть файл
- •Функции ввода и вывода
- •Работа с символами
- •Посимвольное чтение из файла
- •Работа со строками
- •Чтение строк
- •Форматированный ввод и вывод
- •Чтение форматированных файлов
- •Работа со структурами
- •Чтение структур
- •Чтение в массив
- •Дополнение файла новыми данными
- •Текстовый и двоичный форматы
- •Двоичный формат
- •Печать данных
- •Проектирование программы
- •Глава 13. Как собрать все вместе
- •Прикладная программа
- •Глобальные определения
- •Функция main()
- •Добавление записей: функция addcd()
- •Удаление записи: функция delcd()
- •Редактирование данных: функция chcd()
- •Изменение номера ячейки: функция chloc()
- •Вывод записи на экран: функция locate()
- •Печать записей: функция plist()
- •Сортировка записей: функция sort()
- •Приложение I Ответы и решения Глава 1. Основы программирования.
- •Глава 3. Переменные и константы.
- •Глава 6. Операторы.
- •Глава 7. Для чего нужны функции.
- •Глава 8. Позвольте компьютеру принимать решения.
- •Глава 9. Циклы.
- •Глава 10. Массивы и строки.
- •Глава 11. Струтуры и указатели.
- •Глава 12. Вывод на диск и принтер.
- •Приложение II Прикладная программа
Указатели и функции
Без указателя мы должны передавать аргумент функции по значению. Это значит, что значение вызывающего параметра передается получающему параметру. Копируемые значения занимают отдельные области памяти, и изменение значения получающего параметра не приводит к изменению значения передающего параметра.
При передаче параметра по его адресу с помощью указателя мы не делаем дублирующих копий. Напротив, мы создаем вторую переменную, которая указывает на ту же область памяти. Таким образом, если мы изменяем значение переменной по указателю, то изменяем также и значение передающей переменной.
В программе, приведенной в Листинге 11.5, вводится значение строки и символа. Затем подсчитывается, сколько раз символ встречается в строке, и определяется позиция первого появления символа в строке.
Листинг 11.5. Программа, в которой используется указатель для возврата значений.
/*letcount.c*/
main()
{
char name[20], letter;
int number, start;
puts("Введите имя\n");
gets(name);
printf("Введите символ");
letter = getchar();
countlet(name, letter, &number, &start);
printf("\nСимвол %c встречается в имени %s %d раз\n", letter, name, number);
printf("Первый раз символ встречается в %d позиции", start);
}
countlet(ndplume, alpha, count, first)
char ndplume[], alpha;
int *count, *first;
{
int index, flag;
*count = 0;
index = 0;
flag = 0;
*first = 0;
while (ndplume[index != '\0')
{
if (ndplume[index] == alpha)
{
*count = *count+1;
if (flag == 0)
{
*first = index+1;
flag = 1;
}
}
index++;
}
}
После ввода строки и символа мы передаем функции countlet() четыре переменных: строку, символ и адреса переменных count и start, определенных с помощью оператора получения адреса.
Функция присваивает адреса получающим указателям: адрес переменной number хранится в *count, а адрес переменной start содержится в *first (рис.11.12).
Рис. 11.12. Передача адресов функции
Рис. 11.13. Фигурные скобки отмечают блоки инструкций
Переменные инициализируются путем присваивания нулевого значения, а затем начинает выполняться цикл while:
while (ndplum[index] != '\0')
Цикл проверяет каждый символ в строке и продолжает проверку до тех пор, пока не встретит нулевой символ. Как только выясняется, что очередной символ является нулевым, выполнение цикла прекращается.
Положение фигурных скобок внутри цикла while является весьма существенным, так как одна инструкция if целиком вложена в другую (рис.11.13). Первое из условий if проверяет, является ли очередной встреченный символ тем, количество повторений которого мы подсчитываем. Если это так, значение счетчика, который в данном случае является указателем, увеличивается на единицу:
*count = *count + 1;
Это приводит к тому, что происходит увеличение на единицу значения, содержащегося в области памяти, адрес которой является значением указателя. Так как указатель содержит адрес переменной number, значение number увеличивается на 1, хотя эта переменная является локальной, определенной внутри функции main(). Обратите внимание, что в данном случае нельзя использовать синтаксис
*count++;
так как это приведет к изменению значения адреса, реально являющегося значением указателя, а не содержимого соответствующего элемента памяти*.
Второе условие if проверяет значение переменной flag. Если оно равно нулю, значит указанный символ встречен в строке впервые. При этом указателю *first присваивается значение, соответствующее номеру символа в строке плюс единица. Добавляя единицу к индексу, мы указываем положение символа в строке, начиная отсчет с 1 (такой способ является наиболее привычным для большинства людей). После этого значение переменной flag меняется на 1, так что номер позиции первого встреченного в строке символа уже не будет меняться при обнаружении следующих символов.
После выполнения условия if значение индекса увеличивается, в результате чего при следующем прохождении цикла будет проверяться следующий символ строки. Весьма существенно, чтобы инструкция index++; помещалась после закрывающей фигурной скобки внешней инструкции if, но перед двумя заключительными закрывающими скобками, одна из которых отмечает конец инструкции while, а вторая завершает функцию. Если указанная инструкция будет помещена в каком-нибудь другом месте, функция не сможет успешно работать.
После завершения выполнения функции countlet() управление передается назад в main(), где осуществляется вывод информации, включающий вывод строки, символа, количества появлений символа в строке и первого случая появления символа в строке.
Обратите внимание на то, что для возврата значения функция не использует инструкцию return. Вместо этого значения переменных number и start присваиваются через указатели. Другими словами, в программе возврат значений осуществляется путем использования указателей в качестве аргументов функции.
Можно написать ту же программу без использования указателей, определив переменные number и start как глобальные. Тогда и функция main(), и функция countlet() смогут обращаться к ним без передачи аргумента, однако использование указателей расширяет возможности контроля за работой программы. Переменные остаются локальными, но к ним можно обращаться и менять их значения путем передачи их адресов.
Использование указателей совершенно необходимо при работе с дисковыми файлами и выводе информации на принтер, что и будет являться предметом нашего разговора в главе 12.
______________________________
* В этом случае можно использовать инструкцию (*count)++;.(Прим.перев.)
<> |
Вопросы |
|
<> |
Упражнения |
main() { struct CD { char description[40]; char category[12]; char name[20]; float cost; int number; } disc; puts("Введите сведения о диске"); printf("Введите название: "); gets(name); printf("Введите описание: "); gets(description); printf("Введите категорию: "); gets(category); printf("Введите цену: "); scanf("%f", &cost); printf("Введите номер ячейки: "); scanf("%d", &number); puts("Введена следующая информация о диске: "); printf("Название: %s\n", name); printf("Описание: %s\n", description); printf("Категория: %s\n", category); printf("Цена: %6.2f\n", cost); printf("Номер п/п: %d\n", number); } |