Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Статические и внешние переменные



Объекты, размещаемые в статической памяти, декларируются с атрибутом static и могут иметь любой атрибут области действия. В зависимости от расположения оператора описания статические переменные могут быть глобальными и локальными. Время жизни – постоянное. Инициализируется один раз при первом выполнении оператора, содержащего определение переменной. Глобальные объекты всегда являются статическими. Атрибут static, использованный при описании глобального объекта, предписывает ограничение его области применения только в пределах остатка текущего файла, а значения локальных статических объектов сохраняются до повторного вызова функции, т.е. в языке Си ключевое слово static имеет разный смысл для локальных и глобальных объектов.

Итак, переменная, описанная вне функции, является внешней (глобальной) переменной.

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

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

При отсутствии явной инициализации для внешних и статических переменных гарантируется их обнуление. Автоматические и регистровые переменные имеют неопределенные начальные значения («мусор»).

Внешняя переменная должна быть определена вне всех функций. При этом ей выделяется фактическое место в памяти. Такая переменная должна быть описана в той функции, которая собирается ее использовать. Это можно сделать либо явным описанием extern, либо по контексту.

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

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

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

int sp;

double val[20];

то они определяют внешние переменные sp и val, вызывают отведение памяти для них и служат в качестве описания для остальной части этого исходного файла. В то же время строчки:

extern int sp;

extern double val [ ];

описывают в остальной части этого исходного файла переменную sp как int, а vаl как массив типа double, но не создают переменных и не отводят им места в памяти.

Во всех файлах, составляющих исходную программу, должно содержаться только одно определение внешней переменной. Другие файлы могут содержать описание extern для доступа к ней.

Любая инициализация внешней переменной проводится только в декларации. В декларации должны указываться размеры массивов, а в описании extern этого можно не делать.

Например, в основном файле проекта:

int sp = 50;

double val [20];

void main() {

...

а в дополнительном файле этого проекта:

extern int sp;

extern double val [ ];

...

В Си есть возможность с помощью директивы компилятору #include использовать во всей программе только одну копию описаний extern и присоединять ее к каждому файлу во время его препроцессорной обработки.

Если переменная с таким же идентификатором, как внешняя, декларирована в функции без указания extern, то тем самым она становится внутренней (локальной) для данной функции.

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

Пример, иллюстрирующий использование внешних данных:

Основной файл проекта Дополнительный файл
¼ int x, y; char str[ ] = “Rezult = ”; void fun1(void); void fun2(void); void fun3(void); void main(void) { fun1(); fun2(); fun3(); } void fun1(void) { y = 15; printf(“\n %s %d\n”, str, y); } ¼ extern int x, y; extern char str[ ]; int r = 4;   void fun2(void) { x = y / 5 + r; printf(“ %s %d\n”, str, x); }   void fun3(void) { int z= x + y; printf(“ %s %d\n”, str, z); }  

В результате выполнения этого проекта, состоящего из двух различных файлов, будет получено следующее:

Rezult = 15

Rezult = 7

Rezult = 22

 

Область действия переменных

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

Напомним общую структуру исходного текста программы:

<директивы препроцессора>

<описание глобальных объектов>

<заголовок функции>

{

<описание локальных объектов>

<список инструкций>

}

Файл исходного текста может включать любое количество определений функций и/или глобальных данных.

Параметры функции являются локальными объектами и должны отличаться по идентификаторам от используемых в коде функции глобальных объектов. Локальные объекты, описанные в коде функции, имеют приоритет перед объектами, описанными вне функции, например:

#include<stdio.h>

int f1(int);

int f2(int);

int f3(int);

int n; // Глобальная n

void main (void)

{

int i=2; // Локальная i=2

n=3; // Глобальная n=3

i = f1(i); // Обе переменные i – локальные

printf(" 1: i=%d , n=%d\n",i,n); // i=7, n=3

n = f1(i); // n – глобальная, i – локальная

printf(" 2: i=%d , n=%d\n",i,n); // i=7, n=12

i = f2(n); // i и n – локальные

printf(" 3: i=%d , n=%d\n",i,n); // i=15, n=12

i = f3(i); // Обе переменные i – локальные

printf(" 4: i=%d , n=%d\n",i,n); // i=29, n=14

}

//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

int f1(int i) { // Параметр функции i – локальная

int n = 5; // n – локальная

n+=i;

return n;

}

//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

int f2(int n) { // Параметр функции n – локальная

n+=3;

return n;

}

//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

int f3(int i) {

n+=2; // n – глобальная

return i+n;

}

 

Существуют следующие области действия: блок, файл, функция, прототип функции, область структурированных типов данных.

Блок. Идентификаторы, описанные внутри блока, являются локальными. Область действия идентификатора начинается в точке определения и заканчивается в конце блока, видимость – в пределах блока и внутренних блоков, время жизни – до выхода из блока. После выхода из блока память освобождается.

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

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

Прототип функции. Идентификаторы, указанные в списке параметров прототипа (декларации) функции, имеют областью действия только прототип функции.

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

В языке С++ допускается в разных блоках программы использовать один и тот же идентификатор для разных объектов. Декларация такого идентификатора внутри блока скрывает доступ к ранее объявленному, например:

void main(void)

{

int a = 3;

printf(“\n Block 1: %d “, a); {

double a = 2.5;

printf( “\n Block 2: %lf “, a); {

char a = ‘A’;

printf( “\n Block 3: %c “, a);

}

printf( “\n New Block 2: %lf“, a+1.25);

}

printf( “\n New Block 1: %d“, ++a);

}

Результат программы:

Block 1: 3

Block 2: 2.5

Block 3: A

New Block 2: 3.75

New Block 1: 4

 

 

Советы по программированию

При выполнении вариантов заданий придерживайтесь следующих клю­че­вых моментов.

1. Размеры нединамических массивов задаются константами или константными выражениями. Рекомендуется для этого использовать поименованные константы.

2. Элементы массивов нумеруются с нуля, максимальный номер (индекс) элемента всегда на единицу меньше указанного размера.

3. Автоматический контроль выхода индексов элементов за указанные границы массива отсутствует.

4. Указатель – это переменная, в которой хранится адрес участка оперативной памяти.

5. Имя массива является указателем на его нулевой элемент, т.е. на его начало в оперативной памяти.

6. Обнуления динамической памяти при ее выделении не происходит. Инициализировать динамический массив нельзя.

7. Освобождение памяти, выделенной посредством стандартных функций, выполняется при помощи функции free (при использовании операции new – операцией delete).

8. Если количество элементов массива известно заранее, определяйте массив в области декларации переменных (причем лучше как локальный объект). Если же количество элементов массива можно задать во время выполнения программы, лучше создать динамический массив.

9. При задании длины строки необходимо учитывать завершающий нуль-символ (признак окончания строки).

10. Операция присваивания строк выполняется с помощью функции стандартной библиотеки.

11. Для ввода строк, содержащих пробелы, используют функцию gets.

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

13. Недостатком символьных массивов является отсутствие проверки выхода за пределы отведенной им памяти.

14. Двухмерный массив хранится по строкам в непрерывной области памяти.

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

16. Для выделения динамической памяти под массив, в котором все размеры переменные, используются циклы.

17. Функция – это именованная последовательность операторов, выполняющая законченное действие. Функции используют для упрощения структуры программы.

18. Вызов функции осуществляется путем указания ее идентификатора (имени) и в случае необходимости – набора аргументов.

19. Передача аргументов в функцию может выполняться по значению или по адресу.

20. Массивы всегда передаются в функцию по адресу. Количество элементов в массиве должно передаваться отдельным параметром.

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

 

ЗАДАНИЕ 4. Обработка массивов

Первый уровень сложности






Читайте также:

Последнее изменение этой страницы: 2016-03-16; Просмотров: 74; Нарушение авторского права страницы


lektsia.com 2007 - 2017 год. Все права принадлежат их авторам! (0.1 с.) Главная | Обратная связь