15-bo‘lim
Strukturalar
struct bilan o'z ma'lumot turingizni yaratish, typedef, ichma-ich strukturalar, strukturalar massivi, union va enum.
Ushbu bo‘lim mundarijasi
- Nima uchun struktura kerak?
- Struktura yaratish va ishlatish
- Boshlang'ich qiymat berish
- typedef - qisqa nom
- Struktura bilan funksiyalar
- Strukturalar massivi
- Ichma-ich strukturalar
- enum - nomlangan doimiylar
- union - bir xotira, turli turlar
- Struktura va dinamik xotira
- Bog'langan ro'yxat - strukturaning kuchi
- Xulosa
Struktura - turli turdagi ma'lumotlarni bitta nom ostida birlashtiradi. Bu C da o'z ma'lumot turingizni yaratish usuli.
Nima uchun struktura kerak? #
/* 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];
};
Struktura yaratish va ishlatish #
#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;
}
Ism : Husanboy Qodirov
Yosh : 25
Baho : 4.6
Shahar : Namangan
strcpy kerak - = ishlamaydibirinchi.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 #
#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;
}
Husanboy Qodirov 25 4.6
Malika Yusupova 21 4.9
Bo'sh: "" 0 0.0
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 #
#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;
}
Husanboy Qodirov, 25 yosh, o'rtacha 4.6
Struktura hajmi: 64 bayt
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 #
#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;
}
Husanboy Qodirov 25 yosh 4.60
Husanboy Qodirov 26 yosh 4.60
-> operatori(*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 ->.
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 #
#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;
}
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 #
#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;
}
Talaba: Husanboy Qodirov
Tug'ilgan sana : 15.05.2001
Ro'yxatdan o'tgan : 01.09.2026
Yoshi: 25
enum - nomlangan doimiylar #
#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;
}
0 -> Qoralama
2 -> Chop etilgan
3 -> Arxivlangan
enum nima uchun raqamdan yaxshiroq?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:
typedef enum {
OQISH = 1,
YOZISH = 2,
BAJARISH = 4
} Huquq;
union - bir xotira, turli turlar #
#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;
}
Butun : 42
Kasr : 3.14
Matn : salom
union hajmi : 16 bayt
union da bir vaqtda faqat bitta maydon amal qiladiBarcha 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:
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 #
#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;
}
1. Husanboy Qodirov 25 4.6
2. Malika Yusupova 21 4.9
3. Nodira Sobirova 24 4.3
Bog'langan ro'yxat - strukturaning kuchi #
#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;
}
10 -> 20 -> 30 -> NULL
typedef struct Tugun dagi nom nima uchun kerak?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.
Kitobstrukturasini yarating (nom, muallif, yil, narx).- Uni to'ldirib, maydonlarini chiqaring.
typedefbilan qisqa nom bering.- Kitobni chiqaruvchi funksiya yozing (
constko'rsatkich bilan). - Beshta kitobdan iborat massiv yarating.
- Eng qimmat kitobni toping.
Sanastrukturasini yaratib, uniKitobichiga joylang.sizeofbilan struktura hajmini o'lchang va tekislashni tushuntiring.- Kitob holati uchun
enumyarating. mallocbilan 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. typedefstructso'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.
enumraqamlarga nom beradi vaswitchbilan yaxshi ishlaydi.unionbir 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.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.