Чтение онлайн

ЖАНРЫ

Язык Си - руководство для начинающих

Д. МАРТИН

Шрифт:

Вы можете также описать статические переменные вне любой функции. Это создаст "внешнюю статическую" переменную. Разница между внешней переменной и внешней статической переменной заключается в области их действия. Обычная внешняя переменная может использоваться функциями в любом файле, в то время как внешняя статическая переменная может использоваться только функциями того же самого файла, причем после определения переменной. Вы описываете внешнюю статическую переменную, располагая ее определение вне любой функции.

static randx = 1;

rand

{

Немного

позже мы приведем пример, в котором будет необходим этот тип переменной.

 

РИС. 10.1. Внешние и внешние статические переменные.

Регистровые переменные

Обычно переменные хранятся в памяти машины. К счастью, регистровые переменные запоминаются в регистрах центрального процессора, где доступ к ним и работа с ними выполняются гораздо быстрее, чем в памяти. В остальном регистровые переменные аналогичны автоматическим переменным. Они создаются следующим образом:

main

{

register int quick;

Мы сказали "к счастью", потому что описание переменной как регистровой, является скорее просьбой, чем обычным делом. Компилятор должен сравнить ваши требования с количеством доступных регистров, поэтому вы можете и не получить то, что хотите. В этом случае переменная становится простой автоматической переменной.

Какой класс памяти применять?

Ответ на вопрос почти всегда один - "автоматический". В конце концов почему этот класс памяти выбран по умолчанию? Мы знаем, что на первый взгляд использование внешних переменных очень соблазнительно. Опишите все ваши переменные как внешние, и у вас никогда не будет забот при использовании аргументов и указателей для связи между функциями в прямом и обратном направлениях. К сожалению, у вас возникнет проблема с функцией С, коварно изменяющей переменные в функции А, а это совсем не входит в паши интересы. Неоспоримый совокупный опыт использования машин, накопленный в течение многих лет, свидетельствует о том, что такая проблема значительно перевешивает кажущуюся привлекательность широкого использования внешних переменных.

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

Иногда полезны и другие классы памяти. Но прежде чем их использовать, спросите себя, необходимо ли это.

Резюме: Классы памяти

I. Ключевые слова: auto, extern, static, register

II. Общие замечания:

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

III. Свойства

КЛАСС
ПАМЯТИ
КЛЮЧЕВОЕ СЛОВО ПРОДОЛЖИТЕЛЬНОСТЬ СУЩЕСТВОВАНИЯ ОБЛАСТЬ ДЕЙСТВИЯ
Автоматический auto Временно Локальная
Регистровый register Временно Локальная
Статический static Постоянно Локальная
Внешний extern Постоянно Глобальная (все файлы)
Внешний статический static Постоянно Глобальная (один файл)

1. Разделим случайное число на 32768. В результате получим число х в диапазоне - 1 <= х < 1. (Мы должны превратить его в тип float, чтобы иметь десятичные дроби.)

2. Добавим 1. Наше новое число удовлетворяет отношению 0 < = х < 2.

3. Разделим на 2. Теперь имеем 0 <= х < 1.

4. Умножим на 6. Имеем 0 <= х < 6. (Близко к тому, что нужно, но 0 не является возможным значением.)

5. Прибавим 1: 1 <= х < 7. (Заметим, что эти числа все еще являются десятичными дробями.)

6. Преобразуем в целые числа. Теперь мы имеем целые в диапазоне от 1 до 6.

7. Для обобщения достаточно заменить значение 6 в п. 4 на число сторон.

Вот функция, которая выполняет эти действия:

/* электронное бросание костей */

#define SCALE 32768.0

rollem(sides) float sides;

{

float roll;

roll = ((float)rand/SCALE + 1.0) * sides/2.0 + 1.0;

return((int)roll);

}

Мы включили в программу два явных описания типа, чтобы показать, где выполняются преобразования типов. Обратимся к программе, которая использует эти средства:

/* многократное бросание кости */

main

{

int dice, count, roll, seed;

float sides;

printf(" Введите, пожалуйста, значение зерна. \n");

scanf(" %d, &seed);

srand(seed);

printf(" Введите число сторон кости, 0 для завершения. \n");

scanf(" %d", &sides);

while(sides > 0)

{ printf(" Сколько костей?\n");

scanf(" %d", &dice);

for( roll = 0, count = 1; count <= dice; count++)

roll + = rollem(sides); /* бросание всех костей набора */

Поделиться с друзьями: