🔤 Ş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

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"

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...
💪

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 = "";
    }
}