C Xotira sinflari

Avtomatik xotira obyektlari. Blok deb funksiya tanasi yoki figurali qavslar ichiga olingan ta’riflar va operatorlar ketma-ketligiga aytiladi. Avtomatik xotira faqat o’zi aniqlangan blok ichida mavjud bo’ladi. Blokdan chiqishda obyektlar uchun ajratilgan xotira qismi bo’shatiladi, ya’ni obyektlar yo’qoladi. Shunday qilib avtomatik xotira har doim ichki xotiradir, ya’ni bu xotiraga o’zi aniqlangan blokda murojaat qilish mumkin. Avtomatik xotira obyektlari auto xizmatchi so’zi yordamida ta’riflanadi. Ko’zda tutilgan bo’yicha har qanday lokal xotira obyekti avtomatik xotiraga tegishli bo’ladi.

Registrli xotira obyektlari. Registrli xotira obyektlari hamma jihatlari bo’yicha avtomatik xotira obyektlari bilan bir xil bo’ladi, faqat ular uchun xotira iloji bo’lsa registrlarda ajratiladi. Registrli xotira obyektlari register xizmatchi so’zi yordamida ta’riflanadi.

Statik xotira obyektlari. Statik xotira obyektlari blokdan chiqilgandan so’ng ham mavjud bo’lib qolaveradi. Statik xotira obyektlari static xizmatchi so’zi yordamida ta’riflanadi.

Misol:

#include <stdio.h>
void autofunc(void)
{
    int K = 1;
    printf(" K = %d",K);
    K++;
    return;
}
int main()
{
    int i;
    for (i = 0;i<5;i++)
    autofunc();
    return 0;
}

Bu dastur bajarilishi natijasi:

K = 1 K = 1 K = 1 K = 1 K = 1

Shu dasturning ikkinchi ko’rinishida K o’zgaruvchi statik o’zgaruvchi sifatida ta’riflanadi:

#include <stdio.h>
void autofunc(void)
{
    static int K = 1;
    printf(" K = %d",K);
    K++;
    return;
}
int main()
{
    int i;
    for (i = 0;i<5;i++)
    autofunc();
    return 0;
}

Bu dastur bajarilishi natijasi:

K = 1 K = 2 K = 3 K = 4 K = 5

Bu misolda K o’zgaruvchi faqat bir marta inisializasiya qilinadi va uning qiymati navbatdagi murojaatgacha saqlanadi.

Global obyektlar. Global obyektlar deb dasturda hamma bloklar uchun umumiy bo’lgan obyektlarga aytiladi. har bir blok ichida global obyektga murojaat qilish mumkindir.

Misol:

#include <stdio.h>
int N = 5;
void func(void)
{
    printf("\tN = %d",N);
    N--;
    return;
}
int main()
{
    for (int i = 0;i<5;i++)
    {
        func();
        N=N+2;
    }
    return 0;
}

Dastur bajarilishi natijasi:

N = 5 N = 6 N = 7 N = 8 N = 9

Bunda N o’zgaruvchisi main() va func() funksiyalari tashqarisida aniqlangan va bu funksiyalarga nisbatan globaldir. har bir func() chaqirilganda uning qiymati 1 ga kamayadi, asosiy dasturda bo’lsa 2 taga oshadi. Natijada N qiymati 1 ga oshib boradi.

Endi dasturni o’zgartiramiz:

#include <stdio.h>
int N = 5;
void func(void)
{
    printf("\tN = %d",N);
    N--;
    return;
}
int main()
{
    int N;
    for (int i = 0;i<5;i++)
    {
        func();
    }
    return 0;
}

Dastur bajarilishi natijasi:

N = 5 N = 4 N = 3 N = 2 N = 1

N o’zgaruvchisi main() funksiyasida avtomatik o’zgaruvchi sifatida ta’riflangan va u global N o’zgaruvchiga ta’sir qilmaydi. Ya’ni global N o’zgaruvchi main() funksisida ko’rinmaydi.

Tashqi obyektlar. Dastur bir necha matnli fayllarda joylashgan bo’lishi mumkin. Dastur o’z navbatida funksiyalardan iboratdir. Hamma funksiyalar tashqi hisoblanadi. hatto har xil fayllarda joylashgan funksiyalar ham har xil nomlarga ega bo’lishi lozimdir. Funksiyalardan tashqari dasturlarda tashqi obyektlar o’zgaruvchilar, ko’rsatkichlar, massivlar ishlatilishi mumkin. Tashqi obyektlar hamma funksiyalarda ham ko’rinmasligi mumkin. Agar obyekt fayl boshida ta’riflangan bo’lsa u shu fayldagi hamma funksiyalarda ko’rinadi. Agar tashki ob’ektga shu ob’ekt ta’riflangan blokdan yuqorida yoki boshqa faylda joylashgan blokdan murojaat qilinishi kerak bo’lsa, bu obyekt extern xizmatchi so’zi yordamida ta’riflanishi lozimdir. Shuni aytish lozimki extern xizmatchi so’zi yordamida ta’riflanganda inisializasiya qilish yoki chegaralarni ko’rsatish mumkin emas.

extern double summa[];
extern char D_phil [];
extern long M;

Misol uchun VAL va SP o’zgaruvchilari bitta faylda, bu o’zgaruvchilarga murojaat qiluvchi PUSH, POP i CLEAR funksiyalari boshqa faylda ta’riflangan bo’lsin. Bu holda bu fayllar orasidagi bog’liqlikni ta’minlash uchun quyidagi ta’riflar lozimdir:

1 faylda: 

INT SP = 0; /* STACK POINTER */
DOUBLE VAL[MAXVAL]; /* VALUE STACK */ 

2 faylda: 

EXTERN INT SP;
EXTERN DOUBLE VAL[]; 
DOUBLE PUSH(F)  
DOUBLE POP()  
CLEAR() 

Dinamik xotira. Dinamik xotira bu dastur bajarilishi jarayonida ajratiladigan xotiradir. Dinamik xotira malloc funksiyasi orqali ajratilgandan so’ng to free funksiyasi tomonidan bo’shatilmaguncha saqlanadi. Quyidagi misolda yakka ob’ektga xotira ajratiladi:

int*pint = (int*)malloc(sizeof(int))

Bu yerda malloc funksiyasi int turidagi nomsiz obyektga xotirani ajratib beradi, hamda yaratilgan obyekt adresini qaytarib beradi. Bu adres pint ko’rsatkichiga joylashtiriladi. Ushbu nomsiz obyekt ustidagi barcha xatti-harakatlar shu ko’rsatkich bilan ishlash orqali amalga oshiriladi, chunki dinamik obyekt bilan to’g’ridan-to’g’ri ish olib borish (manipulyasiyalar o’tkazish) mumkin emas. Agar dinamik xotira dastur bajarilishi tugaguncha bo’shatilmagan bo’lsa, avtomatik ravishda dastur tugaganda bo’shatiladi. Shunga qaramay ajratilgan xotirani dasturda maxsus bo’shatish dasturlashning sifatini oshiradi. Dinamik obyekt kerak bo’lmay qolganda, unga ajratilgan xotirani to’g’ridan-to’g’ri bo’shatish free funksiyasi yordamida amalga oshiriladi:

free(pint);

Dastur bajarilish davomida ajratilgan xotira qismiga murojaat imkoniyati shu qismga adreslovchi ko’rsatkichga bog’liqdir. Shunday qilib, biror blokda ajratilayotgan dinamik xotira bilan ishlashning quyidagi uchta varianti mavjuddir:

  • Ko’rsatkich avtomatik xotira turiga kiruvchi lokal obyekt. Bu holda ajratildgan xotiraga blokdan tashqarida murojaat qilib bo’lmaydi, shuning uchun blokdan chiqishda bu xotirani bo’shatish lozimdir.
  • Ko’rsatkich avtomatik xotira turiga kiruvchi lokal statik obyekt. Blokda bir marta ajratilgan dinamik xotiraga, blokka har bir qayta kirilganda ko’rsatkich orqali murojaat qilish mumkindir. Xotirani blokdan foydalanib bo’lgandan so’ng bo’shatish lozimdir.
  • Ko’rsatkich blokka nisbatan global ob’ektdir. Dinamik xotiraga ko’rsatkich ko’rinuvchi hamma bloklardan murojaat qilish mumkin. Xotirani faqat undan foydalanib bo’lgandan so’ng bo’shatish lozimdir. 

Ikkinchi variantga misol keltiramiz, bu misolda dinamik xotira obyekti ichki statik ko’rsatkich bilan bog’liqdir:

#include <stdio.h>
#include<stdlib.h>
void dynamo(void)
{ 
    static char *uc = NULL;
    if (uc == NULL)
    {
        uc = (char*)malloc(1);
        *uc = 'A';
    }
    printf("%c",*uc);
    (*uc)++;
    return;
};
int main()
{
    int i;
    for (i = 0;i<5;i++)
    dynamo();
    return 0;
}

Dastur bajarilishi natijasi:

A B C D E

Bu dasturning kamchiligi ajratilgan xotira bo’shatilmasligidir. Keyingi dasturda dinamik xotiraga ko’rsatkich global obyektdir:

#include <stdio.h>
#include<stdlib.h>
char *uk = NULL;
void dynam1(void)
{ 
    printf("%c",*uk);
    (*uk)++;
    return;
};
int main()
{
    int i;
    uk = (char*)malloc(1);
    *uk = 'A';
    for (i = 0;i<5;i++)
    {
        dynam1();
        (*uk)++;
    }
    free(uk);
    return 0;
}

Dastur bajarilishi natijasi:

A C E G I

Dinamik obyekt asosiy dasturda yaratilib, u ko’rsatkich bilan bog’liqdir. Dasturda boshlang’ich 'A' qiymatga ega bo’ladi. Ko’rsatkich global bo’lgani uchun dinamik obyektga main() va dynam1() funksiyalarida murojaat qilish mumkin. Dinamik xotiraga ajratilgandan so’ng shu obyekt bilan bog’liq ko’rsatkich tashki obyekt sifatida ta’riflangan ixtiyoriy blokda murojaat qilish mumkin.