Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2009 лекции ПЯВУ часть1.doc
Скачиваний:
22
Добавлен:
27.03.2015
Размер:
823.3 Кб
Скачать

Генерация случайных чисел

Программа моделирует бросание игральной кости (рис. 6.4.)

#include <iostream>

#include <stdlib.h>

#include <time.h>

using namespace std;

int main()

{

srand(time(0));

for (int i = 1; i <=20; i++)

cout << 1+ rand() % 6 << endl;

return 0;

}

Рис. 6.4. Программа, моделирующая бросание игральной кости

Функция rand()генерирует псевдослучайное целое число в диапазоне между0иRAND_MAX(константа, определенная в заголовочном файлеstdlib.h). Для данной программы необходимы только числа, лежащие в диапазоне от1до6.

rand() % 6– эту операцию называютмасштабированием. Число 6 называетсямасштабирующим коэффициентом. В результате этой операции получаются числа от0до5включительно. После масштабирования нужносдвинутьдиапазон чисел, добавляя1к каждому полученному результату.

Так как функция rand()генерирует псевдослучайные числа, то при втором запуске программы будут получены те же числа, что и при первом. Для получения разных последовательностей необходимо применить операциюрандомизации. Она реализуется с помощью библиотечной функцииsrand. Функция получает в качестве аргумента беззнаковое целое и при каждом выполнении программы задает начальное число, которое функцияrandиспользует для генерации последовательности псевдослучайных чисел. Функцияtimeстандартной библиотеки<time.h>возвращает наилучшее приближение текущего календарного времени, обеспечиваемое реализацией. Таким образом, при каждом запуске программы в генератор псевдослучайных чисел будет передаваться разное начальное число.

6.3. Классы памяти и область действия Классы памяти

В C++ имеется [1] четыре спецификации класса памяти:auto,register,externиstatic. Спецификация класса памяти идентификатора помогает определить его класс памяти, область действия и пространство имен.

Класс памятиидентификатора определяет еговремяжизни- период, в течение которого этот идентификатор существует в памяти. Одни идентификаторы существуют недолго, другие - неоднократно создаются и уничтожаются, третьи - существуют на протяжении всего времени выполнения программы.

Спецификации класса памяти могут быть разбиты на два класса: автоматический класс памяти с локальным временем жизниистатический класс памяти с глобальным временем жизни. Ключевые словаautoиregisterиспользуются для объявления переменных с локальным временем жизни. Такие переменные создаются при входе в блок, в котором они объявлены, они существуют лишь во время активности блока и исчезают при выходе из блока.

К классу с локальным временем жизни могут относиться только переменные. К этому классу относятся локальные переменные функций и параметры функций. Спецификация autoявно объявляет переменные автоматического класса памяти, т.е. с локальным временем жизни. Например, следующее объявление указывает, что переменныех иутипаfloatявляются временными с локальным временем жизни, т.е. они существуют только в теле функции, в которой появляется объявление:

auto float x, у;

Локальные переменные являются переменными с локальным временем жизни по умолчанию, так что ключевое слово autoиспользуется редко. Далее будем ссылаться на переменные автоматического класса памяти просто как на автоматические переменные.

Обычно данные в версии программы на машинном языке загружаются для расчетов и другой обработки в регистры.

Спецификация класса памяти registerможет быть помещена перед объявлением автоматической переменной, чтобы компилятор сохранял переменную не в памяти, а в одном из высокоскоростных аппаратных регистров компьютера. Если интенсивно используемые переменные, такие как счетчики или суммы могут сохраняться в аппаратных регистрах, накладные расходы на повторную загрузку переменных из памяти в регистр и обратную загрузку результата в память могут быть исключены.

Компилятор может проигнорировать объявления register. Например, может оказаться недостаточным количество регистров, доступных компилятору для использования. Приведенное далее объявление определяет, что целая переменнаяcounterдолжна быть помещена в один из регистров компьютера; независимо от того, сделает это компилятор или нет,counterполучит начальное значение1:

register int counter = 1;

Ключевое слово registerможет применяться только к локальным переменным и параметрам функций. Часто объявленияregisterне являются необходимыми. Современные оптимизирующие компиляторы способны распознавать часто используемые переменные и решать, помещать их в регистры или нет, не требуя от программиста объявленияregister

Ключевые слова externиstaticиспользуются, чтобы объявить идентификаторы переменных и функций как идентификаторы статического класса памяти с глобальным временем жизни. Такие переменные существуют с момента начала выполнения программы. Для таких переменных память выделяется и инициализируется сразу после начала выполнения программы. Имена функций тоже существуют с самого начала выполнения программы. Однако это не означает, что эти идентификаторы могут быть использованы во всей программе. Класс памяти и область действия (где можно использовать имя) — это разные вещи.

Существуют два типа идентификаторов статического класса памяти: внешние идентификаторы (такие, как глобальные переменные и имена функций), и локальные переменные, объявленные спецификацией класса памяти static. Глобальные переменные и имена функций по умолчанию относятся к классу памятиextern. Глобальные переменные создаются путем размещения их объявлений вне описания какой-либо функции. Глобальные переменные сохраняют свои значения в течение всего времени выполнения программы. На глобальные переменные и функции может ссылаться любая функция, которая расположена после их объявления или описания в файле.

Если глобальная переменная объявлена в одном файле, а используется в другом, то ее нельзя просто повторно объявить. Для этого в другом файле ее нужно объявить со словом extern, например:

int x, y; //объявление в одном файле (file1)

extern int x, y; //extern объявление в другом файле (file2)

После такого объявления переменных xиyв файлеfile2они будут видны, но повторно создаваться не будут.

#include <iostream>

using namespace std;

int counter()

{

static int count; //по умолчанию count = 0

return ++count;

}

int main()

{

for(int i=0;i<10;i++)

cout<<counter()<<endl;

return 0;

}

Рис. 6.5. Функцияcounterсчитает количество собственных вызовов

Локальные переменные, объявленные с ключевым словом static, известны только в той функции, в которой они определены, но в отличие от автоматических переменных локальные переменныеstaticсохраняют свои значения в течение всего времени существования функции. При каждом следующем вызове функции локальные переменные содержат те значения, которые они имели при предыдущем вызове (см. рис. 6.5.). Следующий оператор объявляет локальную переменнуюcountкакstaticи присваивает начальное значение 1

static int count = 1;

Все числовые переменные статического класса памяти принимают нулевые начальные значения, если программист явно не указал другие начальные значения.

Глобальные переменные и функции, определенные со словом staticизвестны только для файла, где они объявлены.

В С++ для той же цели используются анонимные пространства имен [2]. Использование глобальных static-переменных не рекомендуется.