10-bo‘lim
Satrlar
C da satr nima, nol bilan tugash qoidasi, string.h funksiyalari, satrlarni solishtirish va nusxalashdagi xavfsizlik masalalari.
Ushbu bo‘lim mundarijasi
C da alohida «satr» turi yo'q. Satr - bu oxirida maxsus belgi turgan
char massivi.
Satr aslida nima? #
#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;
}
Satr : Husanboy
Xotira hajmi: 9 bayt
Birinchi harf: H
Uchinchi harf: s
'\0' ni unutish - halokatli xatochar 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:
char togri[4] = {'A', 'B', 'C', '\0'};
char oson[] = "ABC"; /* nol avtomatik qo'shiladi */
Satr e'lon qilishning uch usuli #
#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;
}
a = Kalom
b = Malom
c = Salom
sizeof(a) = 6
sizeof(b) = 20
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 #
| Funksiya | Nima 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 #
#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;
}
strlen : 8
sizeof : 50
strlen va sizeof farqi| Nimani beradi | |
|---|---|
strlen | Belgilar soni - nolgacha sanaydi |
sizeof | Xotira hajmi - massiv necha bayt |
strlen har safar butun satrni aylanib chiqadi. Shuning uchun uni
sikl shartida yozmang:
for (int i = 0; i < strlen(s); i++) { ... } /* sekin */
size_t uzunlik = strlen(s); /* tez */
for (size_t i = 0; i < uzunlik; i++) { ... }
Nusxalash #
#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;
}
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 xavflichar 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 #
#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;
}
To'liq ism: Husanboy Qodirov
Uzunlik : 16
char kichik[10] = "Husanboy";
strcat(kichik, " Qodirov"); /* 16 belgi 10 baytga sig'maydi */
strcat ham hajmni tekshirmaydi. Birlashtirishdan oldin joy borligini
o'zingiz hisoblang:
if (strlen(a) + strlen(b) + 1 <= sizeof(a)) {
strcat(a, b);
}
Solishtirish #
#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;
}
strcmp(a, b) = 0
strcmp(a, c) = 1
strcmp(c, a) = -1
a va b bir xil
== bilan solishtirmangchar 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 #
#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;
}
Birinchi probel indeksi: 8
Shahar topildi: Namangan
Toshkent topilmadi
Satrni belgi bo'yicha aylanish #
#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;
}
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 #
#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;
}
Asl : Husanboy Qodirov
Katta : HUSANBOY QODIROV
Kichik : husanboy qodirov
Satrni teskari aylantirish #
#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;
}
Teskari: yobnasuH
Satrni songa aylantirish #
#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;
}
atoi : 1234
atof : 3.14
strtol: 42, qolgan qism: "abc"
atoi o'rniga strtolatoi("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 #
#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;
}
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
strlen baytlarni sanaydi, harflarni emas. Lotin harflari uchun bu
bir xil, lekin o', g' yoki kirill harflari UTF-8 da ikki bayt
egallaydi.
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.
- Ismingizni satr sifatida e'lon qilib, uzunligini chiqaring.
strlenvasizeofnatijalarini solishtiring.- Ikkita satrni birlashtirib, to'liq ism yasang.
- Ikki satrni
strcmpbilan solishtiring. ==bilan solishtirib, nima uchun ishlamasligini ko'ring.- Satrdagi unli harflar sonini hisoblang.
- Satrni teskari aylantiring.
- Satr palindrom ekanini tekshiring.
- Satrdagi barcha probellarni chiziqchaga almashtiring.
strcpybilan kichik massivga uzun satr nusxalab, natijani kuzating.
Xulosa #
- C da alohida satr turi yo'q - satr bu
'\0'bilan tugaydigancharmassivi. - 8 harfli satr uchun 9 bayt kerak.
'\0'ni unutish - dastur qulashiga yoki axlat chiqishiga olib keladi.strlenbelgilarni sanaydi,sizeofbaytlarni beradi.- Satrlarni
==bilan emas,strcmpbilan solishtiring. strcmpteng bo'lganda 0 qaytaradi.strcpyvastrcathajmni tekshirmaydi - bufer to'lib ketishi xavfi bor.strncpydan keyin nolni qo'lda qo'ying.atoixatoni aniqlamaydi -strtolishlating.- O'zbek harflari UTF-8 da ikki bayt egallaydi.
Keyingi bo'limda funksiyalarni 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.