🔤 Şiruri de Caractere

Capitolul 6 — char[], string, <cctype> (toupper/tolower/isalpha), <cstring>, algoritmi şi probleme BAC

Șiruri de caracterePalindromAnagramăstrlen / strcpyCaesar
📖 12 min
0
🔤

char[] vs string — două abordări

🔡 Ce este un şir de caractere?

Un şir de caractere este o secvenţă de litere, cifre sau simboluri stocate consecutiv în memorie. Fiecare caracter are un cod numeric în tabelul ASCII. De exemplu, 'A' = 65, 'a' = 97, '0' = 48.

Imaginează-ţi un şir ca o cutie cu sertare numerotate — fiecare sertar ţine câte un caracter. Ultimul sertar special conţine '\0' (zero), semn că şirul s-a terminat.

Relaţia dintre caractere şi numere permite comparaţii, conversii şi operaţii matematice pe caractere!

Tabela ASCII — caractere esenţiale pentru BAC

CaracterCod ASCIIUtilizare la BACExemplu
A–Z65–90Litere mari → ch - 'A' = index 0–25'C'-'A' = 2
a–z97–122Litere mici → ch - 'a' = index 0–25'c'-'a' = 2
0–948–57Cifre → ch - '0' = cifra (0–9)'7'-'0' = 7
Spaţiu32Delimitator cuvânte în getline()c == ' '
\00Terminator de şir (null char)s[n] = '\0'
A vs a65 vs 97Diferenţa: 32 → conversie mare/mică'a'-'A' = 32
char[] (C-style)

Vector de caractere terminat cu '\0'. Funcţii din <cstring>: strlen, strcpy, strcat, strcmp, strchr, strstr.

char s[201] = "salut";
Accesare: s[0]='s', s[1]='a', ..., s[5]='\0'
string (C++)

Clasă C++, dimensiune dinamică. Operatori: +, ==, []. Metode: .length(), .substr(), .find(), .erase().

string s = "salut";
Accesare: s[0]='s', s.length()=5
// char[] — declarare si initializare
char s[201];                  // maxim 200 caractere + '\0'
char t[] = "informatica";     // dimensiune dedusa: 12 (11 + '\0')
char r[10] = {'b','a','c','\0'};

// string — declarare si initializare
#include <string>
string str = "informatica";
string str2(5, 'a');            // "aaaaa" — 5 de 'a'
string str3(str, 2, 4);         // "form" — substr din pozitia 2, lung 4
🔣

Funcţii pentru caractere — <cctype>

💡 De ce avem nevoie de funcţii pentru caractere?

La BAC, foarte des trebuie să verificăm: “e literă? e cifră? e spaţiu?” sau să convertăm litere mari în mici. Biblioteca <cctype> oferă funcţii gata făcute pentru asta. În loc să compari cu coduri ASCII direct, poţi folosi aceste funcţii clare.

✅ Funcţii de verificare (returnează 0 sau non-zero)

FuncţieReturnează adevărat când...Exemplu adevăratExemplu fals
isalpha(c)c este literă (A-Z sau a-z)isalpha('A')isalpha('3')
isdigit(c)c este cifră (0-9)isdigit('7')isdigit('a')
isalnum(c)c este literă SAU cifrăisalnum('a')isalnum('!')
isupper(c)c este literă MARE (A-Z)isupper('A')isupper('a')
islower(c)c este literă MICĂ (a-z)islower('a')islower('A')
isspace(c)c este spaţiu, tab, newline etc.isspace(' ')isspace('a')
ispunct(c)c este semn de punctuaţieispunct('.')ispunct('a')
isprint(c)c este caracter afişabilisprint('A')isprint('\0')

🔄 Funcţii de conversie (returnează char convertit)

FuncţieDescriereExempluRezultat
toupper(c)Convertşte litera mică în MARE. Dacă c nu e literă, returnează c neschimbat.toupper('a')'A'
tolower(c)Convertşte litera MARE în mică. Dacă c nu e literă, returnează c neschimbat.tolower('A')'a'
Truc BAC: Conversia manuală fără funcţii: tolower(c) echivalent cu c + 32 (dacă c este literă mare). toupper(c) = c - 32 (dacă c este literă mică). Funcţiile din <cctype> sunt mai sigure — nu necesită verificarea tipului!

Exemple practice

#include <cctype>
#include <iostream>
using namespace std;

// 1. Numarare vocale, consoane, cifre, spatii
char s[] = "BAC 2024 informatica!";
int vocale=0, cifre=0, spatii=0, consoane=0;
for (int i=0; s[i] != '\0'; i++) {
    char c = tolower(s[i]);          // normalizam la minuscule
    if (c=='a'||c=='e'||c=='i'||c=='o'||c=='u') vocale++;
    else if (isdigit(s[i])) cifre++;
    else if (isspace(s[i])) spatii++;
    else if (isalpha(s[i])) consoane++;
}
// Rezultat: vocale=8 cifre=4 spatii=2 consoane=6

// 2. Conversie string la MAJUSCULE
string str = "informatica";
for (int i=0; i < str.length(); i++)
    str[i] = toupper(str[i]);
// str = "INFORMATICA"

// 3. Numarare litere mari vs mici
int mari=0, mici=0;
char s2[] = "BaC2024";
for (int i=0; s2[i]; i++) {
    if (isupper(s2[i])) mari++;
    else if (islower(s2[i])) mici++;
}
// mari=2 mici=1

// 4. Verificare daca un sir contine doar litere si cifre
bool esteAlphanumeric(char s[]) {
    for (int i=0; s[i]; i++)
        if (!isalnum(s[i])) return false;
    return true;
}
⚙️

Funcţii din <cstring> — referinţă completă

📏 Lungime şi copiere

FuncţieDescriereExempluRezultat
strlen(s)Lungimea şirului (fără '\0')strlen("abc")3
strcpy(dest, src)Copiază src în dest (include '\0')strcpy(a, "bac")a = "bac"
strncpy(dest, src, n)Copiază maxim n caractere din srcstrncpy(a, "bacalaureat", 3)a = "bac"

🔗 Concatenare

FuncţieDescriereExempluRezultat
strcat(dest, src)Concatenează src la finalul deststrcat(a, "2024")a+="2024"
strncat(dest, src, n)Concatenează maxim n caractere din srcstrncat(a, "20245678", 4)a+="2024"

⚖️ Comparare

FuncţieReturneazăExempluRezultat
strcmp(s1, s2)<0 dacă s1<s2, 0 dacă egale, >0 dacă s1>s2strcmp("ab","ac")negativ
strncmp(s1, s2, n)Compară primele n caracterestrncmp("abc","abx",2)0 (egale)

🔍 Căutare în şir

FuncţieReturneazăExempluRezultat
strchr(s, c)Pointer la prima apariţie a lui c (sau NULL)strchr("bac",'a')pointer la 'a'
strrchr(s, c)Pointer la ULTIMA apariţie a lui cstrrchr("abcabc",'b')pointer la al 2-lea 'b'
strstr(s, sub)Pointer la prima apariţie a subşirului (sau NULL)strstr("informatica","atic")pointer la "atic"

✂️ Tokenizare şi alte funcţii

FuncţieDescriereObservaţii
strtok(s, delim)Împarte şirul în cuvânte (tokens) după delimitatoriModifică şirul original! Apeluri ulterioare: strtok(NULL, delim)
memset(s, c, n)Umple n octeţi din s cu valoarea cmemset(s, 0, sizeof(s))

Exemple complete

#include <cstring>
#include <iostream>
using namespace std;

// Exemplu 1: strtok — imparte propozitia in cuvinte
char prop[] = "Astazi este o zi frumoasa";
char *token = strtok(prop, " ");
while (token != NULL) {
    cout << token << endl;
    token = strtok(NULL, " ");
}
// Afiseaza: Astazi / este / o / zi / frumoasa

// Exemplu 2: strchr — gaseste prima aparitie
char s[] = "bac";
char *p = strchr(s, 'a');
if (p != NULL)
    cout << "Gasit la pozitia: " << (p - s) << endl;  // 1

// Exemplu 3: strstr — verifica aparitia unui cuvant
char text[] = "Examenul de informatica este maine";
if (strstr(text, "informatica") != NULL)
    cout << "Cuvantul a fost gasit!" << endl;
Atentie la buffer overflow! Asigurati-vă că destinatia (dest) are suficient spaţiu. Preferati strncpy cu verificare explicită.
📜

Metode ale clasei string (C++)

// Referinta completa metode string
string s = "informatica";

// Lungime si acces
s.length()           // 11
s.size()             // 11 (identic cu length())
s.empty()            // false
s[0]                 // 'i'
s.at(0)             // 'i' (cu verificare bounds)
s.front()            // 'i' (primul caracter)
s.back()             // 'a' (ultimul caracter)

// Subsirul si cautare
s.substr(3, 4)       // "orma" (de la poz 3, lungime 4)
s.find("tica")       // 7 (poz prima aparitie)
s.find("xyz")        // string::npos (nu exista)
s.rfind("a")         // 10 (ultima aparitie)

// Modificare
s.replace(0, 4, "XX") // "XXrmatica" (inlocuieste 4 char de la poz 0)
s.erase(2, 3)         // sterge 3 char de la poz 2
s.insert(2, "XY")      // insereaza "XY" la poz 2
s.clear()             // golesste sirul

// Conversie
s.c_str()             // const char* (pt functii C)

// Verificare existenta
if (s.find("info") != string::npos)
    cout << "Gasit!";

// Concatenare cu +=
string a = "bac", b = "2024";
a += b;               // a = "bac2024"
a += '!';            // a = "bac2024!"
📥

Citirea sirurilor de caractere

char s[201];
string str;

// cin >> — citeste pana la primul spatiu/newline
cin >> s;         // "bac" (fara spatii)
cin >> str;       // identic pentru string

// cin.getline — linie intreaga (cu spatii) — char[]
cin.getline(s, 201);          // citeste maxim 200 caractere + '\0'
cin.getline(s, 201, ',');     // citeste pana la ',' sau maxim 200

// getline — linie intreaga — string
getline(cin, str);

// ATENTIE: daca cititi un numar inainte de un sir!
int n;
cin >> n;
cin.ignore();        // consuma newline-ul ramas
getline(cin, str);   // acum functioneaza corect
Eroare frecventa la BAC: Daca cititi un numar cu cin >> n si apoi un sir cu getline, fara cin.ignore(), getline citeste linia goala ramasa!
⚙️

Algoritmi clasici pe siruri

1. Verificare palindrom

bool estePalindrom(string s) {
    int n = s.length();
    for (int i=0; i < n/2; i++)
        if (s[i] != s[n-1-i]) return false;
    return true;
}
// "radar" → true | "madam" → true | "bac" → false
🎮 Demo interactiv — palindrom cu doi pointeri

Pointer stâng st și pointer drept dr avansează unul spre celălalt comparând caracter cu caracter.

Normal
st dr match mismatch

2. Verificare anagrama (cu tablou frecvente)

bool esteAnagrama(string a, string b) {
    if (a.length() != b.length()) return false;
    int freq[26] = {0};
    for (int i=0; i < a.length(); i++) {
        freq[tolower(a[i]) - 'a']++;
        freq[tolower(b[i]) - 'a']--;
    }
    for (int i=0; i < 26; i++)
        if (freq[i] != 0) return false;
    return true;
}
// "listen" si "silent" → true | "race" si "care" → true

3. Cifru Caesar

string criptCaesar(string s, int k) {
    k = ((k % 26) + 26) % 26;   // k poate fi negativ
    for (int i=0; i < s.length(); i++) {
        if (s[i] >= 'a' && s[i] <= 'z')
            s[i] = 'a' + (s[i]-'a'+k) % 26;
        else if (s[i] >= 'A' && s[i] <= 'Z')
            s[i] = 'A' + (s[i]-'A'+k) % 26;
    }
    return s;
}
// decriptare = criptCaesar(s, 26-k)
// criptCaesar("abc", 3) → "def"
🎮 Demo interactiv — Cifrul Caesar (shift letter-by-letter)

Fiecare literă se rotește cu k poziții în alfabet. Roata de jos arată mapping-ul pentru caracterul curent.

Normal

4. Cel mai lung cuvant din propozitie

string linie, cuvCurent, maxCuv;
getline(cin, linie);
linie += " ";  // adaugam spatiu la final
for (int i=0; i < linie.length(); i++) {
    if (linie[i] != ' ') cuvCurent += linie[i];
    else {
        if (cuvCurent.length() > maxCuv.length())
            maxCuv = cuvCurent;
        cuvCurent = "";
    }
}
cout << maxCuv;

5. Inversarea unui sir (in-place)

void inverseaza(string &s) {
    int st=0, dr=s.length()-1;
    while (st < dr) { swap(s[st], s[dr]); st++; dr--; }
}
// inverseaza("bac") → "cab"

6. Eliminare duplicate consecutive

string elimDup(string s) {
    string rez = "";
    if (s.empty()) return rez;
    rez += s[0];
    for (int i=1; i < s.length(); i++)
        if (s[i] != s[i-1]) rez += s[i];
    return rez;
}
// "aaabbc" → "abc" | "mississippi" → "misisipi"

7. Numara cuvintele dintr-o propozitie

int nrCuvinte(string s) {
    int cnt = 0;
    bool inCuv = false;
    for (int i=0; i < s.length(); i++) {
        if (!isspace(s[i])) { if (!inCuv) { cnt++; inCuv=true; } }
        else inCuv = false;
    }
    return cnt;
}
// "Bac 2024 info" → 3
🔄

Conversii numar ↔ sir

#include <cstdlib>   // atoi, atof, atol
#include <cstdio>    // sprintf

// C-style: numar → sir cu sprintf
char buf[50];
sprintf(buf, "%d", 42);          // buf = "42"
sprintf(buf, "%.2f", 3.14);     // buf = "3.14"
sprintf(buf, "%05d", 7);         // buf = "00007"

// C-style: sir → numar
int    n = atoi("123");           // 123
double d = atof("3.14");          // 3.14

// Manual: cifre din numar → sir
int nr = 12345;
char cifre[20];
int len = 0;
while (nr > 0) {
    cifre[len++] = '0' + nr % 10;
    nr /= 10;
}
cifre[len] = '\0';
for (int i=0; i < len/2; i++) swap(cifre[i], cifre[len-1-i]);
// cifre = "12345"

// Manual: sir de cifre → numar
char str[] = "12345";
int val = 0;
for (int i=0; str[i] != '\0'; i++)
    val = val * 10 + (str[i] - '0');
// val = 12345
🎬

Demo Interactiv — Operatii pe siruri

Experimentează cu operaţiile pe siruri direct în browser!

Apasă un buton...
Pașii vor apărea aici...
🧩

Probleme rezolvate — șiruri de caractere

5 probleme clasice, cu enunț, exemplu și soluție comentată.

1 Numără vocalele Ușor
Citește un șir de caractere (lungime ≤ 100). Afișează câte vocale (a, e, i, o, u — mari sau mici) conține.
Intrare:
Bacalaureat 2024
Ieșire:
7
💡 Vezi soluția
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
int main() {
    char s[105]; cin.getline(s, 105);
    int cnt = 0;
    for (int i = 0; s[i]; i++) {
        char c = tolower(s[i]);
        if (c=='a'||c=='e'||c=='i'||c=='o'||c=='u') cnt++;
    }
    cout << cnt;
    return 0;
}

Idee: tolower tratează uniform majuscule/minuscule; bucla for (...; s[i]; ...) se oprește când întâlnește '\0'.

2 Cel mai lung cuvânt Ușor
Citește o propoziție cu cuvinte separate prin spațiu. Afișează cel mai lung cuvânt (primul, dacă există mai multe de lungime maximă).
Intrare:
am dat bacalaureatul la informatica
Ieșire:
bacalaureatul
💡 Vezi soluția
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s, cuv, best;
    getline(cin, s); s += ' ';     // trick: spațiu final
    for (char c : s) {
        if (c == ' ') {
            if (cuv.length() > best.length()) best = cuv;
            cuv.clear();
        } else cuv += c;
    }
    cout << best;
    return 0;
}

Truc: adăugăm spațiu la final ca să procesăm și ultimul cuvânt fără cod special după buclă.

3 Palindrom (ignorând spații/case) Mediu
Verifică dacă o propoziție este palindrom ignorând spațiile și diferențele majuscule/minuscule. Afișează DA / NU.
Intrare:
Ele fac cafele
Ieșire:
DA
💡 Vezi soluția
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int main() {
    string s, t;
    getline(cin, s);
    for (char c : s)
        if (isalpha((unsigned char)c)) t += tolower(c);
    int l = 0, r = t.length() - 1;
    while (l < r) {
        if (t[l] != t[r]) { cout << "NU"; return 0; }
        l++; r--;
    }
    cout << "DA";
    return 0;
}

Idee: normalizăm întâi (păstrăm doar litere, minuscule), apoi aplicăm două-pointer. „Ele fac cafele" → "elefaccafele" → palindrom.

4 Frecvența literelor (a-z) Mediu
Citește un text și afișează, pentru fiecare literă mică, de câte ori apare (doar literele care apar cel puțin o dată).
Intrare:
informatica
Ieșire:
a:2 c:1 f:1 i:3 m:1 n:1 o:1 r:1 t:1
💡 Vezi soluția
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s; getline(cin, s);
    int f[26] = {0};
    for (char c : s)
        if (c >= 'a' && c <= 'z') f[c - 'a']++;
    for (int i = 0; i < 26; i++)
        if (f[i]) cout << (char)('a'+i) << ":" << f[i] << " ";
    return 0;
}

Cheia: c - 'a' convertește litera în index 0..25. Output-ul iese automat în ordine alfabetică pentru că iterăm i = 0..25.

5 Inversare cuvinte în propoziție Dificil
Citește o propoziție și afișează cuvintele în ordine inversă, păstrând câte un singur spațiu între ele.
Intrare:
am dat bacalaureatul la informatica
Ieșire:
informatica la bacalaureatul dat am
💡 Vezi soluția
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main() {
    string s; getline(cin, s);
    stringstream ss(s); string w;
    vector<string> v;
    while (ss >> w) v.push_back(w);
    for (int i = v.size() - 1; i >= 0; i--) {
        cout << v[i];
        if (i > 0) cout << ' ';
    }
    return 0;
}

De ce stringstream: ss >> w tratează automat spații multiple ca un singur separator. Stocăm cuvintele într-un vector și le afișăm invers.

Alternativă în O(1) memorie: inversezi întreg șirul, apoi inversezi fiecare cuvânt (truc clasic).

💪 Quiz-ul interactiv de la Exerciții și problemele BAC din secțiunea următoare îți consolidează aceste tehnici.
💪

Exerciţii interactive — testează cunoştinţele

📝

Probleme tip BAC — siruri de caractere

Problema 1 (BAC 2022): Cititi un sir de caractere si afisati cel mai lung cuvant.
Solutie:
string linie, cuvantCurent, maxCuvant;
getline(cin, linie);
linie += " ";
for (int i=0; i < linie.length(); i++) {
    if (linie[i] != ' ') cuvantCurent += linie[i];
    else {
        if (cuvantCurent.size() > maxCuvant.size())
            maxCuvant = cuvantCurent;
        cuvantCurent = "";
    }
}
cout << maxCuvant;
Problema 2: Dat un sir de caractere format din litere mici. Inlocuiti toate vocalele cu '*'.
Solutie:
string vocale = "aeiou";
for (int i=0; i < s.length(); i++)
    if (vocale.find(s[i]) != string::npos)
        s[i] = '*';
Problema 3: Data o propozitie, afisati cuvintele in ordine inversa.
Solutie:
char s[501], cuv[50][50];
int nc = 0;
cin.getline(s, 501);
char *p = strtok(s, " ");
while (p != NULL) { strcpy(cuv[nc++], p); p = strtok(NULL, " "); }
for (int i=nc-1; i >= 0; i--) cout << cuv[i] << " ";
Problema 4: Verificati daca doua siruri sunt anagrame.
Solutie cu tablou frecvente:
char a[101], b[101];
cin.getline(a, 101); cin.getline(b, 101);
if (strlen(a) != strlen(b)) { cout << "NU"; return 0; }
int freq[256] = {0};
for (int i=0; a[i]; i++) freq[(unsigned char)a[i]]++;
for (int i=0; b[i]; i++) freq[(unsigned char)b[i]]--;
for (int i=0; i < 256; i++)
    if (freq[i] != 0) { cout << "NU"; return 0; }
cout << "DA";
Problema 5: Numarati cate cuvinte dintr-o propozitie incep cu litera mare.
Solutie:
char s[501];
cin.getline(s, 501);
int cnt = 0;
bool inCuv = false;
for (int i=0; s[i]; i++) {
    if (!isspace(s[i])) {
        if (!inCuv && isupper(s[i])) cnt++;
        inCuv = true;
    } else inCuv = false;
}
cout << cnt;
Problema 6: Cititi un sir si afisati toate cuvintele care sunt palindroame.
Solutie:
auto isPal = [](string w) {
    for (int i=0; i < w.size()/2; i++)
        if (w[i] != w[w.size()-1-i]) return false;
    return true;
};
string linie; getline(cin, linie); linie += " ";
string cuvant = "";
for (char c : linie) {
    if (c != ' ') cuvant += c;
    else {
        if (!cuvant.empty() && isPal(cuvant)) cout << cuvant << " ";
        cuvant = "";
    }
}