15-bo‘lim

Strukturalar

struct bilan o'z ma'lumot turingizni yaratish, typedef, ichma-ich strukturalar, strukturalar massivi, union va enum.

🕑 16 daqiqa o‘qish 📄 576 so‘z 👁 3 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Nima uchun struktura kerak?
  2. Struktura yaratish va ishlatish
  3. Boshlang'ich qiymat berish
  4. typedef - qisqa nom
  5. Struktura bilan funksiyalar
  6. Strukturalar massivi
  7. Ichma-ich strukturalar
  8. enum - nomlangan doimiylar
  9. union - bir xotira, turli turlar
  10. Struktura va dinamik xotira
  11. Bog'langan ro'yxat - strukturaning kuchi
  12. Xulosa

Struktura - turli turdagi ma'lumotlarni bitta nom ostida birlashtiradi. Bu C da o'z ma'lumot turingizni yaratish usuli.

Nima uchun struktura kerak? #

C
/* strukturasiz - ma'lumotlar tarqoq */
char ism[50];
int yosh;
double ortacha_baho;
char shahar[50];

/* struktura bilan - bitta yaxlit tushuncha */
struct Talaba {
    char ism[50];
    int yosh;
    double ortacha_baho;
    char shahar[50];
};
struct Talaba xotirada bir bo'lak ism char[50] 50 bayt yosh int 4 bayt ortacha_baho double 8 bayt shahar char[50] 50 bayt Barcha maydonlar xotirada ketma-ket yotadi Bitta o'zgaruvchi - bitta talaba haqidagi to'liq ma'lumot
Struktura - bog'liq ma'lumotlarni bir joyda saqlash usuli

Struktura yaratish va ishlatish #

C
#include <stdio.h>
#include <string.h>

struct Talaba {
    char ism[50];
    int yosh;
    double ortacha_baho;
    char shahar[50];
};

int main(void) {
    struct Talaba birinchi;

    strcpy(birinchi.ism, "Husanboy Qodirov");
    birinchi.yosh = 25;
    birinchi.ortacha_baho = 4.6;
    strcpy(birinchi.shahar, "Namangan");

    printf("Ism     : %s\n", birinchi.ism);
    printf("Yosh    : %d\n", birinchi.yosh);
    printf("Baho    : %.1f\n", birinchi.ortacha_baho);
    printf("Shahar  : %s\n", birinchi.shahar);

    return 0;
}
Natija
Ism     : Husanboy Qodirov
Yosh    : 25
Baho    : 4.6
Shahar  : Namangan
strcpy kerak - = ishlamaydi
C
birinchi.ism = "Husanboy";      /* XATO: massivga tenglashtirib bo'lmaydi */
strcpy(birinchi.ism, "Husanboy");   /* to'g'ri */

Struktura maydoni massiv bo'lsa, unga strcpy bilan yoziladi. Bu 10-bo'limdagi qoidaning davomi.

Boshlang'ich qiymat berish #

C
#include <stdio.h>

struct Talaba {
    char ism[50];
    int yosh;
    double ortacha_baho;
};

int main(void) {
    /* tartib bo'yicha */
    struct Talaba a = {"Husanboy Qodirov", 25, 4.6};

    /* nom bo'yicha - C99, ancha aniqroq */
    struct Talaba b = {
        .ism = "Malika Yusupova",
        .yosh = 21,
        .ortacha_baho = 4.9
    };

    /* barcha maydonlar nol */
    struct Talaba c = {0};

    printf("%-18s %3d %.1f\n", a.ism, a.yosh, a.ortacha_baho);
    printf("%-18s %3d %.1f\n", b.ism, b.yosh, b.ortacha_baho);
    printf("Bo'sh: \"%s\" %d %.1f\n", c.ism, c.yosh, c.ortacha_baho);

    return 0;
}
Natija
Husanboy Qodirov    25 4.6
Malika Yusupova     21 4.9
Bo'sh: "" 0 0.0
Nom bo'yicha e'lon afzalroq
C
struct Talaba b = {.ism = "Malika", .yosh = 21};

Afzalliklari:

  • tartib muhim emas - istalgan ketma-ketlikda yozish mumkin;
  • hujjat vazifasi - qaysi qiymat qaysi maydonga tegishli ekani ko'rinadi;
  • xavfsiz - strukturaga yangi maydon qo'shilsa, kod buzilmaydi;
  • ko'rsatilmagan maydonlar avtomatik nol bo'ladi.

typedef - qisqa nom #

C
#include <stdio.h>
#include <string.h>

typedef struct {
    char ism[50];
    int yosh;
    double ortacha_baho;
} Talaba;

int main(void) {
    Talaba t = {"Husanboy Qodirov", 25, 4.6};   /* "struct" yozish shart emas */

    printf("%s, %d yosh, o'rtacha %.1f\n", t.ism, t.yosh, t.ortacha_baho);
    printf("Struktura hajmi: %zu bayt\n", sizeof(Talaba));

    return 0;
}
Natija
Husanboy Qodirov, 25 yosh, o'rtacha 4.6
Struktura hajmi: 64 bayt
Nima uchun 64, 62 emas?

char[50] + int(4) + double(8) = 62 bayt. Lekin natija 64.

Sababi - tekislash (alignment). Protsessor double ni 8 ga bo'linadigan manzildan o'qiganda tezroq ishlaydi. Shuning uchun kompilyator maydonlar orasiga bo'sh joy (padding) qo'shadi.

Maydonlar tartibini o'zgartirib, hajmni kamaytirish mumkin - katta ma'lumotlar bilan ishlaganda bu sezilarli farq beradi. Qoida: katta turlarni oldinga qo'ying.

Struktura bilan funksiyalar #

C
#include <stdio.h>
#include <string.h>

typedef struct {
    char ism[50];
    int yosh;
    double ortacha_baho;
} Talaba;

void chiqar(const Talaba *t) {
    printf("%-18s %3d yosh   %.2f\n", t->ism, t->yosh, t->ortacha_baho);
}

void tugilgan_kun(Talaba *t) {
    t->yosh++;
}

Talaba yarat(const char *ism, int yosh, double baho) {
    Talaba yangi;

    strncpy(yangi.ism, ism, sizeof(yangi.ism) - 1);
    yangi.ism[sizeof(yangi.ism) - 1] = '\0';
    yangi.yosh = yosh;
    yangi.ortacha_baho = baho;

    return yangi;
}

int main(void) {
    Talaba t = yarat("Husanboy Qodirov", 25, 4.6);

    chiqar(&t);
    tugilgan_kun(&t);
    chiqar(&t);

    return 0;
}
Natija
Husanboy Qodirov    25 yosh   4.60
Husanboy Qodirov    26 yosh   4.60
-> operatori
C
(*t).yosh      /* uzun shakl */
t->yosh        /* qisqa shakl - shuni ishlating */

Ikkalasi ham bir xil. -> ko'rsatkich orqali maydonga murojaat qilish uchun maxsus operator.

Qoida: oddiy o'zgaruvchi bilan ., ko'rsatkich bilan ->.

Strukturani qiymat bo'yicha uzatish - nusxa yaratadi
C
void chiqar(Talaba t);          /* 64 baytlik nusxa ko'chiriladi */
void chiqar(const Talaba *t);   /* faqat 8 baytlik manzil */

Katta strukturalar uchun doim ko'rsatkich uzating. O'zgartirmasangiz - const qo'shing.

Strukturalar massivi #

C
#include <stdio.h>

typedef struct {
    char ism[30];
    int yosh;
    double baho;
} Talaba;

int main(void) {
    Talaba guruh[] = {
        {"Husanboy Qodirov", 25, 4.60},
        {"Malika Yusupova",  21, 4.90},
        {"Nodira Sobirova",  24, 4.30},
        {"Aziza Tosheva",    22, 4.10},
        {"Bekzod Rasulov",   23, 3.20}
    };

    int soni = sizeof(guruh) / sizeof(guruh[0]);

    printf("%-18s %5s %6s\n", "Talaba", "Yosh", "Baho");
    printf("-------------------------------\n");

    double yigindi = 0.0;
    int eng_yaxshi = 0;

    for (int i = 0; i < soni; i++) {
        printf("%-18s %5d %6.2f\n", guruh[i].ism, guruh[i].yosh, guruh[i].baho);
        yigindi += guruh[i].baho;

        if (guruh[i].baho > guruh[eng_yaxshi].baho) {
            eng_yaxshi = i;
        }
    }

    printf("-------------------------------\n");
    printf("Guruh o'rtachasi : %.2f\n", yigindi / soni);
    printf("Eng yuqori baho  : %s (%.2f)\n",
           guruh[eng_yaxshi].ism, guruh[eng_yaxshi].baho);

    return 0;
}
Natija
Talaba              Yosh   Baho
-------------------------------
Husanboy Qodirov      25   4.60
Malika Yusupova       21   4.90
Nodira Sobirova       24   4.30
Aziza Tosheva         22   4.10
Bekzod Rasulov        23   3.20
-------------------------------
Guruh o'rtachasi : 4.22
Eng yuqori baho  : Malika Yusupova (4.90)

Ichma-ich strukturalar #

C
#include <stdio.h>

typedef struct {
    int kun;
    int oy;
    int yil;
} Sana;

typedef struct {
    char ism[40];
    Sana tugilgan;
    Sana royxatdan_otgan;
} Talaba;

void sana_chiqar(const char *nom, Sana s) {
    printf("%-18s: %02d.%02d.%d\n", nom, s.kun, s.oy, s.yil);
}

int main(void) {
    Talaba t = {
        .ism = "Husanboy Qodirov",
        .tugilgan = {15, 5, 2001},
        .royxatdan_otgan = {1, 9, 2026}
    };

    printf("Talaba: %s\n", t.ism);
    sana_chiqar("Tug'ilgan sana", t.tugilgan);
    sana_chiqar("Ro'yxatdan o'tgan", t.royxatdan_otgan);
    printf("Yoshi: %d\n", t.royxatdan_otgan.yil - t.tugilgan.yil);

    return 0;
}
Natija
Talaba: Husanboy Qodirov
Tug'ilgan sana    : 15.05.2001
Ro'yxatdan o'tgan : 01.09.2026
Yoshi: 25

enum - nomlangan doimiylar #

C
#include <stdio.h>

typedef enum {
    QORALAMA,
    KORIB_CHIQILMOQDA,
    CHOP_ETILGAN,
    ARXIVLANGAN
} Holat;

const char *holat_nomi(Holat h) {
    switch (h) {
        case QORALAMA:          return "Qoralama";
        case KORIB_CHIQILMOQDA: return "Ko'rib chiqilmoqda";
        case CHOP_ETILGAN:      return "Chop etilgan";
        case ARXIVLANGAN:       return "Arxivlangan";
        default:                return "Noma'lum";
    }
}

int main(void) {
    Holat holatlar[] = {QORALAMA, CHOP_ETILGAN, ARXIVLANGAN};

    for (int i = 0; i < 3; i++) {
        printf("%d -> %s\n", holatlar[i], holat_nomi(holatlar[i]));
    }

    return 0;
}
Natija
0 -> Qoralama
2 -> Chop etilgan
3 -> Arxivlangan
enum nima uchun raqamdan yaxshiroq?
C
if (holat == 2) { ... }              /* 2 nimani bildiradi? */
if (holat == CHOP_ETILGAN) { ... }   /* darhol tushunarli */

Qo'shimcha foyda: switch da barcha enum qiymatlarini qamramasangiz, -Wall bilan kompilyator ogohlantiradi. Bu yangi holat qo'shilganda uni hamma joyda hisobga olishga yordam beradi.

Qiymatlarni o'zingiz ham berishingiz mumkin:

C
typedef enum {
    OQISH   = 1,
    YOZISH  = 2,
    BAJARISH = 4
} Huquq;

union - bir xotira, turli turlar #

C
#include <stdio.h>
#include <string.h>

typedef union {
    int butun;
    double kasr;
    char matn[16];
} Qiymat;

int main(void) {
    Qiymat q;

    q.butun = 42;
    printf("Butun : %d\n", q.butun);

    q.kasr = 3.14;
    printf("Kasr  : %.2f\n", q.kasr);

    strcpy(q.matn, "salom");
    printf("Matn  : %s\n", q.matn);

    printf("union hajmi : %zu bayt\n", sizeof(Qiymat));

    return 0;
}
Natija
Butun : 42
Kasr  : 3.14
Matn  : salom
union hajmi : 16 bayt
union da bir vaqtda faqat bitta maydon amal qiladi

Barcha maydonlar bir xil xotirani bo'lishadi. q.kasr ga yozganingizda q.butun buziladi.

Oxirgi yozilgan maydondan boshqasini o'qish - aniqlanmagan xatti-harakat.

Shuning uchun union odatda teg bilan birga ishlatiladi:

C
typedef enum { BUTUN, KASR, MATN } Tur;

typedef struct {
    Tur tur;              /* qaysi maydon amal qilyapti */
    union {
        int butun;
        double kasr;
        char matn[16];
    } qiymat;
} Element;

union xotira juda cheklangan joylarda (mikrokontroller, tarmoq paketlari) ishlatiladi.

Struktura va dinamik xotira #

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

typedef struct {
    char ism[40];
    int yosh;
    double baho;
} Talaba;

int main(void) {
    int soni = 3;
    Talaba *guruh = malloc(soni * sizeof(*guruh));

    if (guruh == NULL) {
        return 1;
    }

    strcpy(guruh[0].ism, "Husanboy Qodirov");
    guruh[0].yosh = 25;
    guruh[0].baho = 4.6;

    strcpy(guruh[1].ism, "Malika Yusupova");
    guruh[1].yosh = 21;
    guruh[1].baho = 4.9;

    strcpy(guruh[2].ism, "Nodira Sobirova");
    guruh[2].yosh = 24;
    guruh[2].baho = 4.3;

    for (int i = 0; i < soni; i++) {
        printf("%d. %-18s %3d %.1f\n", i + 1,
               guruh[i].ism, guruh[i].yosh, guruh[i].baho);
    }

    free(guruh);
    return 0;
}
Natija
1. Husanboy Qodirov    25 4.6
2. Malika Yusupova     21 4.9
3. Nodira Sobirova     24 4.3

Bog'langan ro'yxat - strukturaning kuchi #

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

typedef struct Tugun {
    int qiymat;
    struct Tugun *keyingi;      /* o'ziga ko'rsatkich */
} Tugun;

Tugun *qosh(Tugun *bosh, int qiymat) {
    Tugun *yangi = malloc(sizeof(*yangi));

    if (yangi == NULL) {
        return bosh;
    }

    yangi->qiymat = qiymat;
    yangi->keyingi = bosh;      /* boshiga qo'shamiz */

    return yangi;
}

void chiqar(const Tugun *bosh) {
    for (const Tugun *t = bosh; t != NULL; t = t->keyingi) {
        printf("%d -> ", t->qiymat);
    }
    printf("NULL\n");
}

void ozod_qil(Tugun *bosh) {
    while (bosh != NULL) {
        Tugun *keyingi = bosh->keyingi;
        free(bosh);
        bosh = keyingi;
    }
}

int main(void) {
    Tugun *royxat = NULL;

    royxat = qosh(royxat, 30);
    royxat = qosh(royxat, 20);
    royxat = qosh(royxat, 10);

    chiqar(royxat);
    ozod_qil(royxat);

    return 0;
}
Natija
10 -> 20 -> 30 -> NULL
typedef struct Tugun dagi nom nima uchun kerak?
C
typedef struct Tugun {
    struct Tugun *keyingi;    /* shu yerda "Tugun" hali mavjud emas */
} Tugun;

typedef faqat blok tugagach kuchga kiradi. Shuning uchun struktura ichida o'ziga murojaat qilish uchun teg nomi (struct Tugun) kerak.

Bu o'ziga murojaat qiladigan tuzilmalar - bog'langan ro'yxat, daraxt, graf - uchun asos.

Amaliy topshiriq
  1. Kitob strukturasini yarating (nom, muallif, yil, narx).
  2. Uni to'ldirib, maydonlarini chiqaring.
  3. typedef bilan qisqa nom bering.
  4. Kitobni chiqaruvchi funksiya yozing (const ko'rsatkich bilan).
  5. Beshta kitobdan iborat massiv yarating.
  6. Eng qimmat kitobni toping.
  7. Sana strukturasini yaratib, uni Kitob ichiga joylang.
  8. sizeof bilan struktura hajmini o'lchang va tekislashni tushuntiring.
  9. Kitob holati uchun enum yarating.
  10. malloc bilan dinamik kitoblar ro'yxatini yarating va ozod qiling.

Xulosa #

  • Struktura - turli turdagi ma'lumotlarni bitta nom ostida birlashtiradi.
  • Maydonga . orqali, ko'rsatkich orqali esa -> bilan murojaat qilinadi.
  • typedef struct so'zini yozishdan xalos qiladi.
  • Nom bo'yicha e'lon (.ism = "...") tartibdan mustaqil va xavfsizroq.
  • Struktura hajmi maydonlar yig'indisidan katta bo'lishi mumkin - bu tekislash tufayli.
  • Katta strukturalarni funksiyaga ko'rsatkich orqali uzating.
  • enum raqamlarga nom beradi va switch bilan yaxshi ishlaydi.
  • union bir xotirani bo'lishadi - bir vaqtda faqat bitta maydon amal qiladi.
  • Struktura o'ziga ko'rsatkich saqlashi mumkin - bu bog'langan ro'yxat asosi.

Keyingi bo'limda fayllar bilan ishlashni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.