Жады кластары және программаларды ұйымдастыру


Объектілердің локализациялануы. Автоматы жадыны сипаттау үшін auto немесе register жадыларының классспецификаторлары қолданыла береді. Бірақта бұл жады класының  спецификаторлардың-кілттік сөздерінсіз-ақ блок ішінде анықталған(мысалы,функция денесінің ішінде) кез-келген объект (мысалы,массивтер немесе айнымалылар), автоматты жады объектісі ретінде қабылданады. Автоматты жады объектісі өзі анықталған блоктың ішінде ғана бар болады. Аuto немесе register типіндегі объектілерімен белгіленген жады блоктан шыға бергенде босатылады, яғни объектілер жоғалады. Блокқа қайта кіргенде сол объектілер үшін жадыдан алдыңғылардан тәуелдсіз жаңа аймақтар бөлінеді. Автоматты жады объектілері өздері анықталған блоктың ішінде локалданған, олардың бар болу уақыты("өмір сүру" уақыты) сол блоктың ішіндегі басқарудың бар болуымен анықталады. Басқаша айтқанда, автоматты жады әрқашанда ішкі болады, оған тек сол блокта, яғни өзі анықталған блокта болғанда ғана байланыса аласыз.

Мысал:

# include <stdio.h>

/* Автоматты жады айнымалылары */

void autofunc(void)

{

int K=l;

printf("\tK=%d",K);

K++;

return;

}

void main()

{

int x;

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

autofunc();

}

Программаның орындалуының нәтижелері: K=1  K=1     K=1     K=1     K=1

Бұл программаның орындалуының нәтижесі айқын көрініп тұр, және келтірмей-ақ қоюға болатын еді егер ішкі жадының тағы бір классы статистикалық ішкі жады болмаса. Келтірілген программаға өте ұқсас программаны қарастырайық:

#include <stdio.h>

/* Статистикалық жадының локальды айнымалылары */

void stat(void)

{

static int K=l;

printf("\tK=%d",K>

K++;

return;

}

void main()

{

int i;

for (i=0;x<5;i++)

stat() ;

}

Программаның орындалуының нәтижелері:K=1   K=2     K=3     K=4     K=5

Отличие функций autofunc() и stat() состоит в наличии спецификатора static при определении переменной int К, локализованной в теле функции stat(). К айнымалысы autofunc() функциясындағы - бұл автоматты жады айнымалысы, ол функцияға әр кірген сайын анықталады және инициализацияланады. static int К айнымалысы жадыдан орын алады және бір-ақ рет қана инициализирленеді. К статистикалық ішкі айнымалысының соңғы мәні stat() функциясынан шыға берісте, дәл осы функцияның кезеті шақырылуына дейіін сақталады. 

Глобальды объектілер. Блоктар ішінде объектілерді қолдану мүмкіндігіне назар аудару қажет, Следует обратить внимание на возможность использовать внутри блоков объекты, которые по месторасположению своего определения оказываются глобальными по отношению к операторам и определениям блока. Есімізге түсірейік, блок – бұл тек функция денесі ғана емес, сонымен қоса ирек жақша ішіне алынған кез-келегн анықтама және операторлар кезектілігі.

Глобальды айнымалы программасынан мысал:

#include <stdio.h>

int N=5;

/* Глобальная переменная */

void func(void)

{

printf("\tN=%d",N);

N--;

return;

}

void main()

{

int i;

for (i=0;i<5;x++)

{

func();

N+=2;

}

}

Программа орындалуының нәтижесі: N=5 N=6     N=7     N=8     N=9

int N айнымалысы main( ) және func() функциясының ішінде анықталмаған және олардың әрқайсысына байланысты глобальды объект болып табылады. Ғunc( ) –ты әр шақырған сайын N-нің мәні 1-ге азаяды, негізгі программада 2-ге ұлғаяды. Глобальді обьект блоктың ішінде глобальді обьектінің аты басқа мақсатпен иқолданғанда, анықтамамен  "затенен" немесе "жасырылған" болуы мүмкін. Алдыңғы программаны модифицирлейміз:

#include <stdio.h>

int N=5; /* глобальды айнымалы*/

void func(void)

{

printf("\tN=%d",N);

N--;

return;

}

void main()

{

int N; /* локальды айнымалы */

for (N=0;N<5;N++)

func() ;

}

Программа орындалуының нәтижесі:  N=5 N=4   N=3     N=2     N=l

Автоматты жадының main( ) функциясынан шыққан int N айнымалысы  int N глобальды айнымалысының мәніне еш әсер етпейді. Бұлар жадыдан әртүрлі аумақтары берілген әртүрлі объектілер. Ішкі айнымалы N main() функциясынан "көрінбейді" және бұл int N анықтамасының нәтижесі оның ішінде болады.

Динамикалық жады – бұл программаның орындалу барысында бөлінетін жады. Ал мына сұраққа: "Динамикалық жадыда глобальды ма әлде локальді объект орналасқан?" дұрыс жауап тауып көрейік.

Динамикалық жадыны бөлгеннен кейін, арнайы библиотекалық  free() функциясының  көмегімен ғана орындалуы мүмкін, оның толық босатылуына дейін сақталады.

 

Программаның орындалу барысында динамикалық жады аумағы осы аумақты адрестейтін нұсқаушы рұқсат етілген барлық жерде рұқсат етілген. Сондай қандай да бір блокта бөлінген (мысалы, негізгі емес функцияның денесінде) динамикалық жадымен жұмыстың келесі үш нұсқасы мүмкін:

· нұсқаушы (динамикалық жады аумағында) автоматты жадының локальды объектісі ретінде анықталған. Бұл жағдайда бөлініп алынған жады нұсқаушының локальденуі блогының сыртына шыға бергенде рұқсат жоқ болады, және оны блоктан шығар алдында босату қажет;

· нұсқаушы статистикалық жадының локальды объектісі ретінде анықталған. Блокта бөлініп алынған динамикалық жады әр блокқа кірген сайын нұсқаушы арқылы рұқсат етілген. Жадыны тек оны қолдануды аяқтағаннан кейін ғана босату керек;

  • нұсқаушы блокқа байланысты глобальді объект болып табылады. Динамикалық жады нұсқаушы "көрінген" барлық блокта мүмкін. Жадыны тек оны қолдануды аяқтағаннан кейін босату керек.

Динамикалық жадының объектісі ішкі статистикалық нұсқаушымен(локальденген) байланысты болғанда, екінші нұсқасын иллюстрациялаймыз:

#include <stdio.h>

#include <alloc.h> /* malloc(),free() функциялары үшін */

void dynam(void)

{

static char *uc=NULL; /*  Ішкі нұсқаушы */

/* Жадының бірнеше рет бөлінуінен сақтау: */

if (uc ==NULL)

{

uc=(char*)malloc(1);

*uc='A';

}

printf("\t%c",*uc);

(*uc)++;

return;

}

void main()

{

int i;

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

dynam( );

}

Программа орындалуының нәтижесі:  А     B          C         D         E

Алдыңғы программаның дұрыс еместігі - malloc()функциясымен бөлінген жады аумағы free( ) функциясымен босатылуы екіталай.

Келесі программада нұсқаушы жадының динамикалық аумағында - глобальды объект:

#include <stdio.h>

#include <alloc.h> /* malloc( ), free( ) функциялары үшін */

char  *  uk=NULL; /*  глобальды нұсқаушы  */

void dynam1 (void)

{

printf("\t%c", *uk) ;

(*uk)++;

}

void main (void)

{

int i ;

uk=(char*) malloc (1);

*uk='A' ;

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

{

dynam1();

(*uk)++;

}

free(uk);

}

Программа орындалуының нәтижесі:  А     С         Е         G         I

Динамикалық объект негізгі функцияда құрылады және uk нұсқаушысымен байланысады. Сол жерде меншіктеуде бастапқы 'А' мәнін қабылдайды. Динамикалық объект глобальды нұсқаушы есебінен екі main() және dynam1() функцияларында да мүмкін. main() және dynam1() функциясының ішінде циклдың орындалу барысында динамикалық объект мәні өзгереді.

Жадының динамикалық бөлінген аумағын адрестейтін нұсқаушы, автоматты жады объектісі болып табылатындығына мысал келтірудің қажеттігі жоқ. Атап өтейік,  динамикалық жады, анықталған немесе сыртқы объект ретінде сипатталған нұсқаушының осы жадымен байланысқан жерінде(кез-келген функцияда және кез-келген файлда) бөлінгеннен кейін барлық жерде рұқсат етілген. Ішкі объект анықтамасын нақты анықтау керек, ол тақырыпқа да көшеміз.

Ішкі объектілер. Си тіліндегі қарапайым немесе күрделі программа бірнеше мәтіндік файлдарда орналасқан, функциялар жиынынан тұрады.  Программа мәтіні бар бөлек файлды кейде программалық модуль деп те атайды, бірақ модульдерге немесе файлдарға қатысты қатаң терминологиялық келісімдер жоқ. Программа функциялар жиынынан тұрады. Барлық ішкі функциялар, функцияның ішінде орналасқандықтан Си тілінің ережесі бойынша басқа функцияны анықтауға болмайды. Барлық функцияларда, тіпті әртүрлі файлдарда орналасқанның өзінде әртүрлі атаулар болуы керек. Функциялардың бірдей атауы бір және сол функцияға ғана қатысты болуы керек.

Функциядан басқа, программада ішкі обьектілер – айнымалылар, нұсқаушылар, массивтер және т.б қолданылады. Сыртқы объектілер функция мәтінінің сыртында анықталуы керек.

Сыртқы объектілер программаның көптеген функцияларынан алына алады, бірақта бұндай рұқсат алу үнемі автоматты түрде болмайды-жағдайлар қатарында программисттің қосымша араласуы қажет. Егер объект программамен бірге файлдың басында анықталған болса, онда ол файлда орналасқан барлық функциялар үшін глобальды болып табылады, және соның ішінде ешқандай қосымша жазылымдарсыз-ақ байланысу мүмкін болады.  (Шектеу - егер функция ішінде глобальды объект атауы ішкі объект ретінде қолданылса, онда сыртқы объект мүмкін емес болып қалады, яғни "көрінбейтін" дәл осы функция денесінде.).

Суретте:

Егер сыртқы объект басқа файлдың немесе функцияның функциясы үшін рұқсат етілген болуы қажет болса, онда ол сұхбаттасудан бұрын қосымша кілттік extern сөзін қолданумен бірге қосымша сипатталған болуы керек. (Наличие этого слова по умолчанию предполагается и для всех функций, т.е. не требуется в их прототипах.) Ондай сипаттама, extern сөзінің спецификаторымен бірге файлдың басында енгізіледі, және сонда объект файлдың барлық функцияларында доступен. Бірақта бұл сипаттама бір функцияның денесінде орналасуы мүмкін, онда объект сонда(ішнде)  ғана доступен.

Сыртқы объект сипаттамасы оның анықтамасы емес. Естеріңізде сақтаңыздар: анықтамада объектіге ылғида жады бөлінеді, және ол инициализирленген болуы мүмкін. Анықтама мысалы:

double summa[5];

char D_Phil []="Doctor of Philosophy";

long M=1000;

Сипаттауда инициализация мүмкін емес, массивтер элементтерінің санын да көрсетуге болмайды:

extern double summa  [  ];

extern char D_Phil   [   ];

extern long M;