Параметры подпрограмм, локальные и глобальные данные
Для обеспечения максимальной независимости программных единиц во всех алгоритмических языках принято стандартное правило – данные, объявленные внутри программной единицы, являются собственностью этой программной единицы и образуют так называемый набор локальных данных. В Си область действия локальных данных распространяется только на подпрограмму (функцию), в которой эти данные объявлены. Поэтому несмотря на совпадение имен переменных, используемых в разных программных единицах, между такими переменными ничего общего нет. Это развязывает руки создателям программ, т.к. позволяет им не вникать в детали чужих программ, которые они собираются использовать. Наличие вложенных блоков в программах на Паскале немного модифицирует это стандарт. Здесь действуют права наследования – любой внутренний блок имеет право использовать данные, объявленные во внешнем по отношению к нему блоку. Но если во внутреннем блоке объявляется переменная с таким же именем как и во внешнем блоке, то для нее выделяется новая ячейка оперативной памяти при одновременном сохранении значения переменной внешнего блока.
В связи с описанным разграничением данных возникает вопрос о механизмах взаимодействия программных единиц, одна из которых обращается к другой. Таких механизмов, в общем-то, два – передача данных через параметры и совместное использование общих (глобальных) переменных.
Передача параметров в рассматриваемых системах программирования организуется через стек, в который вызывающая программа может положить либо значение соответствующего фактического параметра, либо его адрес в оперативной памяти. Поэтому принято говорить о передаче параметров либо по значению, либо по адресу.
Если в стеке находится значение фактического параметра, то вызываемая подпрограмма может его извлечь и поместить в свою собственную локальную переменную. Эта переменная может участвовать в любых вычислениях, ее значение во время работы вызванной подпрограммы может неоднократно изменяться, но вызвавшая программа об этих изменениях ничего не узнает. Поэтому по значению можно передавать только те параметры, которые содержат входную информацию для работы вызванной процедуры или функции.
Если вместо значения фактического параметра в стек был помещен его адрес, то любые изменения значения соответствующей переменной сразу же станут общим достоянием. Поэтому по адресу обычно передают те параметры, значения которых должна сформировать вызванная подпрограмма. Кроме этого, по адресу стараются передавать массивы, т.к. поместить в стек адрес намного эффективнее, чем пересылать туда каждый элемент массива. Иногда в стек желательно поместить адрес параметра, сопроводив его дополнительным указанием, запрещающим вызванной подпрограмме изменять значение параметра.
В системах компилирующего типа, к которым относятся и Turbo C, и Turbo Pascal, ситуация с формальными параметрами процедур и функций определена более жестко. В качестве любого конкретного параметра можно передать либо адрес соответствующего фактического аргумента, либо его значение. Для параметров, принимающих только адреса, в Си используются указатели а в Паскале – аргументы, снабженные описателем var. Все остальные параметры передаются только по значению. Чтобы предотвратить изменение фактического параметра, переданного по адресу, в списке аргументов перед описанием соответствующего формального параметра должно находиться служебное слово const.
Кроме аппарата параметров программные единицы могут совместно использовать значения общих (глобальных переменных).
В программных файлах Си переменные, объявленные за пределами всех функций, считаются глобальными по отношению к функциям этого файла и могут использоваться в теле любой функции без каких-либо дополнительных указаний. Но если в теле функции объявлена переменная с таким же именем, то зона ее влияния локализована в данной функции и глобальная переменная с аналогичным именем здесь уже не действует. Если же задача собирается из нескольких программных файлов, то общие для всех функций переменные целесообразно выделить в отдельный программный файл. В функциях, где предполагается их использование, такие переменные должны объявляться с описателем extern (внешний):
extern int a[20];
extern float d;
В программе на Паскале все переменные головной программы являются глобальными. К таковым же относятся и все переменные, объявленные в модулях, подключаемых к программе с помощью директивы Uses. А дальше действует описанный выше стандарт – переменные любого блока могут выступать в качестве глобальных по отношению ко всем вложенным блокам.