Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Листинг 12.13. Файл manydice.c
Глава 12
Скомпилируйте файл с кодом из листинга 12.13 вместе с файлом, содержащим код из листинга 12.11. Для простоты поместите файлы с исходным кодом из листингов 12.11, 12.12 и 12.13 в одну и ту же папку или каталог. Запустите результирующую программу. Вывод должен иметь примерно такой вид:
Введите количество граней кости или 0 для завершения программы.
6
Сколько костей?
2
Вы бросали 12 раз(а), используя 2 кости с 6 гранями.
Сколько граней? Для прекращения введите 0.
6
Сколько костей?
2
Вы бросали 4 раз(а), используя 2 кости с 6 гранями.
Сколько граней? Для прекращения введите 0.
6
Сколько костей?
2
Вы бросали 5 раз (а), используя 2 кости с 6 гранями.
Сколько граней? Для прекращения введите 0.
О
Функция rollemO была вызвана 6 раз(а) .
Пусть удача не покидает вас!
Из-за того, что в программе используется функция srand() для рандомизации начального случайного числа, скорее всего, вы не получите один и тот же вывод при том же самом входном значении. Обратите внимание, что функция main() в manydice.c имеет доступ к переменной roll_count, определенной в diceroll.c.
Внешний цикл while может прекратиться по трем причинам: значение sides оказывается меньше 1, введенное значение не соответствует по типу (scanf() возвращает 0) или встретился конец файла (scanf() возвращает EOF). При чтении количества костей появление конца файла обрабатывается иначе, чем ситуация с несоответствием типа; в первом случае происходит выход из цикла while, а во втором инициирует ся новая итерация цикла.
Функцию roll n dice() можно применять многими способами. В случае значения sides, равного 2, программа эмулирует процесс бросания монеты, при котором выпадение орла обозначается 2, а рещки — 1 (или, если хотите, то наоборот). Вы можете легко модифицировать программу так, чтобы она показывала отдельные результаты и сумму, или построить эмулятор игры в кости. Если требуется большое коли-
Классы хранения, связывание и управление памятью 509
чество бросаний, как в некоторых ролевых играх, несложно изменить программу для получения примерного такого вывода:
Введите количество бросаний или q для завершения.
16
Сколько граней и сколько костей?
6 3
Имеем 18 бросаний 3 костей с 6 гранями.
12 10 6 9 8 14 8 15 9 14 12 17 11 7 10
13 8 14
Введите количество бросаний или q для завершения.
q
Функции randl() и rand() (но не rollem()) могут также использоваться для создания программы, в которой компьютер выбирает число, а вы его отгадываете. Попробуйте написать ее самостоятельно.
Выделенная память: malloc() и free()
Рассмотренные классы хранения имеют одну общую особенность. После выбора класса хранения автоматически появятся решения относительно области видимости и продолжительности хранения. Варианты подчиняются предварительно укомплектованным правилам управления памятью. Однако на выбор доступен еще один вариант, который обеспечивает более высокую гибкость. Он предусматривает применение библиотечных функций выделения и управления памятью.
Для начала давайте вспомним ряд фактов, касающихся выделения памяти. Все программы должны резервировать пространство памяти, достаточное для хранения данных, с которыми они работают. Некоторые операции по выделению памяти происходят автоматически. Например, в результате объявлений
float х;
char place[] = "Поющие в терновнике";
резервируется пространство памяти, достаточное для хранения переменной float и строки. Можно также явно запросить определенный объем памяти:
int plates[100];
Это объявление резервирует 100 ячеек памяти, в каждой из которых можно хранить значение int. Во всех показанных случаях объявление также предоставляет идентификатор выделенной памяти, так что для обращения к данным можно использовать х или place. Как вы помните, память под статические данные выделяется во время загрузки программы в память, а память под автоматические данные выделяется, когда поток управления программы входит в блок, и освобождается, когда поток управления покидает блок.
Язык С выходит за эти рамки. Во время выполнения программы можно выделять дополнительную память. Основным инструментом является функция malloc() которая принимает один аргумент: нужное количество байтов памяти. Затем malloc() ищет подходящий блок свободной памяти. Память будет анонимной, т.е. функция malloc() выделяет блок памяти, но не назначает ему имя. Тем не менее, она возвращает адрес первого байта в этом блоке. Следовательно, вы можете присвоить этот адрес переменной типа указателя и применять такой указатель для доступа в память. Поскольку байт представлен посредством char, функция malloc() традиционно была объявлена с типом указателя на char. Однако в стандарте ANSI С используется новый тип: указатель на void. Этот тип задумывался как обобщенный указатель.
510 глава 12
Функция malloc() может применяться для возвращения указателей на массивы, структуры и т.п., поэтому обычно возвращаемое значение приводится к подходящему типу. В условиях стандарта ANSI С для ясности вы по-прежнему должны осуществлять приведение, но присваивание значения указателя на void указателю другого типа не считается конфликтом типов. Если функции malloc() не удается найти запрошенное пространство, она возвращает нулевой указатель.
Давайте воспользуемся malloc() для решения задачи создания массива. С помощью malloc() можно запросить блок памяти во время выполнения программы. Кроме того, понадобится указатель, чтобы отслеживать, где в памяти находится выделенный блок. Например, взгляните на следующий код:
double * ptd;
ptd = (double *) malloc(30 * sizeof(double));
Этот код запрашивает пространство иод 30 значений типа double и устанавливает ptd для указания на соответствующую ячейку памяти. Обратите внимание, что ptd объявлен как указатель на одиночное значение double, а не на блок из 30 значений double. Вспомните, что имя массива представляет собой адрес его первого элемента. Следовательно, если вы установили ptd так, чтобы он указывал на первый элемент блока, вы можете использовать его подобно имени массива. То есть вы можете применять выражение ptd [0] для доступа к первому элементу блока, ptd [1] — для доступа ко второму элементу и т.д. Как было показано ранее, форму записи с указателями можно использовать для имен массивов, а форму записи с массивами можно применять для указателей.
Теперь у вас есть три способа создания массива.
Читать дальшеИнтервал:
Закладка: