Șirurile de caractere apar la BAC informatică în aproape fiecare sesiune: la itemii scurți din Subiectul II („ce se afișează în urma executării secvenței…”) și la programul din Subiectul III. În C++ lucrăm la BAC cu șiruri în stilul C: tablouri de tip char terminate cu caracterul nul '\0', prelucrate cu funcțiile din biblioteca <cstring>. Dacă înțelegi cum arată un astfel de șir în memorie, toate funcțiile devin logice.
Cum arată un șir char[] în memorie
Declarația char s[21] = "bac"; rezervă 21 de octeți. În primii patru se află 'b', 'a', 'c' și '\0'. Terminatorul nul marchează sfârșitul șirului — toate funcțiile din <cstring> se opresc la el. De aici rezultă prima regulă: un șir de cel mult 20 de caractere are nevoie de un tablou de cel puțin 21.
Fiecare caracter este, de fapt, un cod numeric (codul ASCII). Merită să reții câteva valori: '0' = 48, 'A' = 65, 'a' = 97. Literele mari și cele mici corespunzătoare diferă prin 32, iar literele sunt consecutive în alfabet. Consecințe utile:
s[i] - '0'transformă o cifră-caracter în valoarea ei numerică ('7' - '0'= 7);s[i] - 'a' + 'A'transformă o literă mică în majusculă;s[i] >= 'a' && s[i] <= 'z'verifică dacă un caracter este literă mică.
Citirea unui șir de caractere
cin >> s citește doar până la primul spațiu, deci e potrivit doar pentru un singur cuvânt. Pentru un text care conține spații, folosește cin.getline(s, 101), unde 101 este numărul maxim de caractere citite plus unu (pentru terminator). Dacă înainte ai citit un număr cu cin >> n, în buffer rămâne caracterul de linie nouă; scapă de el cu cin.get() înainte de getline, altfel vei citi un șir vid.
Funcțiile de bază din cstring
| Funcție | Ce face | Exemplu |
|---|---|---|
strlen(s) | numărul de caractere până la '\0' | strlen("informatica") = 11 |
strcpy(d, s) | copiază s în d (inclusiv terminatorul) | d devine o copie a lui s |
strcat(d, s) | adaugă s la finalul lui d | "bac" + "info" → "bacinfo" |
strcmp(a, b) | compară lexicografic | <0, 0 sau >0 |
strchr(s, c) | adresa primei apariții a caracterului c | NULL dacă nu apare |
strstr(s, t) | adresa primei apariții a subșirului t | NULL dacă nu apare |
strlen
Returnează lungimea, fără terminator. Pentru char s[] = "informatica";, strlen(s) este 11, iar caracterele sunt la pozițiile 0…10. Parcurgerea standard este for (i = 0; i < n; i++), cu n = strlen(s) calculat o singură dată, înainte de buclă.
strcpy și strcat
Ambele scriu în primul parametru, așa că acesta trebuie să aibă loc suficient. Exemplu:
char a[51] = "bac", b[51] = "info";
strcat(a, " ");
strcat(a, b);
cout << a; // bac info
strcpy(b, a + 4);
cout << b; // info
Expresia a + 4 înseamnă „șirul care începe de la poziția 4 a lui a”. Asta e o idee pe care o vei folosi des: un pointer în interiorul unui șir este tot un șir, care se termină la același '\0'.
strcmp
Compară caracter cu caracter, de la stânga, până la prima diferență. Rezultatul e negativ dacă primul șir e mai mic lexicografic, 0 dacă sunt egale și pozitiv altfel. Nu te baza pe valoarea exactă (−1, −3 etc.), ci doar pe semn.
strcmp("ana", "andrei")< 0: primele două caractere coincid, iar la poziția 2,'a'<'d'.strcmp("mar", "mare")< 0: un prefix este mai mic decât șirul complet.strcmp("Zebra", "albina")< 0:'Z'(90) are cod mai mic decât'a'(97) — majusculele vin înaintea literelor mici.
Comparația cu == între două tablouri char compară adrese, nu conținut. Pentru egalitate folosește întotdeauna strcmp(a, b) == 0.
strchr și strstr
Ambele returnează un pointer (adresa) sau NULL. Ca să obții poziția, scazi adresa de început a șirului:
char s[] = "informatica";
char *p = strchr(s, 'f');
if (p != NULL) cout << p - s; // 2
char t[] = "bacalaureat";
char *q = strstr(t, "laur");
if (q != NULL) cout << q - t; // 4
Un truc foarte util: strchr("aeiou", c) != NULL verifică dacă litera mică c este vocală, fără cinci comparații legate cu ||. Ai grijă să nu-l aplici pe caracterul '\0', pe care strchr îl găsește în orice șir.
Exemplu complet: numărarea aparițiilor unui cuvânt
Se citește un text și un cuvânt; afișăm de câte ori apare cuvântul ca secvență în text. După fiecare apariție găsită, continuăm căutarea de la caracterul următor.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[256], c[31];
cin.getline(s, 256);
cin.getline(c, 31);
int nr = 0;
char *p = strstr(s, c);
while (p != NULL)
{
nr++;
p = strstr(p + 1, c);
}
cout << nr;
return 0;
}
Pentru textul ana are banane și secvența an, programul afișează 3: o apariție în „ana” (poziția 0) și două în „banane” (pozițiile 9 și 11). Atenție la aparițiile suprapuse: în textul banana, secvența ana apare la pozițiile 1 și 3, care se suprapun, iar programul de mai sus afișează 2. Dacă enunțul cere apariții care nu se suprapun, continui căutarea cu p + strlen(c) în loc de p + 1 și obții 1.
Ștergerea unui caracter din șir
Ca să elimini caracterul de la poziția k, muți toate caracterele de după el cu o poziție la stânga, inclusiv terminatorul. Multe culegeri scriu strcpy(s + k, s + k + 1), dar standardul nu garantează că strcpy funcționează corect când sursa și destinația se suprapun. Varianta sigură folosește un șir auxiliar:
char aux[256];
strcpy(aux, s + k + 1);
strcpy(s + k, aux);
Și mai simplu, poți face deplasarea cu o buclă: for (i = k; s[i] != '\0'; i++) s[i] = s[i + 1]; — se oprește după ce a copiat și terminatorul.
De reținut
- ● Un șir char[] se termină cu
'\0'; tabloul trebuie să aibă cu un element mai mult decât lungimea maximă. - ●
cin >> scitește un cuvânt,cin.getline(s, dim)citește o linie întreagă. - ● strcmp returnează un semn, nu adevărat/fals; egalitatea se testează cu
strcmp(a, b) == 0. - ● strchr și strstr returnează adrese; poziția se obține ca
p - s. - ● 'A' = 65, 'a' = 97, '0' = 48; literă mică → majusculă: scazi 32.