Dinamik xotira bilan ishlash

Dinamik xotira bilan ishlash, xususan, malloc, calloc, realloc, va free kabi funktsiyalarni tushunish va ulardan foydalanish dasturlashda muhim rol o'ynaydi. Quyida dinamik xotira ajratish, bo'shatish, pointerlar, va dinamik massivlar bilan ishlash haqida to'liq nazariy ma'lumotlar va amaliy misollarni taqdim etaman.

1. Dinamik Xotira Ajratish va Bo'shatish

Dinamik xotira bu dastur ish vaqtida (runtime) ajratiladigan xotira bo'lib, u o'rnatilgan massiv yoki o'zgaruvchilar kabi kompilyatsiya vaqtida ajratilmaydi. Dinamik xotira odatda stack emas, heap (xotira maydoni) orqali ajratiladi.

Funktsiyalar:

  • malloc(size_t size): Xotiradan berilgan hajmda (size) joy ajratadi va unga ko'rsatgich qaytaradi. Agar xotira ajratib bo'lmasa, NULL qiymatini qaytaradi.

  • calloc(size_t num, size_t size): num elementli massiv uchun xotira ajratadi va har bir elementni size bayt hajmida saqlaydi. Ajratilgan xotira nol bilan to'ldiriladi.

  • realloc(void *ptr, size_t size): Dinamik xotiraning hajmini o'zgartirish uchun ishlatiladi. Oldin ajratilgan xotira maydonini qayta o'lchash imkonini beradi.

  • free(void *ptr): Ajratilgan xotirani bo'shatadi. Dasturda xotira ishlatib bo'lingandan keyin u bo'shatilishi kerak, aks holda memory leak yuzaga keladi.

2. Dinamik Xotira va Pointerlar

Dinamik xotira ajratishda ko'rsatgichlar muhim ahamiyatga ega. Ko'rsatgichlar (pointers) ajratilgan xotira joyini saqlaydi va unga bevosita kirish imkonini beradi.

Amaliy Misol:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr;
    // Dinamik xotira ajratish
    ptr = (int*) malloc(5 * sizeof(int)); // 5 ta butun son uchun joy ajratish
    
    // Xotira ajratishda xatolik yuz bersa
    if (ptr == NULL) {
        printf("Xotira ajratilmadi!\n");
        return 1;
    }
    
    // Ajratilgan xotiraga qiymatlar kiritish
    for (int i = 0; i < 5; i++) {
        ptr[i] = i + 1;
    }

    // Qiymatlarni chiqarish
    for (int i = 0; i < 5; i++) {
        printf("%d ", ptr[i]);
    }
    
    // Xotirani bo'shatish
    free(ptr);

    return 0;
}

3. Dinamik Massivlar

Statik massivlar oldindan ma'lum o'lchamda ajratiladi va dastur davomida o'lchami o'zgarmaydi. Dinamik massivlar esa xotiradan ajratiladi va o'lchami dastur ish vaqtida o'zgartirilishi mumkin.

Amaliy Misol:

Dinamik massiv yaratish uchun malloc yoki calloc orqali xotira ajratamiz:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr;
    int n;
    
    // Foydalanuvchidan massiv hajmini so'rash
    printf("Massiv o'lchamini kiriting: ");
    scanf("%d", &n);
    
    // Dinamik xotira ajratish
    arr = (int*) malloc(n * sizeof(int));
    
    if (arr == NULL) {
        printf("Xotira ajratilmadi!\n");
        return 1;
    }
    
    // Massiv elementlariga qiymat kiritish
    for (int i = 0; i < n; i++) {
        arr[i] = i * 10;
    }

    // Qiymatlarni chiqarish
    printf("Massiv elementlari: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    
    // Xotirani bo'shatish
    free(arr);
    
    return 0;
}

4. realloc bilan Xotirani Kengaytirish

Agar siz ajratilgan xotirani kattalashtirmoqchi yoki kichraytirmoqchi bo'lsangiz, realloc funksiyasidan foydalanishingiz mumkin. Bu funksiyaning asosiy vazifasi ajratilgan xotiraning hajmini o'zgartirishdir.

Amaliy Misol:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr;
    int n = 5;

    // 5 ta element uchun xotira ajratish
    arr = (int*) malloc(n * sizeof(int));
    
    if (arr == NULL) {
        printf("Xotira ajratilmadi!\n");
        return 1;
    }
    
    // Elementlarga qiymat berish
    for (int i = 0; i < n; i++) {
        arr[i] = i * 2;
    }

    // Xotira o'lchamini oshirish
    n = 10;
    arr = (int*) realloc(arr, n * sizeof(int));
    
    // Yangi elementlarga qiymat berish
    for (int i = 5; i < n; i++) {
        arr[i] = i * 2;
    }
    
    // Qiymatlarni chiqarish
    printf("Kengaytirilgan massiv: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    
    // Xotirani bo'shatish
    free(arr);
    
    return 0;
}

5. Xotira Bo'shatish (free)

Xotirani ajratib bo'lgach, uni bo'shatishni unutmang. Xotirani bo'shatmaslik xotira oqishiga olib kelishi mumkin, bu esa dastur ishlashi vaqtida keraksiz xotira band qilinadi degani.

Amaliy Misol:

#include <stdlib.h>

int main() {
    int *arr;

    // Xotira ajratish
    arr = (int*) malloc(10 * sizeof(int));
    
    // Xotiradan foydalanish...
    
    // Xotirani bo'shatish
    free(arr);

    return 0;
}

6. GCC Orqali Sinab Ko'rish

Linux yoki boshqa UNIX asosidagi operatsion tizimlarda GCC kompilyatori orqali yuqoridagi dasturlarni sinab ko'rishingiz mumkin.

GCC orqali kompilyatsiya qilish:

gcc -o testfile yourfile.c
./testfile

Misol uchun:

gcc -o memory_example memory_example.c
./memory_example

Bu dasturlarning har birini kompyuteringizda sinab ko'ring va dinamik xotira ajratish va ishlatish usullarini yaxshiroq o'rganing.

Rasmlar

Dinamik xotira ishlash jarayonini tushuntirish uchun quyidagi rasmda ko'rsatish mumkin:

  1. Heap vs Stack Diagram: Dinamik va statik xotira joylarini tasvirlovchi diagram.

  2. malloc ishlashi jarayoni: Xotira ajratish diagrammasi.

  3. realloc ishlashi: Xotirani kengaytirish yoki kichraytirish jarayonini tushuntiruvchi diagram.

Yuqorida ko'rsatilgan rasmda dinamik xotira ajratish jarayoni tushuntirilgan. U erda xotira stack va heap hududlariga bo'lingan. Stack mahalliy o'zgaruvchilar va funksion chaqiruvlar uchun ishlatiladi, heap esa dinamik ravishda ajratilgan xotirani saqlaydi. Diagramda malloc funksiyasi orqali heapda xotira ajratish jarayoni ko'rsatilgan va stackda ko'rsatgich heapdagi xotirani ko'rsatib turibdi.

Dinamik xotira bilan ishlashda ushbu diagram sizga tushunchalarni yanada aniqroq qilishga yordam beradi !.

Last updated