6-bo‘lim
Satrlar
std::string, std::string_view va nima uchun ikkalasi ham kerak.
Ushbu bo‘lim mundarijasi
C da satr - nol bilan tugaydigan char massivi. Uzunlikni
bilish uchun butun massivni aylanib chiqish kerak, hajmni
o'zgartirish esa qo'lda qilinadi.
C++ da std::string bu ishlarni o'z zimmasiga oladi.
std::string asoslari #
#include <print>
#include <string>
#include <string_view>
#include <vector>
#include <algorithm>
#include <sstream>
int main()
{
std::string bosh;
std::string salom{"Salom"};
std::string takror(5, 'x');
std::string nusxa{salom};
std::string qism{salom, 0, 3}; // 0-indeksdan 3 belgi
std::println("bosh: '{}' ({} belgi)", bosh, bosh.size());
std::println("salom: '{}' ({} belgi)", salom, salom.size());
std::println("takror: '{}'", takror);
std::println("nusxa: '{}'", nusxa);
std::println("qism: '{}'", qism);
// Uzunlik O(1) - saqlanadi, hisoblanmaydi
std::println("");
std::println("bo'shmi: {}", bosh.empty());
std::println("birinchi: {}", salom.front());
std::println("oxirgi: {}", salom.back());
return 0;
}
bosh: '' (0 belgi)
salom: 'Salom' (5 belgi)
takror: 'xxxxx'
nusxa: 'Salom'
qism: 'Sal'
bo'shmi: true
birinchi: S
oxirgi: m
Satrlarni birlashtirish va o'zgartirish #
int main()
{
std::string matn{"Salom"};
matn += ", ";
matn += "dunyo";
matn.push_back('!');
std::println("qo'shgandan keyin: {}", matn);
matn.insert(0, ">> ");
std::println("boshiga qo'shildi: {}", matn);
matn.replace(3, 5, "Assalom");
std::println("almashtirildi: {}", matn);
matn.erase(0, 3);
std::println("boshi o'chirildi: {}", matn);
std::println("");
std::println("katta harflarda:");
std::string katta = matn;
std::ranges::transform(katta, katta.begin(),
[](unsigned char c) { return std::toupper(c); });
std::println(" {}", katta);
return 0;
}
qo'shgandan keyin: Salom, dunyo!
boshiga qo'shildi: >> Salom, dunyo!
almashtirildi: >> Assalom, dunyo!
boshi o'chirildi: Assalom, dunyo!
katta harflarda:
ASSALOM, DUNYO!
Qidirish #
int main()
{
std::string matn{"Husanboy Qodirov, Namangan shahri"};
auto orin = matn.find("Qodirov");
std::println("'Qodirov' o'rni: {}", orin);
auto yoq = matn.find("Toshkent");
std::println("'Toshkent' topildimi: {}",
yoq == std::string::npos ? "yo'q" : "ha");
std::println("");
std::println("boshlanadi 'Husanboy' bilan: {}",
matn.starts_with("Husanboy")); // C++20
std::println("tugaydi 'shahri' bilan: {}",
matn.ends_with("shahri"));
std::println("'Namangan' bormi: {}",
matn.contains("Namangan")); // C++23
// Barcha vergullarni topish
std::println("");
std::size_t joy = 0;
int soni = 0;
while ((joy = matn.find(',', joy)) != std::string::npos) {
++soni;
++joy;
}
std::println("vergullar soni: {}", soni);
return 0;
}
'Qodirov' o'rni: 9
'Toshkent' topildimi: yo'q
boshlanadi 'Husanboy' bilan: true
tugaydi 'shahri' bilan: true
'Namangan' bormi: true
vergullar soni: 1
npos - "topilmadi" belgisifind topa olmasa std::string::npos qaytaradi. Bu
eng katta size_t qiymati.
Tuzoq: npos ni -1 bilan solishtirish yoki int ga
solish - xato:
int orin = matn.find("x"); // XATO: npos int ga sig'maydi
if (orin >= 0) { ... } // har doim rost
To'g'ri:
auto orin = matn.find("x");
if (orin != std::string::npos) { ... }
auto bu yerda ham foydali - u to'g'ri turni o'zi tanlaydi.
std::string_view - nusxasiz ko'rinish #
// Nusxa oladi
std::size_t nusxaBilan(std::string matn)
{
return matn.size();
}
// Nusxa olmaydi, lekin faqat std::string qabul qiladi
std::size_t havolaBilan(const std::string& matn)
{
return matn.size();
}
// Nusxa olmaydi va HAMMA narsani qabul qiladi
std::size_t korinishBilan(std::string_view matn)
{
return matn.size();
}
int main()
{
std::string s{"Husanboy Qodirov"};
const char* c = "C uslubidagi satr";
std::println("std::string bilan:");
std::println(" nusxaBilan: {}", nusxaBilan(s));
std::println(" havolaBilan: {}", havolaBilan(s));
std::println(" korinishBilan: {}", korinishBilan(s));
std::println("");
std::println("const char* bilan:");
std::println(" nusxaBilan: {} <- vaqtinchalik string yasaldi",
nusxaBilan(c));
std::println(" havolaBilan: {} <- vaqtinchalik string yasaldi",
havolaBilan(c));
std::println(" korinishBilan: {} <- nusxa YO'Q", korinishBilan(c));
std::println("");
std::println("string_view hajmi: {} bayt", sizeof(std::string_view));
std::println("string hajmi: {} bayt", sizeof(std::string));
return 0;
}
std::string bilan:
nusxaBilan: 16
havolaBilan: 16
korinishBilan: 16
const char* bilan:
nusxaBilan: 17 <- vaqtinchalik string yasaldi
havolaBilan: 17 <- vaqtinchalik string yasaldi
korinishBilan: 17 <- nusxa YO'Q
string_view hajmi: 16 bayt
string hajmi: 32 bayt
string_view nimastd::string_view - ikkita narsadan iborat: ko'rsatkich
va uzunlik. U hech narsaga egalik qilmaydi.
std::string | std::string_view | |
|---|---|---|
| Xotira egallaydimi | Ha | Yo'q |
| Nusxalash narxi | Butun matn | 16 bayt |
| O'zgartirish | Mumkin | Mumkin emas |
| Nol bilan tugaydimi | Ha | Kafolat yo'q |
| Egalik | Bor | Yo'q |
Amaliy qoida:
Funksiya satrni faqat o'qisa -
std::string_view. Satrni saqlab qolsa -std::string.
Oxirgi qator muhim: string_view ni sinf a'zosi sifatida
saqlash xavfli - ko'rsatilayotgan matn yo'q bo'lishi
mumkin.
string_view ning xavfi #
std::string_view xatoFunksiya()
{
std::string mahalliy{"men yo'q bo'laman"};
return mahalliy; // string_view osilib qoladi
}
int main()
{
// TO'G'RI ishlatish - asl obyekt hayot davomida mavjud
std::string manba{"Husanboy Qodirov, Namangan"};
std::string_view toliq{manba};
std::string_view ism = toliq.substr(0, 8);
std::string_view familiya = toliq.substr(9, 7);
std::println("to'liq: {}", toliq);
std::println("ism: {}", ism);
std::println("familiya: {}", familiya);
std::println("");
std::println("uchalasi BIR XIL xotiraga ishora qiladi -");
std::println("hech qanday nusxa olinmadi.");
std::println("");
std::println("xatoFunksiya() osilgan ko'rinish qaytaradi -");
std::println("uni ishlatish aniqlanmagan xulq-atvor.");
return 0;
}
to'liq: Husanboy Qodirov, Namangan
ism: Husanboy
familiya: Qodirov
uchalasi BIR XIL xotiraga ishora qiladi -
hech qanday nusxa olinmadi.
xatoFunksiya() osilgan ko'rinish qaytaradi -
uni ishlatish aniqlanmagan xulq-atvor.
string_view umrni uzaytirmaydiBu 4- va 5-bo'limlardagi osilgan havola muammosining uchinchi ko'rinishi.
string_view faqat manzil va uzunlikni saqlaydi. Asl matn
yo'q bo'lsa - u ishora qiladigan xotira ham yo'q.
Eng ko'p uchraydigan xatolar:
| Xato | Nima uchun |
|---|---|
string_view qaytarish (mahalliy satrdan) | Osilgan |
| Sinf a'zosi sifatida saqlash | Manba yo'q bo'lishi mumkin |
sv = std::string{"..."} | Vaqtinchalik obyekt darhol o'ladi |
| Konteynerda saqlash | Manba o'zgarsa yaroqsizlanadi |
Xavfsiz ishlatish:
| To'g'ri | Izoh |
|---|---|
| Funksiya parametri | Chaqiruv davomida manba mavjud |
| Mahalliy o'zgaruvchi | Qamrov ichida |
| Doimiy satrlar bilan | "matn" dastur davomida yashaydi |
Satrni bo'laklarga ajratish #
std::vector<std::string> ajrat(std::string_view matn, char belgi)
{
std::vector<std::string> natija;
std::size_t boshi = 0;
while (true) {
std::size_t orin = matn.find(belgi, boshi);
if (orin == std::string_view::npos) {
natija.emplace_back(matn.substr(boshi));
break;
}
natija.emplace_back(matn.substr(boshi, orin - boshi));
boshi = orin + 1;
}
return natija;
}
int main()
{
auto qismlar = ajrat("Husanboy,Malika,Nodira,Aziza", ',');
std::println("{} ta qism:", qismlar.size());
for (const auto& q : qismlar) {
std::println(" '{}'", q);
}
// Bo'shliq bo'yicha
auto sozlar = ajrat("bir ikki uch tort", ' ');
std::println("");
std::println("so'zlar: {}", sozlar);
return 0;
}
4 ta qism:
'Husanboy'
'Malika'
'Nodira'
'Aziza'
so'zlar: ["bir", "ikki", "uch", "tort"]
Sonlarni satrga va aksincha #
#include <charconv>
int main()
{
// Songa aylantirish - eski usul
std::string matn{"12345"};
int son = std::stoi(matn);
double kasr = std::stod("3.14159");
std::println("stoi: {}", son);
std::println("stod: {}", kasr);
// Satrga aylantirish
std::println("to_string: {}", std::to_string(42));
std::println("format: {}", std::format("{:.3f}", 3.14159));
std::println("format: {}", std::format("{:>10}", "o'ngga"));
std::println("format: {}", std::format("{:08.2f}", 3.14159));
std::println("format: {}", std::format("{:#x}", 255));
// Xato holatlari
std::println("");
try {
std::stoi("bu son emas");
} catch (const std::invalid_argument& x) {
std::println("stoi xatosi: {}", x.what());
}
// Zamonaviy usul - istisnosiz
std::string_view kiritma{"789xyz"};
int natija{};
auto [oxiri, xato] = std::from_chars(kiritma.data(),
kiritma.data() + kiritma.size(),
natija);
std::println("");
std::println("from_chars: {} (qolgan qism: '{}')",
natija, std::string_view{oxiri});
return 0;
}
stoi: 12345
stod: 3.14159
to_string: 42
format: 3.142
format: o'ngga
format: 00003.14
format: 0xff
stoi xatosi: stoi
from_chars: 789 (qolgan qism: 'xyz')
std::format - qulay formatlash{} ichiga formatlash ko'rsatmalari yoziladi:
| Yozuv | Ma'nosi |
|---|---|
{:.3f} | Kasr, 3 raqam |
{:>10} | O'ngga tekislash, 10 kenglik |
{:<10} | Chapga |
{:^10} | O'rtaga |
{:08.2f} | Nol bilan to'ldirish |
{:#x} | O'n oltilik, 0x prefiksi bilan |
{:b} | Ikkilik |
{:+} | Ishorani doim ko'rsatish |
std::format va std::println bir xil sintaksisdan
foydalanadi.
Muhim: format satri kompilyatsiya paytida tekshiriladi.
Argument soni yoki turi mos kelmasa - kompilyatsiya xatosi.
printf da esa bu ish vaqtidagi buzilishga olib kelardi.
Satrlarni solishtirish #
int main()
{
std::string a{"olma"};
std::string b{"anor"};
std::println("a == b: {}", a == b);
std::println("a < b: {}", a < b);
std::println("a > b: {}", a > b);
// C++20 - uch tomonlama solishtirish
auto natija = a <=> b;
std::println("");
std::println("a <=> b: {}",
natija < 0 ? "kichik" : (natija > 0 ? "katta" : "teng"));
// Tartiblash lug'at tartibida
std::vector<std::string> mevalar{"uzum", "olma", "anor", "behi"};
std::ranges::sort(mevalar);
std::println("");
std::println("tartiblangan: {}", mevalar);
// Registrga sezgir emas solishtirish
auto tengmi = [](std::string_view x, std::string_view y) {
return std::ranges::equal(x, y, [](unsigned char c1, unsigned char c2) {
return std::tolower(c1) == std::tolower(c2);
});
};
std::println("");
std::println("'Olma' va 'olma' teng: {}", tengmi("Olma", "olma"));
return 0;
}
a == b: false
a < b: false
a > b: true
a <=> b: katta
tartiblangan: ["anor", "behi", "olma", "uzum"]
'Olma' va 'olma' teng: true
std::string UTF-8 ni bilmaydi. U baytlarni solishtiradi.
Oqibatlari:
| Amal | O'zbek matni bilan |
|---|---|
.size() | Baytlar soni, harflar emas |
[i] | i-bayt, i-harf emas |
< solishtirish | Lug'at tartibi emas |
toupper | Faqat ASCII harflar uchun |
Masalan "o'g'il" da apostroflar bilan birga 7 bayt bor,
lekin harflar soni boshqa.
Kirill yoki maxsus belgilar bilan ishlaganda bu farq kattaroq bo'ladi.
To'liq Unicode qo'llab-quvvatlash uchun alohida kutubxona kerak (ICU va h.k.). Standart kutubxonada bu yo'q.
Amaliy holat: saqlash va uzatish uchun std::string
mukammal ishlaydi. Muammo faqat harflarni sanash va
tartiblashda paydo bo'ladi.
Kichik satr optimallashtirishi #
int main()
{
std::println("std::string hajmi: {} bayt", sizeof(std::string));
std::println("");
std::string qisqa{"salom"};
std::string uzun{"bu satr kichik satr optimallashtirishiga sig'maydi"};
std::println("qisqa: {} belgi, sig'im {}", qisqa.size(), qisqa.capacity());
std::println("uzun: {} belgi, sig'im {}", uzun.size(), uzun.capacity());
std::println("");
std::println("Qisqa satrlar obyektning O'ZIDA saqlanadi -");
std::println("dinamik xotira ajratilmaydi.");
return 0;
}
std::string hajmi: 32 bayt
qisqa: 5 belgi, sig'im 15
uzun: 50 belgi, sig'im 50
Qisqa satrlar obyektning O'ZIDA saqlanadi -
dinamik xotira ajratilmaydi.
std::string 32 bayt egallaydi, lekin uning ichida
ko'rsatkich, uzunlik va sig'imdan tashqari kichik
bufer ham bor.
Satr yetarlicha qisqa bo'lsa (GCC da 15 belgigacha), u o'sha buferga joylashadi va dinamik xotira umuman ajratilmaydi.
Foydasi:
| Holat | Xotira ajratish |
|---|---|
"salom" (5 belgi) | Yo'q |
"Husanboy Qodirov" (16 belgi) | Bor |
| Vaqtinchalik kalitlar, qisqa nomlar | Odatda yo'q |
Bu ko'p kodda std::string ni const char* bilan bir xil
tezlikda ishlashini ta'minlaydi.
Aniq chegara kompilyatorga bog'liq va standartda belgilanmagan.
- Satrni besh xil usulda yarating va uzunliklarini chiqaring.
- Satrga qo'shish, kiritish, almashtirish va o'chirishni sinang.
findbilan qidiring vanposni to'g'ri tekshiring.starts_with,ends_with,containsni ishlating.- Bir funksiyani
string,const string&vastring_viewbilan yozing. - Har birini
const char*bilan chaqirib, farqni tushuntiring. string_viewqaytaruvchi xavfli funksiya yozing.- Satrni belgi bo'yicha bo'laklarga ajratuvchi funksiya yozing.
std::formatning oltita formatlash ko'rsatmasini sinang.sizeof(std::string)ni o'lchang va SSO chegarasini toping.
Xulosa #
std::stringuzunlikni saqlaydi -.size()doimiy vaqtda ishlaydi.- U xotirani o'zi boshqaradi: qo'shish, o'chirish, kengaytirish avtomatik.
findtopa olmasanposqaytaradi - uniintga solmang.- C++20/23 da
starts_with,ends_with,containsqo'shildi. std::string_view- ko'rsatkich va uzunlik, nusxa olmaydi.- Faqat o'qiydigan parametrlar uchun
string_view, saqlash uchunstring. string_viewasl matnning umrini uzaytirmaydi - osilib qolishi mumkin.std::formatformat satrini kompilyatsiya paytida tekshiradi.- Solishtirish baytlar bo'yicha boradi - UTF-8 harflari bilan ehtiyot bo'ling.
- Kichik satr optimallashtirishi qisqa satrlar uchun xotira ajratmaydi.
Keyingi bo'limda konteynerlar bilan tanishamiz.
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.