Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В листинге 12.9 представлена модифицированная версия.
Листинг 12.9. Программа s_and г.с
504 глава 12
Обратите внимание, что next — это статическая переменная с областью видимости в пределах файла и внутренним связыванием. Это означает, что она может использоваться как randl(), так и srandl(), но не функциями в других файлах. Для тестирования этих функций применяйте драйвер из листинга 12.10.
Листинг 12.10. Драйвер г drivel. с
Снова скомпилируйте два файла и запустите программу:
Введите желаемое начальное число.
1
16838
5758
10113
17515
31051
Введите следующее начальное число (q для завершения):
513
20067
23475
8955
20841
15324
Введите следующее начальное число (q для завершения) :
q
Программа завершена.
Использование значения 1 для seed выдает те же псевдослучайные числа, что и ранее, но значение 3 для seed обеспечивает выдачу новых результатов.
НА ЗАМЕТКУ! Автоматическая переустановка начального значения
Если ваша реализация С предоставляет доступ к какой-то меняющейся величине, такой как показание системных часов, ее можно применять (возможно, с усечением) для инициализации начального числа.
Классы хранения, связывание и управление памятью 505
s Например, в ANSI С имеется функция time(), которая возвращает системное время, к Единицы измерения времени зависят от системы, однако здесь важно то, что возвращаемое значение имеет арифметический тип и меняется с течением времени. Точный тип может отличаться от системы к системе, и он получил метку time t, но можно воспользоваться приведением. Вот как выглядит базовый подход:
#include /* прототип ANSI для timet) */
srandl((unsigned int) time(O)); /* инициализация начального числа */
В общем time() принимает аргумент, который является адресом объекта типа time_t. В данном случае значение времени также сохраняется по этому адресу. В качестве аргумента можно передать нулевой указатель (0), тогда значение будет передаваться только с помощью механизма возврата из функции.
Вы можете применять тот же самый метод с функциями srand() и rand() из ANSI С. Если вы планируете использовать эти функции, включите заголовочный файл stdlib.h. Фактически теперь, когда вы увидели, каким образом в srandl() и randl() применяется статическая переменная с внутренним связыванием, вы можете также воспользоваться версиями, которые поставляет компилятор. Мы сделаем это в следующем примере.
Игра в кости
Мы собираемся эмулировать весьма популярное действие со случайным характером — игру в кости. В наиболее распространенной форме этой игры участвуют две шестигранных кости, но существуют и другие разновидности. Во многих азартных играх применяются все пять геометрически возможных костей — с 4, 6, 8, 12 и 20 гранями. Талантливые древние греки доказали, что лишь у пяти правильных тел все грани имеют одинаковую форму и размер, и эти тела являются основой для всего разнообразия костей. Можно было бы сделать кости с другим числом граней, но не все грани имели бы одинаковый размер, что не способствовало бы уравниванию шансов их выпадения.
Компьютерные вычисления не ограничиваются этими геометрическими соображениями, так что мы можем придумать электронную игральную кость, которая имеет любое количество граней. Давайте начнем с варианта с шестью гранями, после чего займемся обобщением. Нам необходимо случайное значение от 1 до 6. Тем не менее, функция rand() генерирует целое число из диапазона от 0 до RAND_MAX; значение RAND_MAX определено в stdlib.h. Обычно это INT_MAX. Следовательно, понадобятся провести ряд настроек. Ниже представлен один из подходов.
1. Получить случайное число но модулю 6. Это даст целое число из диапазона от 0 до 5.
2. Добавить к нему 1. Новое число находится в диапазоне от 1 до 6.
3. Для обобщения этого алгоритма просто замените 6 в первом шаге количеством граней.
Описанные идеи реализованы в следующем коде:
#include /* для rand() */ int rollem(int sides)
{
int roll;
roll = rand() % sides + 1;
return roll;
}
506 глава 12
Давайте немного расширим возможности и сделаем так, чтобы функция позволяла бросать произвольное количество костей и возвращала общее число очков. Это реализовано в листинге 12.11.
Листинг 12.11. Файл dicerol1.c
В этом файле предпринято несколько действий. Во-первых, rollem() сделана функцией, закрытой для файла. Она выступает в качестве вспомогательной функции для roll_n_dice(). Во-вторых, для демонстрации работы внешнего связывания в файле объявлена внешняя переменная по имени roll count, которая отслуживает количество вызовов функции rollem(). Пример несколько надуман, но он показывает, как работают внешние переменные.
В-третьих, файл содержит следующий оператор:
#include "diceroll.h"
В случае использования стандартных библиотечных функций, таких как rand(), вы включаете стандартный заголовочный файл (stdlib.h для rand()) вместо объявления функции. Причина в том, что такой заголовочный файл уже содержит корректное объявление. Мы эмулируем этот подход, предоставляя заголовочный файл diceroll.h для применения функции roll_n_dice(). Заключение имени файла в двойные кавычки, а не в угловые скобки, указывает компилятору на необходимость
Классы хранения, связывание и управление памятью 507
поиска этого файла локально, а не в стандартных местоположениях, которые используются для хранения стандартных заголовочных файлов. Смысл выражения “поиска локально” зависит от реализации. Распространенные интерпретации предполагают помещение заголовочного файла в тот же каталог или папку, где находится исходный код или файл проекта (если ваш компилятор имеет делос ним). Содержимое заголовочного файла приведено в листинге 12.12.
Листинг 12.12. Файл diceroll.li
Данный заголовочный файл содержит прототипы функций и объявление extern. Поскольку dicer oil. с включает этот заголовочный файл, diceroll.c в действительности содержит два объявления переменной roll_count:
extern int roll_count; //из заголовочного файла
int roll_count =0; //из файла исходного кода
Можно иметь только одно определяющее объявление переменной. Однако объявление с ключевым словом extern является ссылочным, и таких объявлений может быть столько, сколько пожелаете.
Программа, в которой применяется функция roll_n_dice(), должна включать указанный заголовочный файл. Это не только предоставляет прототип функции roll_n_dice(), но также делает доступной переменную roll count в программе. Все сказанное иллюстрируется в листинге 12.13.
Читать дальшеИнтервал:
Закладка: