Локальные и глобальные переменные. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Локальные и глобальные переменные.



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

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

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

Время жизни –это время между размещением переменной в стеке и ее унчтожением- может быть постоянным (в течение выполнения программы) и временным (в течение выполнения блока)

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

Класс памяти

Класс памяти определяет порядок размещения объекта в памяти. Различают автоматический и статический классы памяти. C++ располагает четырьмя спецификаторами класса памяти:

auto

register

static

extern

по два для обозначения принадлежности к динамическому и статическому классам памяти.

В свою очередь, статический класс памяти может быть локальным (внутренним) или глобальным (внешним).

Следующая таблица иллюстрирует иерархию классов памяти.

Динамический класс памяти Статический класс памяти
Автоматический Регистровый Локальный Глобальный
auto register static Extern

Спецификаторы позволяют определить класс памяти определяемого объекта:

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

register. Ещё один спецификатор автоматического класса памяти. Применяется к объектам, по умолчанию располагаемым в локальной памяти. Представляет из себя "ненавязчивую просьбу" к транслятору (если это возможно) о размещении значений объектов, объявленных со спецификатором register в одном из доступных регистров, а не в локальной памяти. Если по какой-либо причине в момент начала выполнения кода в данном блоке операторов регистры оказываются занятыми, транслятор обеспечивает с этими объектами обращение, как с объектами класса auto. Очевидно, что в этом случае объект располагается в локальной области памяти.

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

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

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

 

Параметры функции

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

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

3 по значению

4 по адресу.

П ередача по значению

Синтаксис при вызове имя_ф(имя факт. парам);

при определении и объявлении тип имя_ф(тип имя форм параметра);

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

Передача по адресу

Используется 2 синтаксиса

1. с помощью ссылки.

при вызове имя_ф(имя факт. парам);

при определении и объявлении тип имя_ф(тип &имя форм параметра);

2. с помощью указателя

при вызове имя_ф(&имя факт. парам);

при определении и объявлении тип имя_ф(тип *имя форм параметра);

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

При передаче по адресу в качестве фактических параметров нельзя использовать выражения, а только имена переменных

#include <iostream.h>

void f(int, int*. int&);

int main(){

int i = 1. j = 2, k= 3;

cout <<"i j k\n";

cout << i <<' '<< j <<' '<< k <<'\n';

f(i, &j, k);

cout << i <<' '<< j <<' '<< k <<'\n';

return 0;}

void f(int i. int* j. int& k)

{

i++; (*j)++; k++;

}

Первый параметр (1) передается по значению. Его изменение в функции не влияет на исходное значение. Третий параметр (у2) передается по адресу с помощью указателя, при этом для передачи в функцию адреса фактического параметра используется операция взятия адреса, а для получения его значения в функции требуется операция разыменования. Второй параметр (у1) передается по адресу с помощью ссылки.

Пример: Написать программу, вычисляющую значение и 1-ю, 2-ю производные функции у=х3-2х+1 при заданном значении х.

#include <iostream.h>

#include <math.h>

#include <conio.h>

float dif(float, float &, float *);

void main (void)

{float x,p,p1,p2;

cout<<"y=x^3-2x+3"<<endl<<"x=";

cin>>x;

p=dif(x,p1,&p2);

cout<<"y= "<<p<<endl;

cout<<"y'= "<<p1<<endl;

cout<<"y''= "<<p2<<endl;

getche();}

float dif(float t, float &y1, float *y2)

{y1=2*t*t-2;

*y2=6*t;

return pow(t,3)-2*t+1;}

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

Передача массивов в функции

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

Т.к. работаем с указателями, то информация о количестве элементов массива теряется, и следует передавать его размерность через отдельный параметр (в случае массива символов, то есть строки, ее фактическую длину можно определить по положению нуль-символа):

Имеется три способа объявления параметра, предназначенного для получения указателя на массив.

Во-первых, он может быть объявлен как массив, как показано ниже:

#include <stdio.h>

void vivod(int num[10], int n);

int main(void)

{

int t[10], i;

for(i=0; i<10; i++) t[i]=i;

vivod (t,10);

return 0;

}

void vivod (int num[10])

// void display(int num[],int n)

// void display(int *num,int n)

{

int i;

for(i=0; i<n; i++) printf(“%d “, num[i]);

}

Все, приведенные выше, три способа объявления параметра приводят к одинаковому результату – указателю.

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

Пример Даны два одномерных массива. Вывести упорядоченные массивы, и упорядоченный массив, объединенный из элементов двух массивов

#include<stdio.h>

#include<conio.h>

void input(float *,int);

void sort(float *,int);

void output(float *,int);

main()

{

int i,j,k,n1,n2;

printf("Vv n1 and n2:");

scanf("%d%d",&n1,&n2);

float *a=new float[n1];

float *b=new float[n2];

float *c=new float[n1+n2];

input(a,n1);

input(b,n2);

sort(a,n1);

sort(b,n2);

output(a,n1);

output(b,n2);

for (i=j=k=0;i<n1+n2;i++)

if((a[j]<=b[k]||k>=n2)&&j<n1) {c[i]=a[j];j++;}

else {c[i]=b[k];k++;}

output(c,n1+n2);

getche();

return 0;

}

void input(float *a,int n)

{

int i;

for(i=0;i<n;i++)

{printf("Vv %3d element:",i+1);

scanf("%f",&a[i]);

}

}

void sort(float *a,int n)

{

int i,j;

float tmp;

for(i=1;i<n;i++)

{tmp=a[i];

for(j=i-1;j>=0;j--)

{if(tmp>a[j]) break;

a[j+1]=a[j];

}

a[j+1]=tmp;

} }

void output(float *a,int n)

{int i;

for(i=0;i<n;i++)

printf("%.3f ",a[i]);

printf("\n");

}

 



Поделиться:


Последнее изменение этой страницы: 2017-02-07; просмотров: 220; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.226.187.24 (0.027 с.)