8-dars: Pointer, massiv va string
Dars haqida
Davomiyligi: 90 daqiqa Maqsad: Talaba pointer va massiv bog'liqligini chuqur tushunishi, dinamik xotira (malloc/free) bilan ishlashi va string funksiyalarining pointer orqali qanday ishlashini bilishi kerak.
O'tgan darsda (7-dars) pointer asoslarini o'rgandik: &, *, NULL, pass by reference. Bugun pointer'ning eng katta ish maydoni — massiv va string.
1. Massiv = pointer
int arr[5] = {10, 20, 30, 40, 50};
// Bu ikkalasi bir xil:
printf("%d\n", arr[0]); // 10
printf("%d\n", *arr); // 10
// Bu ham:
printf("%d\n", arr[2]); // 30
printf("%d\n", *(arr + 2)); // 30Aslida arr[i] = *(arr + i) — compiler shunday o'qiydi.
Pointer'ni massiv kabi ishlatish ham mumkin:
int *p = arr; // & kerak emas — arr o'zi birinchi element manzili
printf("%d\n", p[0]); // 10
printf("%d\n", p[2]); // 30
printf("%d\n", *(p + 3)); // 402. Massiv va pointer farqi
int arr[5];
int *p;
sizeof(arr); // 20 (5 * 4) — massiv hajmi
sizeof(p); // 8 — pointer hajmi
arr = NULL; // XATO — massiv nomi const
p = NULL; // OK — pointerMassiv nomi — const pointer (manzilni o'zgartirib bo'lmaydi).
3. Massiv funksiyaga — faqat pointer
void print_array(int arr[], int n) { ... } // arr aslida int*
void print_array(int *arr, int n) { ... } // bir xil — ikkalasi ham ishlaydiint arr[] = int *arr (C uchun farqi yo'q). Shuning uchun funksiya ichida sizeof ishlamaydi:
void func(int arr[10]) {
printf("%zu\n", sizeof(arr)); // 8 — pointer hajmi!
}
int main(void) {
int arr[10];
printf("%zu\n", sizeof(arr)); // 40 — massiv hajmi
func(arr);
return 0;
}Funksiya massiv hajmini bilmaydi — doim n parametr sifatida uzating.
4. Pointer arithmetic — massiv bo'ylab yurish
int arr[] = {10, 20, 30, 40, 50};
int *p = arr;
while (p < arr + 5) {
printf("%d ", *p);
p++; // keyingi elementga
}
// 10 20 30 40 50Yig'indi — faqat pointer bilan:
int sum(int *start, int *end) {
int total = 0;
while (start < end) {
total += *start;
start++;
}
return total;
}
// Chaqirish
int arr[] = {1, 2, 3, 4, 5};
int s = sum(arr, arr + 5); // 155. malloc — dinamik xotira
Oddiy massiv hajmi kompilatsiya vaqtida ma'lum bo'lishi kerak. Dinamik — ish vaqtida aniqlanadi:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("Necha element: ");
scanf("%d", &n);
int *arr = malloc(n * sizeof(int)); // n ta int uchun joy
if (arr == NULL) {
printf("Xotira yetmadi\n");
return 1;
}
for (int i = 0; i < n; i++) {
arr[i] = i * 10; // oddiy massiv kabi ishlatiladi
}
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
arr = NULL; // xavfsizlik uchun
return 0;
}malloc → free
malloc'dan keyin doim free kerak. Aks holda — memory leak. Kichik dasturlarda OS bo'shatadi, lekin uzoq ishlovchi dasturlarda RAM tugab qoladi.
6. calloc va realloc
int *a = calloc(100, sizeof(int)); // 100 ta int, hammasi 0
int *b = malloc(100 * sizeof(int)); // 100 ta int, axlat qiymatlar
// Hajmni o'zgartirish:
b = realloc(b, 200 * sizeof(int)); // endi 200 ta elementcalloc — biroz sekinroq, lekin xavfsizroq (0 bilan to'ldirilgan).
7. Memory xatolari
Use after free
int *p = malloc(10 * sizeof(int));
free(p);
*p = 42; // CRASH — yo'q joyga yozishDouble free
free(p);
free(p); // CRASH yoki noma'lum xato
// Yechim:
free(p);
p = NULL; // ikkinchi free xavfsiz bo'ladiMemory leak
int *p = malloc(100);
p = malloc(200); // Birinchisi yo'qoldi!Tool'lar: Valgrind (Linux, valgrind ./program), AddressSanitizer (gcc -fsanitize=address).
8. String — char pointer ko'zi bilan
String = char massivi + \0. Demak string bilan ishlash = char pointer bilan yurish:
char str[] = "Hello";
char *p = str;
while (*p != '\0') {
putchar(*p);
p++;
}
// HelloPointer massivi — stringlar ro'yxati:
char *names[] = {"Akmal", "Aziza", "Botir", "Dilshod"};
for (int i = 0; i < 4; i++) {
printf("%s\n", names[i]);
}String va malloc:
char *str = malloc(100);
strcpy(str, "Hello");
printf("%s\n", str);
free(str);9. string.h funksiyalari ichida nima bor?
2-darsda strlen, strcpy, strcmp, strcat ni ishlatgan edik. Endi ular ichida qanday ishlashini ko'ramiz — hammasi pointer:
my_strlen
size_t my_strlen(const char *s) {
size_t len = 0;
while (*s != '\0') {
len++;
s++;
}
return len;
}my_strcpy
char *my_strcpy(char *dst, const char *src) {
char *start = dst;
while ((*dst++ = *src++) != '\0');
return start;
}(*dst++ = *src++) — klassik C idiomasi: belgini nusxalash, ikkala pointerni surish, \0 nusxalanganda to'xtash.
my_strcat
char *my_strcat(char *dst, const char *src) {
char *start = dst;
while (*dst != '\0') dst++; // oxiriga borish
while ((*dst++ = *src++) != '\0'); // nusxalash
return start;
}my_strcmp
int my_strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(unsigned char*)s1 - *(unsigned char*)s2;
}strlen tezligi — O(n)
Har chaqirishda oxirigacha o'tadi. Sikl shartida chaqirmang:
for (int i = 0; i < strlen(str); i++) { // SEKIN — har iteration'da qayta hisob
}
int len = strlen(str);
for (int i = 0; i < len; i++) { // TEZ — bir marta hisoblandi
}10. Pointer qaytaruvchi funksiyalar: strchr, strstr
char str[] = "Hello World";
char *p = strchr(str, 'W'); // 'W' ga pointer (str + 6)
printf("%s\n", p); // "World"
char *p2 = strstr(str, "World"); // substring boshlanishiga pointer
char *p3 = strstr(str, "xyz"); // NULL — topilmadiNatija — string ichiga pointer. Topilmasa — NULL (doim tekshiring).
11. strtok — bo'lish
char str[] = "apple,banana,orange";
char *token = strtok(str, ",");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, ","); // ikkinchidan boshlab — NULL
}strtok original'ni o'zgartiradi
strtok — , o'rniga \0 qo'yadi. Original string buziladi. Kerak bo'lsa — avval nusxa oling.
12. String algoritmlari — pointer bilan
Reverse (pointer versiyasi)
void reverse(char *s) {
char *end = s;
while (*end) end++; // oxiriga borish
end--; // \0 dan bitta oldin
while (s < end) {
char t = *s;
*s = *end;
*end = t;
s++;
end--;
}
}2-darsda index bilan yozgan edik — pointer versiyasi ixchamroq.
Anagram tekshirish
Anagram — bir xil harflardan tuzilgan ikki so'z (listen va silent):
int is_anagram(const char *s1, const char *s2) {
if (strlen(s1) != strlen(s2)) return 0;
int count[256] = {0};
while (*s1) {
count[(unsigned char)*s1]++;
s1++;
}
while (*s2) {
count[(unsigned char)*s2]--;
if (count[(unsigned char)*s2] < 0) return 0;
s2++;
}
return 1;
}String massivi sort
strcmp bilan taqqoslash, strcpy bilan swap (5-darsdagi bubble sort + string):
void sort_strings(char arr[][50], int n) {
char temp[50];
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (strcmp(arr[j], arr[j+1]) > 0) {
strcpy(temp, arr[j]);
strcpy(arr[j], arr[j+1]);
strcpy(arr[j+1], temp);
}
}
}
}13. Xavfsiz input: fgets, sscanf, snprintf
scanf("%s", ...) — bo'shliqgacha o'qiydi. To'liq qator uchun — fgets:
char buffer[100];
fgets(buffer, sizeof(buffer), stdin);
buffer[strcspn(buffer, "\n")] = '\0'; // \n ni olib tashlashKeyin sscanf bilan tahlil:
char input[] = "Akmal 22 Toshkent";
char name[50], city[50];
int age;
sscanf(input, "%s %d %s", name, &age, city);snprintf — buffer'ga xavfsiz yozish (overflow yo'q):
char buffer[100];
snprintf(buffer, sizeof(buffer), "Yosh: %d, Ism: %s", 22, "Akmal");Darsdagi topshiriqlar
Topshiriq 1 — Pointer va massiv
pointer-array.c — bitta massivni 4 xil usulda chiqaring: arr[i], *(arr + i), p[i] va *(p + i) (bu yerda p — massivga ishora qiluvchi pointer). To'rtala usul ham bir xil natija berishiga ishonch hosil qiling.
Topshiriq 2 — Dinamik massiv
dynamic-input.c — foydalanuvchi N kiritsin, malloc bilan joy ajrating, N ta raqam oling va statistika (sum, max, min, avg) chiqaring. Oxirida free.
Topshiriq 3 — Realloc
realloc.c — o'suvchi massiv (vektor tushunchasi) yozing: kichik capacity bilan boshlang, har safar element qo'shganda size ni oshiring va size capacity ga yetganda realloc bilan hajmni ikki barobarga oshiring. Kamida 10 ta element qo'shib, natijani chiqaring va oxirida free qiling.
Topshiriq 4 — Memory leak test
leak-test.c:
void leak(void) {
int *p = malloc(1000 * sizeof(int));
// free yo'q
}
int main(void) {
for (int i = 0; i < 100; i++) {
leak();
}
return 0;
}Mac'da: Activity Monitor'da RAM oshganini ko'ring. Linux'da: valgrind ./leak-test.
Tuzating: free(p) qo'shing.
Topshiriq 5 — String funksiyalar
string-fn.c — dars matnidagi barcha my_* funksiyalarni yozing va string.h versiyalari bilan natijani taqqoslang.
Topshiriq 6 — Reverse
reverse.c — 2 ta versiya: index bilan (2-darsdan) va pointer bilan. Ikkalasini ham sinab ko'ring.
Topshiriq 7 — Anagram
anagram.c — 2 ta so'z anagramami?
Sinab ko'ring:
- listen, silent → Ha
- hello, world → Yo'q
- evil, vile → Ha
Topshiriq 8 — Tokenize
tokenize.c — strtok bilan:
char data[] = "Akmal,22,Toshkent,Talaba";
// 4 ta token: Akmal, 22, Toshkent, TalabaTopshiriq 9 — GitHub
$ mkdir 5-oy-dars-8
$ git add . && git commit -m "feat: dars 8 - pointer, massiv, string" && git pushAsosiy tushunchalar (lug'at)
| Termin | Izoh |
|---|---|
| malloc | Memory ALLOCation — dinamik xotira |
| calloc | Cleared alloc (0 bilan) |
| realloc | Hajmni o'zgartirish |
| free | Xotirani bo'shatish |
| Memory leak | Yo'qotilgan xotira |
| Use after free | free'dan keyin ishlatish |
| Double free | Ikki marta free |
| Heap | Dinamik xotira joyi |
| Stack | Local o'zgaruvchilar joyi |
| Pointer arithmetic | Pointer bilan massiv bo'ylab yurish |
| strchr / strstr | Belgini/substringni topish (pointer qaytaradi) |
| strtok | String'ni bo'lish |
| snprintf | Xavfsiz formatlangan yozish |
| fgets | Qator olish (xavfsiz) |
| Anagram | Bir xil harflardan tuzilgan so'zlar |
| Valgrind | Memory bug topish vositasi |