20-bo‘lim
Amaliy loyiha - talabalar bazasi
Darslikda o'rganilgan hamma narsani birlashtirib, dinamik xotira, strukturalar va fayllar bilan ishlaydigan to'liq dastur yozamiz.
Ushbu bo‘lim mundarijasi
Endi bilimlarni bir joyga to'playmiz. Biz talabalar bazasi yaratamiz - u yozuv qo'shadi, qidiradi, saralaydi va faylga saqlaydi.
Loyiha talablari #
| Imkoniyat | Qaysi bo'limdan |
|---|---|
| Talaba qo'shish | Strukturalar (15) |
| Ro'yxatni ko'rish | Massivlar (9), printf (5) |
| Ism bo'yicha qidirish | Satrlar (10) |
| Baho bo'yicha saralash | qsort (18) |
| O'chirish | Ko'rsatkichlar (12) |
| Faylga saqlash va yuklash | Fayllar (16) |
| Cheksiz ko'p yozuv | Dinamik xotira (14) |
| Menyu | Sikllar (8), switch (7) |
Loyiha tuzilishi #
talabalar/
├── Makefile
├── talaba.h e'lonlar
├── talaba.c ma'lumot bilan ishlash
└── main.c menyu va foydalanuvchi bilan muloqot
talaba.h #
#ifndef TALABA_H
#define TALABA_H
#include <stddef.h>
#define MAKS_ISM 60
#define MAKS_SHAHAR 40
typedef struct {
int id;
char ism[MAKS_ISM];
char shahar[MAKS_SHAHAR];
int yosh;
double baho;
} Talaba;
/* O'sib boruvchi talabalar ro'yxati. */
typedef struct {
Talaba *elementlar;
size_t soni;
size_t sigim;
int keyingi_id;
} Baza;
typedef enum {
OK = 0,
XATO_XOTIRA,
XATO_FAYL,
XATO_TOPILMADI,
XATO_ARGUMENT
} Natija;
const char *natija_matni(Natija n);
/* Bazani boshlang'ich holatga keltiradi. */
Natija baza_yarat(Baza *b);
/* Baza egallagan barcha xotirani ozod qiladi. */
void baza_ozod(Baza *b);
/* Yangi talaba qo'shadi va unga id beradi. */
Natija baza_qosh(Baza *b, const char *ism, const char *shahar,
int yosh, double baho);
/* id bo'yicha o'chiradi. */
Natija baza_ochir(Baza *b, int id);
/* Ism bo'yicha qidiradi (qismiy moslik). Topilganlar sonini qaytaradi. */
size_t baza_qidir(const Baza *b, const char *matn);
/* Baho bo'yicha kamayish tartibida saralaydi. */
void baza_sarala_baho(Baza *b);
/* Ism bo'yicha alifbo tartibida saralaydi. */
void baza_sarala_ism(Baza *b);
/* Butun ro'yxatni jadval ko'rinishida chiqaradi. */
void baza_chiqar(const Baza *b);
/* Statistikani chiqaradi. */
void baza_statistika(const Baza *b);
/* CSV faylga saqlaydi va undan yuklaydi. */
Natija baza_saqla(const Baza *b, const char *fayl_nomi);
Natija baza_yukla(Baza *b, const char *fayl_nomi);
#endif /* TALABA_H */
talaba.c #
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "talaba.h"
#define BOSHLANGICH_SIGIM 4
const char *natija_matni(Natija n) {
switch (n) {
case OK: return "Bajarildi";
case XATO_XOTIRA: return "Xotira yetmadi";
case XATO_FAYL: return "Fayl bilan ishlashda xato";
case XATO_TOPILMADI: return "Topilmadi";
case XATO_ARGUMENT: return "Noto'g'ri argument";
default: return "Noma'lum xato";
}
}
Natija baza_yarat(Baza *b) {
if (b == NULL) {
return XATO_ARGUMENT;
}
b->elementlar = malloc(BOSHLANGICH_SIGIM * sizeof(*b->elementlar));
if (b->elementlar == NULL) {
return XATO_XOTIRA;
}
b->soni = 0;
b->sigim = BOSHLANGICH_SIGIM;
b->keyingi_id = 1;
return OK;
}
void baza_ozod(Baza *b) {
if (b == NULL) {
return;
}
free(b->elementlar);
b->elementlar = NULL;
b->soni = 0;
b->sigim = 0;
}
/* Kerak bo'lsa sig'imni ikki barobar oshiradi. */
static Natija sigimni_tekshir(Baza *b) {
if (b->soni < b->sigim) {
return OK;
}
size_t yangi_sigim = b->sigim * 2;
Talaba *yangi = realloc(b->elementlar, yangi_sigim * sizeof(*yangi));
if (yangi == NULL) {
return XATO_XOTIRA;
}
b->elementlar = yangi;
b->sigim = yangi_sigim;
return OK;
}
Natija baza_qosh(Baza *b, const char *ism, const char *shahar,
int yosh, double baho) {
if (b == NULL || ism == NULL || shahar == NULL) {
return XATO_ARGUMENT;
}
if (yosh < 14 || yosh > 120 || baho < 0.0 || baho > 5.0) {
return XATO_ARGUMENT;
}
Natija n = sigimni_tekshir(b);
if (n != OK) {
return n;
}
Talaba *t = &b->elementlar[b->soni];
t->id = b->keyingi_id++;
snprintf(t->ism, sizeof(t->ism), "%s", ism);
snprintf(t->shahar, sizeof(t->shahar), "%s", shahar);
t->yosh = yosh;
t->baho = baho;
b->soni++;
return OK;
}
Natija baza_ochir(Baza *b, int id) {
if (b == NULL) {
return XATO_ARGUMENT;
}
for (size_t i = 0; i < b->soni; i++) {
if (b->elementlar[i].id == id) {
/* oxirgi elementni bo'shagan joyga ko'chiramiz */
b->elementlar[i] = b->elementlar[b->soni - 1];
b->soni--;
return OK;
}
}
return XATO_TOPILMADI;
}
size_t baza_qidir(const Baza *b, const char *matn) {
if (b == NULL || matn == NULL) {
return 0;
}
size_t topilgan = 0;
for (size_t i = 0; i < b->soni; i++) {
if (strstr(b->elementlar[i].ism, matn) != NULL ||
strstr(b->elementlar[i].shahar, matn) != NULL) {
if (topilgan == 0) {
printf(" %-4s %-20s %-12s %5s %6s\n",
"ID", "Ism", "Shahar", "Yosh", "Baho");
printf(" --------------------------------------------------\n");
}
const Talaba *t = &b->elementlar[i];
printf(" %-4d %-20s %-12s %5d %6.2f\n",
t->id, t->ism, t->shahar, t->yosh, t->baho);
topilgan++;
}
}
return topilgan;
}
static int baho_boyicha(const void *a, const void *b) {
const Talaba *x = a;
const Talaba *y = b;
if (x->baho < y->baho) return 1; /* kamayish tartibi */
if (x->baho > y->baho) return -1;
return 0;
}
static int ism_boyicha(const void *a, const void *b) {
const Talaba *x = a;
const Talaba *y = b;
return strcmp(x->ism, y->ism);
}
void baza_sarala_baho(Baza *b) {
if (b != NULL && b->soni > 1) {
qsort(b->elementlar, b->soni, sizeof(*b->elementlar), baho_boyicha);
}
}
void baza_sarala_ism(Baza *b) {
if (b != NULL && b->soni > 1) {
qsort(b->elementlar, b->soni, sizeof(*b->elementlar), ism_boyicha);
}
}
void baza_chiqar(const Baza *b) {
if (b == NULL || b->soni == 0) {
printf(" Baza bo'sh.\n");
return;
}
printf(" %-4s %-20s %-12s %5s %6s\n", "ID", "Ism", "Shahar", "Yosh", "Baho");
printf(" --------------------------------------------------\n");
for (size_t i = 0; i < b->soni; i++) {
const Talaba *t = &b->elementlar[i];
printf(" %-4d %-20s %-12s %5d %6.2f\n",
t->id, t->ism, t->shahar, t->yosh, t->baho);
}
printf(" --------------------------------------------------\n");
printf(" Jami: %zu ta talaba\n", b->soni);
}
void baza_statistika(const Baza *b) {
if (b == NULL || b->soni == 0) {
printf(" Statistika uchun ma'lumot yo'q.\n");
return;
}
double yigindi = 0.0;
size_t eng_yaxshi = 0;
size_t eng_past = 0;
int yosh_yigindi = 0;
for (size_t i = 0; i < b->soni; i++) {
yigindi += b->elementlar[i].baho;
yosh_yigindi += b->elementlar[i].yosh;
if (b->elementlar[i].baho > b->elementlar[eng_yaxshi].baho) {
eng_yaxshi = i;
}
if (b->elementlar[i].baho < b->elementlar[eng_past].baho) {
eng_past = i;
}
}
printf(" Talabalar soni : %zu\n", b->soni);
printf(" O'rtacha baho : %.2f\n", yigindi / (double) b->soni);
printf(" O'rtacha yosh : %.1f\n", (double) yosh_yigindi / (double) b->soni);
printf(" Eng yuqori baho : %s (%.2f)\n",
b->elementlar[eng_yaxshi].ism, b->elementlar[eng_yaxshi].baho);
printf(" Eng past baho : %s (%.2f)\n",
b->elementlar[eng_past].ism, b->elementlar[eng_past].baho);
printf(" Xotira sig'imi : %zu (ishlatilgan: %zu)\n", b->sigim, b->soni);
}
Natija baza_saqla(const Baza *b, const char *fayl_nomi) {
if (b == NULL || fayl_nomi == NULL) {
return XATO_ARGUMENT;
}
FILE *f = fopen(fayl_nomi, "w");
if (f == NULL) {
return XATO_FAYL;
}
for (size_t i = 0; i < b->soni; i++) {
const Talaba *t = &b->elementlar[i];
fprintf(f, "%d;%s;%s;%d;%.2f\n",
t->id, t->ism, t->shahar, t->yosh, t->baho);
}
fclose(f);
return OK;
}
Natija baza_yukla(Baza *b, const char *fayl_nomi) {
if (b == NULL || fayl_nomi == NULL) {
return XATO_ARGUMENT;
}
FILE *f = fopen(fayl_nomi, "r");
if (f == NULL) {
return XATO_FAYL;
}
char qator[256];
int eng_katta_id = 0;
while (fgets(qator, sizeof(qator), f) != NULL) {
qator[strcspn(qator, "\n")] = '\0';
char *id_matni = strtok(qator, ";");
char *ism = strtok(NULL, ";");
char *shahar = strtok(NULL, ";");
char *yosh_matni = strtok(NULL, ";");
char *baho_matni = strtok(NULL, ";");
if (id_matni == NULL || ism == NULL || shahar == NULL ||
yosh_matni == NULL || baho_matni == NULL) {
continue; /* buzilgan qatorni tashlaymiz */
}
if (baza_qosh(b, ism, shahar, atoi(yosh_matni), atof(baho_matni)) != OK) {
continue;
}
int id = atoi(id_matni);
b->elementlar[b->soni - 1].id = id; /* asl id ni tiklaymiz */
if (id > eng_katta_id) {
eng_katta_id = id;
}
}
fclose(f);
b->keyingi_id = eng_katta_id + 1;
return OK;
}
main.c #
#include <stdio.h>
#include <string.h>
#include "talaba.h"
#define FAYL "talabalar.csv"
static void sarlavha(const char *matn) {
printf("\n=== %s ===\n", matn);
}
int main(void) {
Baza baza;
if (baza_yarat(&baza) != OK) {
fprintf(stderr, "Bazani yaratib bo'lmadi\n");
return 1;
}
/* 1. Ma'lumot qo'shamiz */
sarlavha("Talabalar qo'shilmoqda");
baza_qosh(&baza, "Husanboy Qodirov", "Namangan", 25, 4.60);
baza_qosh(&baza, "Malika Yusupova", "Buxoro", 21, 4.90);
baza_qosh(&baza, "Nodira Sobirova", "Samarqand", 24, 4.30);
baza_qosh(&baza, "Aziza Tosheva", "Xiva", 22, 4.10);
baza_qosh(&baza, "Bekzod Rasulov", "Toshkent", 23, 3.20);
baza_qosh(&baza, "Jasur Xolmatov", "Andijon", 22, 3.50);
printf(" %zu ta talaba qo'shildi.\n", baza.soni);
/* noto'g'ri ma'lumot rad etiladi */
Natija n = baza_qosh(&baza, "Xato Yozuv", "Namangan", 5, 4.0);
printf(" Noto'g'ri yosh: %s\n", natija_matni(n));
/* 2. Ro'yxat */
sarlavha("Barcha talabalar");
baza_chiqar(&baza);
/* 3. Saralash */
sarlavha("Baho bo'yicha (kamayish)");
baza_sarala_baho(&baza);
baza_chiqar(&baza);
/* 4. Qidiruv */
sarlavha("Qidiruv: \"ova\"");
size_t topilgan = baza_qidir(&baza, "ova");
printf(" %zu ta natija topildi.\n", topilgan);
sarlavha("Qidiruv: \"Namangan\"");
topilgan = baza_qidir(&baza, "Namangan");
printf(" %zu ta natija topildi.\n", topilgan);
/* 5. Statistika */
sarlavha("Statistika");
baza_statistika(&baza);
/* 6. O'chirish */
sarlavha("5-idli talabani o'chirish");
n = baza_ochir(&baza, 5);
printf(" Natija: %s\n", natija_matni(n));
n = baza_ochir(&baza, 999);
printf(" Mavjud bo'lmagan id: %s\n", natija_matni(n));
/* 7. Saqlash */
sarlavha("Faylga saqlash");
n = baza_saqla(&baza, FAYL);
printf(" %s (%s)\n", natija_matni(n), FAYL);
/* 8. Qayta yuklash */
sarlavha("Yangi bazaga yuklash");
Baza ikkinchi;
if (baza_yarat(&ikkinchi) == OK) {
n = baza_yukla(&ikkinchi, FAYL);
printf(" %s\n", natija_matni(n));
baza_sarala_ism(&ikkinchi);
baza_chiqar(&ikkinchi);
baza_ozod(&ikkinchi);
}
baza_ozod(&baza);
return 0;
}
Natija #
=== Talabalar qo'shilmoqda ===
6 ta talaba qo'shildi.
Noto'g'ri yosh: Noto'g'ri argument
=== Barcha talabalar ===
ID Ism Shahar Yosh Baho
--------------------------------------------------
1 Husanboy Qodirov Namangan 25 4.60
2 Malika Yusupova Buxoro 21 4.90
3 Nodira Sobirova Samarqand 24 4.30
4 Aziza Tosheva Xiva 22 4.10
5 Bekzod Rasulov Toshkent 23 3.20
6 Jasur Xolmatov Andijon 22 3.50
--------------------------------------------------
Jami: 6 ta talaba
=== Baho bo'yicha (kamayish) ===
ID Ism Shahar Yosh Baho
--------------------------------------------------
2 Malika Yusupova Buxoro 21 4.90
1 Husanboy Qodirov Namangan 25 4.60
3 Nodira Sobirova Samarqand 24 4.30
4 Aziza Tosheva Xiva 22 4.10
6 Jasur Xolmatov Andijon 22 3.50
5 Bekzod Rasulov Toshkent 23 3.20
--------------------------------------------------
Jami: 6 ta talaba
=== Qidiruv: "ova" ===
ID Ism Shahar Yosh Baho
--------------------------------------------------
2 Malika Yusupova Buxoro 21 4.90
3 Nodira Sobirova Samarqand 24 4.30
2 ta natija topildi.
=== Qidiruv: "Namangan" ===
ID Ism Shahar Yosh Baho
--------------------------------------------------
1 Husanboy Qodirov Namangan 25 4.60
1 ta natija topildi.
=== Statistika ===
Talabalar soni : 6
O'rtacha baho : 4.10
O'rtacha yosh : 22.8
Eng yuqori baho : Malika Yusupova (4.90)
Eng past baho : Bekzod Rasulov (3.20)
Xotira sig'imi : 8 (ishlatilgan: 6)
=== 5-idli talabani o'chirish ===
Natija: Bajarildi
Mavjud bo'lmagan id: Topilmadi
=== Faylga saqlash ===
Bajarildi (talabalar.csv)
=== Yangi bazaga yuklash ===
Bajarildi
ID Ism Shahar Yosh Baho
--------------------------------------------------
4 Aziza Tosheva Xiva 22 4.10
1 Husanboy Qodirov Namangan 25 4.60
6 Jasur Xolmatov Andijon 22 3.50
2 Malika Yusupova Buxoro 21 4.90
3 Nodira Sobirova Samarqand 24 4.30
--------------------------------------------------
Jami: 5 ta talaba
Makefile #
CC = gcc
CFLAGS = -std=c17 -Wall -Wextra -g
NOSOZLIK = -fsanitize=address,undefined
MAQSAD = talabalar
OBYEKTLAR = main.o talaba.o
all: $(MAQSAD)
$(MAQSAD): $(OBYEKTLAR)
$(CC) $(CFLAGS) $(OBYEKTLAR) -o $@
main.o: main.c talaba.h
$(CC) $(CFLAGS) -c main.c -o $@
talaba.o: talaba.c talaba.h
$(CC) $(CFLAGS) -c talaba.c -o $@
nosozlik: tozala
$(CC) $(CFLAGS) $(NOSOZLIK) main.c talaba.c -o $(MAQSAD)
./$(MAQSAD)
tozala:
rm -f $(OBYEKTLAR) $(MAQSAD) talabalar.csv
ishga: $(MAQSAD)
./$(MAQSAD)
.PHONY: all nosozlik tozala ishga
make # yig'ish
make ishga # ishga tushirish
make nosozlik # sanitizer bilan tekshirish
make tozala # tozalash
Loyihada qo'llanilgan qarorlar #
1. Baza strukturasi
Massiv, uning hajmi va sig'imi bitta strukturada. Shunday qilib har bir funksiyaga uchta alohida parametr uzatish shart emas.
2. Sig'imni ikki barobar oshirish
sigimni_tekshir faqat joy tugaganda realloc chaqiradi. Har bir
qo'shishda emas - bu ancha tez.
3. O'chirishda oxirgi elementni ko'chirish
b->elementlar[i] = b->elementlar[b->soni - 1];
b->soni--;
Barcha elementlarni siljitish O(n) bo'lardi. Oxirgisini bo'shagan
joyga qo'yish esa O(1). Bunda tartib buziladi, lekin bizga tartib
kerak bo'lganda qsort bor.
4. snprintf bilan nusxalash
strcpy o'rniga - hajmdan oshib ketmaydi va nolni doim qo'yadi.
5. Natija enum'i
Har bir funksiya nima uchun muvaffaqiyatsiz bo'lganini aytadi.
natija_matni esa uni o'qishli matnga aylantiradi.
6. static yordamchi funksiyalar
sigimni_tekshir, baho_boyicha, ism_boyicha - faqat talaba.c
ichida kerak. Ular sarlavhada e'lon qilinmagan.
7. Har bir kirish nuqtasida tekshiruv
if (b == NULL) return XATO_ARGUMENT; - kutubxona funksiyasi
noto'g'ri chaqiruvdan qulamasligi kerak.
Xotira tekshiruvi #
gcc -std=c17 -Wall -Wextra -g -fsanitize=address,undefined \
main.c talaba.c -o talabalar
./talabalar
Sanitizer hech qanday xabar bermasa, xotira to'g'ri boshqarilgan.
valgrind --leak-check=full ./talabalar
==12345== HEAP SUMMARY:
==12345== in use at exit: 0 bytes in 0 blocks
==12345== total heap usage: 5 allocs, 5 frees, 1,984 bytes allocated
==12345==
==12345== All heap blocks were freed -- no leaks are possible
Bu - C dasturchisi uchun eng yoqimli xabar. U har bir malloc uchun
mos free bo'lganini bildiradi.
Loyihangizni topshirishdan oldin doim shu tekshiruvni o'tkazing.
Loyihani kengaytirish #
Loyihani bosqichma-bosqich kengaytiring:
- Interaktiv menyu qo'shing -
fgetsbilan foydalanuvchidan tanlov o'qing. - Tahrirlash funksiyasini yozing (
baza_tahrir). - Yosh bo'yicha saralash qo'shing.
- Shahar bo'yicha filtr yozing - faqat berilgan shahar talabalarini chiqaring.
- Baho oralig'i bo'yicha qidiruv qo'shing (masalan 4.0 - 5.0).
bsearchbilan id bo'yicha tez qidiruv - avval id bo'yicha saralang.- Ikkilik faylga saqlash variantini qo'shing va CSV bilan solishtiring.
- Har bir shahar bo'yicha statistika chiqaring (
GROUP BYkabi). - Buyruq qatori argumentlari - fayl nomini
argvdan oling. - Sanitizer va valgrind bilan tekshiring - hech qanday xato qolmasin.
Darslik yakuni #
C ni chuqurlashtirish:
- Bog'langan ro'yxat, stek, navbat, xesh jadval, daraxtlarni C da yozing
- Modul testlarini yozishni o'rganing
- Ochiq kodli loyihalarni o'qing: SQLite, Redis, curl
Tizim dasturlash:
- POSIX API:
open,read,write,fork,pipe - Soketlar bilan tarmoq dasturlash
- Ko'p oqimlilik (
pthread)
Yaqin tillar:
- C++ - C ustiga qurilgan, obyektga yo'naltirilgan
- Rust - C ning tezligi, lekin xotira xavfsizligi kafolati bilan
- Go - tizim dasturlash uchun soddaroq til
Kitoblar:
- «The C Programming Language» (K&R) - klassika
- «C Programming: A Modern Approach» - batafsil darslik
- «Expert C Programming» - chuqur tafsilotlar
Eng muhimi: o'z loyihangizni yozing. Kichik bo'lsa ham - matn muharriri, kalkulyator, o'yin. Nazariya amaliyotsiz tez unutiladi.
Xulosa #
- Loyihani
.hva.cfayllarga bo'ling - e'lonlar va amalga oshirish alohida. - O'sib boruvchi massiv sig'imni ikki barobar oshirish bilan quriladi.
- O'chirishda oxirgi elementni ko'chirish
O(1)beradi. - Har bir funksiya
NULLargumentga tayyor bo'lsin. - Xatolarni
enumbilan qaytaring, matnini alohida funksiya bersin. - Faqat ichki funksiyalarni
staticqiling. strcpyo'rnigasnprintf.- Loyihani topshirishdan oldin sanitizer va valgrind bilan tekshiring.
- «All heap blocks were freed» - maqsadga yetganingizning belgisi.
Darslik tugadi. C ni bilish - kompyuter qanday ishlashini bilish demakdir. Bu bilim boshqa har qanday tilni o'rganishda sizga umr bo'yi yordam beradi.
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.