10-bo‘lim

Satrlar

C da satr nima, nol bilan tugash qoidasi, string.h funksiyalari, satrlarni solishtirish va nusxalashdagi xavfsizlik masalalari.

🕑 18 daqiqa o‘qish 📄 753 so‘z 👁 4 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Satr aslida nima?
  2. Satr e'lon qilishning uch usuli
  3. string.h funksiyalari
  4. Uzunlik
  5. Nusxalash
  6. Birlashtirish
  7. Solishtirish
  8. Qidirish
  9. Satrni belgi bo'yicha aylanish
  10. Katta va kichik harfga o'girish
  11. Satrni teskari aylantirish
  12. Satrni songa aylantirish
  13. Satrlar massivi
  14. Xulosa

C da alohida «satr» turi yo'q. Satr - bu oxirida maxsus belgi turgan char massivi.

Satr aslida nima? #

char ism[] = "Husanboy" xotirada 'H' [0] 72 'u' [1] 117 's' [2] 'a' [3] 'n' [4] 'b' [5] 'o' [6] 'y' [7] \0 [8] 0 Nol belgisi ('\0') satrning oxirini bildiradi 8 harf uchun 9 bayt kerak - oxirgisi nol uchun
Barcha satr funksiyalari aynan shu nolni qidiradi
C
#include <stdio.h>

int main(void) {
    char ism[] = "Husanboy";

    printf("Satr        : %s\n", ism);
    printf("Xotira hajmi: %zu bayt\n", sizeof(ism));
    printf("Birinchi harf: %c\n", ism[0]);
    printf("Uchinchi harf: %c\n", ism[2]);

    return 0;
}
Natija
Satr        : Husanboy
Xotira hajmi: 9 bayt
Birinchi harf: H
Uchinchi harf: s
'\0' ni unutish - halokatli xato
C
char notogri[3] = {'A', 'B', 'C'};    /* nol belgisi YO'Q */
printf("%s\n", notogri);              /* XAVFLI */

printf("%s") nolni qidiradi. U yo'q bo'lsa, funksiya xotira bo'ylab nol topilgunicha yurishda davom etadi - va axlat chiqaradi yoki dastur qulaydi.

To'g'ri yozuv:

C
char togri[4] = {'A', 'B', 'C', '\0'};
char oson[] = "ABC";                   /* nol avtomatik qo'shiladi */

Satr e'lon qilishning uch usuli #

C
#include <stdio.h>

int main(void) {
    char a[] = "Salom";            /* massiv - o'zgartirish mumkin */
    char b[20] = "Salom";          /* katta massiv - joy zaxira bilan */
    const char *c = "Salom";       /* ko'rsatkich - faqat o'qish */

    a[0] = 'K';                    /* mumkin */
    printf("a = %s\n", a);

    b[0] = 'M';                    /* mumkin */
    printf("b = %s\n", b);

    /* c[0] = 'T';   XATO: doimiy satrni o'zgartirib bo'lmaydi */
    printf("c = %s\n", c);

    printf("sizeof(a) = %zu\n", sizeof(a));
    printf("sizeof(b) = %zu\n", sizeof(b));

    return 0;
}
Natija
a = Kalom
b = Malom
c = Salom
sizeof(a) = 6
sizeof(b) = 20
Satr literalini o'zgartirmang
C
char *matn = "Salom";
matn[0] = 'K';           /* XAVFLI: dastur qulashi mumkin */

"Salom" xotiraning faqat o'qish uchun mo'ljallangan qismida yotadi. Uni o'zgartirishga urinish - aniqlanmagan xatti-harakat.

Shuning uchun bunday satrlarni doim const char * deb e'lon qiling - kompilyator sizni xatodan saqlaydi.

string.h funksiyalari #

FunksiyaNima qiladi
strlen(s)Uzunlik (nolni hisoblamaydi)
strcpy(maqsad, manba)Nusxalash
strncpy(maqsad, manba, n)Ko'pi bilan n belgi nusxalash
strcat(maqsad, manba)Oxiriga qo'shish
strncat(maqsad, manba, n)Cheklangan qo'shish
strcmp(a, b)Solishtirish
strncmp(a, b, n)Birinchi n belgini solishtirish
strchr(s, c)Belgini qidirish
strstr(s, kichik)Kichik satrni qidirish
strcspn(s, rad)Rad etilgan belgigacha uzunlik

Uzunlik #

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

int main(void) {
    char ism[50] = "Husanboy";

    printf("strlen  : %zu\n", strlen(ism));
    printf("sizeof  : %zu\n", sizeof(ism));

    return 0;
}
Natija
strlen  : 8
sizeof  : 50
strlen va sizeof farqi
Nimani beradi
strlenBelgilar soni - nolgacha sanaydi
sizeofXotira hajmi - massiv necha bayt

strlen har safar butun satrni aylanib chiqadi. Shuning uchun uni sikl shartida yozmang:

C
for (int i = 0; i < strlen(s); i++) { ... }   /* sekin */

size_t uzunlik = strlen(s);                    /* tez */
for (size_t i = 0; i < uzunlik; i++) { ... }

Nusxalash #

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

int main(void) {
    char manba[] = "Husanboy Qodirov";
    char maqsad[50];

    /* maqsad = manba;   XATO: massivni tenglashtirib bo'lmaydi */

    strcpy(maqsad, manba);
    printf("Nusxa: %s\n", maqsad);

    /* xavfsizroq shakl */
    char qisqa[10];
    strncpy(qisqa, manba, sizeof(qisqa) - 1);
    qisqa[sizeof(qisqa) - 1] = '\0';    /* nolni qo'lda qo'yamiz */
    printf("Qisqa: %s\n", qisqa);

    return 0;
}
Natija
Nusxa: Husanboy Qodirov
Qisqa: Husanboy 

E'tibor bering: qisqa ichida «Husanboy» dan keyin probel ham bor - strncpy to'qqizta belgini ko'chirdi va to'qqizinchisi probel edi.

strcpy xavfli
C
char kichik[5];
strcpy(kichik, "Juda uzun matn");   /* BUFER TO'LIB KETDI */

strcpy maqsad massivning hajmini bilmaydi. U manbadagi hamma narsani, nolgacha, ko'chiradi - qo'shni xotirani buzsa ham.

Bu buffer overflow zaifligining klassik manbai. Morris qurti (1988) ham aynan shunday xatodan foydalangan.

strncpy xavfsizroq, lekin uning ham tuzog'i bor: agar manba juda uzun bo'lsa, u nol qo'ymaydi. Shuning uchun yuqoridagi misolda nolni qo'lda qo'ydik.

Birlashtirish #

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

int main(void) {
    char toliq[100] = "Husanboy";

    strcat(toliq, " ");
    strcat(toliq, "Qodirov");

    printf("To'liq ism: %s\n", toliq);
    printf("Uzunlik   : %zu\n", strlen(toliq));

    return 0;
}
Natija
To'liq ism: Husanboy Qodirov
Uzunlik   : 16
Maqsad massiv yetarli kattami?
C
char kichik[10] = "Husanboy";
strcat(kichik, " Qodirov");      /* 16 belgi 10 baytga sig'maydi */

strcat ham hajmni tekshirmaydi. Birlashtirishdan oldin joy borligini o'zingiz hisoblang:

C
if (strlen(a) + strlen(b) + 1 <= sizeof(a)) {
    strcat(a, b);
}

Solishtirish #

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

int main(void) {
    char a[] = "olma";
    char b[] = "olma";
    char c[] = "anor";

    printf("strcmp(a, b) = %d\n", strcmp(a, b));
    printf("strcmp(a, c) = %d\n", strcmp(a, c) > 0 ? 1 : -1);
    printf("strcmp(c, a) = %d\n", strcmp(c, a) > 0 ? 1 : -1);

    if (strcmp(a, b) == 0) {
        printf("a va b bir xil\n");
    }

    return 0;
}
Natija
strcmp(a, b) = 0
strcmp(a, c) = 1
strcmp(c, a) = -1
a va b bir xil
Satrlarni == bilan solishtirmang
C
char a[] = "olma";
char b[] = "olma";

if (a == b) { ... }        /* NOTO'G'RI: manzillarni solishtiradi */
if (strcmp(a, b) == 0) { } /* to'g'ri: mazmunni solishtiradi */

a va b - ikki alohida massiv, ularning manzillari boshqa-boshqa. Shuning uchun a == b har doim yolg'on bo'ladi, mazmuni bir xil bo'lsa ham.

Eslab qoling: strcmp teng bo'lganda 0 qaytaradi - ya'ni «yolg'on». Shuning uchun if (strcmp(...)) emas, if (strcmp(...) == 0) yozing.

Qidirish #

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

int main(void) {
    char matn[] = "Husanboy Qodirov, Namangan";

    char *probel = strchr(matn, ' ');
    if (probel != NULL) {
        printf("Birinchi probel indeksi: %ld\n", probel - matn);
    }

    char *shahar = strstr(matn, "Namangan");
    if (shahar != NULL) {
        printf("Shahar topildi: %s\n", shahar);
    }

    if (strstr(matn, "Toshkent") == NULL) {
        printf("Toshkent topilmadi\n");
    }

    return 0;
}
Natija
Birinchi probel indeksi: 8
Shahar topildi: Namangan
Toshkent topilmadi

Satrni belgi bo'yicha aylanish #

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

int main(void) {
    char matn[] = "Salom, C tili 2026!";

    int harflar = 0, raqamlar = 0, probellar = 0, boshqa = 0;

    for (int i = 0; matn[i] != '\0'; i++) {
        if (isalpha((unsigned char) matn[i])) {
            harflar++;
        } else if (isdigit((unsigned char) matn[i])) {
            raqamlar++;
        } else if (isspace((unsigned char) matn[i])) {
            probellar++;
        } else {
            boshqa++;
        }
    }

    printf("Harflar   : %d\n", harflar);
    printf("Raqamlar  : %d\n", raqamlar);
    printf("Probellar : %d\n", probellar);
    printf("Boshqa    : %d\n", boshqa);

    return 0;
}
Natija
Harflar   : 10
Raqamlar  : 4
Probellar : 3
Boshqa    : 2
(unsigned char) nima uchun?

isalpha va shunga o'xshash funksiyalar unsigned char yoki EOF qiymatini kutadi. char esa ba'zi platformalarda ishorali bo'ladi va 127 dan katta belgilar manfiy songa aylanadi - bu aniqlanmagan xatti-harakat.

(unsigned char) ga aylantirish bu muammoni yo'q qiladi. Bu kichik tafsilot, lekin professional kodda doim shunday yoziladi.

Katta va kichik harfga o'girish #

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

int main(void) {
    char matn[] = "Husanboy Qodirov";
    char katta[50];
    char kichik[50];

    strcpy(katta, matn);
    strcpy(kichik, matn);

    for (int i = 0; katta[i] != '\0'; i++) {
        katta[i] = (char) toupper((unsigned char) katta[i]);
    }

    for (int i = 0; kichik[i] != '\0'; i++) {
        kichik[i] = (char) tolower((unsigned char) kichik[i]);
    }

    printf("Asl    : %s\n", matn);
    printf("Katta  : %s\n", katta);
    printf("Kichik : %s\n", kichik);

    return 0;
}
Natija
Asl    : Husanboy Qodirov
Katta  : HUSANBOY QODIROV
Kichik : husanboy qodirov

Satrni teskari aylantirish #

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

int main(void) {
    char matn[] = "Husanboy";
    size_t uzunlik = strlen(matn);

    for (size_t i = 0; i < uzunlik / 2; i++) {
        char vaqtinchalik = matn[i];
        matn[i] = matn[uzunlik - 1 - i];
        matn[uzunlik - 1 - i] = vaqtinchalik;
    }

    printf("Teskari: %s\n", matn);
    return 0;
}
Natija
Teskari: yobnasuH

Satrni songa aylantirish #

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

int main(void) {
    const char *raqam_matni = "1234";
    const char *kasr_matni = "3.14";

    int son = atoi(raqam_matni);
    double kasr = atof(kasr_matni);

    printf("atoi : %d\n", son);
    printf("atof : %.2f\n", kasr);

    /* xavfsizroq usul - xatoni aniqlaydi */
    char *qolgan;
    long xavfsiz = strtol("42abc", &qolgan, 10);

    printf("strtol: %ld, qolgan qism: \"%s\"\n", xavfsiz, qolgan);

    return 0;
}
Natija
atoi : 1234
atof : 3.14
strtol: 42, qolgan qism: "abc"
atoi o'rniga strtol

atoi("abc") 0 qaytaradi - lekin atoi("0") ham 0 qaytaradi. Ya'ni xato bo'lganini bilib bo'lmaydi.

strtol esa qayerda to'xtaganini aytadi. Agar qolgan ko'rsatkichi satr boshiga teng bo'lsa - hech qanday raqam o'qilmagan.

Satrlar massivi #

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

int main(void) {
    const char *talabalar[] = {
        "Husanboy Qodirov",
        "Malika Yusupova",
        "Nodira Sobirova",
        "Aziza Tosheva"
    };

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

    printf("Talabalar ro'yxati:\n");
    for (int i = 0; i < soni; i++) {
        printf("%d. %-20s (%zu belgi)\n", i + 1, talabalar[i], strlen(talabalar[i]));
    }

    /* eng uzun ismni topamiz */
    int eng_uzun = 0;
    for (int i = 1; i < soni; i++) {
        if (strlen(talabalar[i]) > strlen(talabalar[eng_uzun])) {
            eng_uzun = i;
        }
    }

    printf("\nEng uzun ism: %s\n", talabalar[eng_uzun]);

    return 0;
}
Natija
Talabalar ro'yxati:
1. Husanboy Qodirov     (16 belgi)
2. Malika Yusupova      (15 belgi)
3. Nodira Sobirova      (15 belgi)
4. Aziza Tosheva        (13 belgi)

Eng uzun ism: Husanboy Qodirov
O'zbek harflari va UTF-8

strlen baytlarni sanaydi, harflarni emas. Lotin harflari uchun bu bir xil, lekin o', g' yoki kirill harflari UTF-8 da ikki bayt egallaydi.

C
char matn[] = "o'zbek";
printf("%zu\n", strlen(matn));    /* 7, 6 emas */

Shuning uchun o'zbek matni bilan ishlaganda belgilarni indeks bo'yicha kesish xavfli - harf o'rtasidan bo'linib ketishi mumkin. Bunday hollarda maxsus kutubxonalar (ICU) yoki wchar_t ishlatiladi.

Amaliy topshiriq
  1. Ismingizni satr sifatida e'lon qilib, uzunligini chiqaring.
  2. strlen va sizeof natijalarini solishtiring.
  3. Ikkita satrni birlashtirib, to'liq ism yasang.
  4. Ikki satrni strcmp bilan solishtiring.
  5. == bilan solishtirib, nima uchun ishlamasligini ko'ring.
  6. Satrdagi unli harflar sonini hisoblang.
  7. Satrni teskari aylantiring.
  8. Satr palindrom ekanini tekshiring.
  9. Satrdagi barcha probellarni chiziqchaga almashtiring.
  10. strcpy bilan kichik massivga uzun satr nusxalab, natijani kuzating.

Xulosa #

  • C da alohida satr turi yo'q - satr bu '\0' bilan tugaydigan char massivi.
  • 8 harfli satr uchun 9 bayt kerak.
  • '\0' ni unutish - dastur qulashiga yoki axlat chiqishiga olib keladi.
  • strlen belgilarni sanaydi, sizeof baytlarni beradi.
  • Satrlarni == bilan emas, strcmp bilan solishtiring.
  • strcmp teng bo'lganda 0 qaytaradi.
  • strcpy va strcat hajmni tekshirmaydi - bufer to'lib ketishi xavfi bor.
  • strncpy dan keyin nolni qo'lda qo'ying.
  • atoi xatoni aniqlamaydi - strtol ishlating.
  • O'zbek harflari UTF-8 da ikki bayt egallaydi.

Keyingi bo'limda funksiyalarni 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.