Funcții din
cstring
Am învățat să lucrăm cu șiruri de caractere manual: parcurgere, lungime, inversare, comparare - totul caracter cu caracter.
Biblioteca cstring (sau
string.h) ne oferă funcții gata
făcute care fac aceste operații mai ușor și mai
rapid.
#include <cstring>strlen -
lungimea unui șir
int lungime = strlen(s);Returnează numărul de caractere până la
'\0' (fără a-l include).
#include <fstream>
#include <cstring>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
char s[101];
int main()
{
fin >> s;
fout << strlen(s);
return 0;
}date.in:
Informaticadate.out:
11Echivalentul manual
// strlen face exact asta intern:
int lung = 0;
while (s[lung] != '\0') {
lung++;
}Atenție la performanță: strlen
parcurge tot șirul la fiecare apel. Dacă o folosești în condiția
unui for, se recalculează la
fiecare iterație. Salvează rezultatul într-o
variabilă:
// GREȘIT (lent):
for (int i = 0; i < strlen(s); i++) { ... }
// CORECT (rapid):
int lung = strlen(s);
for (int i = 0; i < lung; i++) { ... }strcpy -
copierea unui șir
strcpy(destinatie, sursa);Copiază conținutul lui sursa în
destinatie (inclusiv '\0').
char a[20] = "Salut";
char b[20];
strcpy(b, a); // b devine "Salut"
fout << b; // SalutDe ce avem nevoie?
Nu putem copia șiruri cu =:
char a[20] = "Salut";
char b[20];
b = a; // GREȘIT! Nu compilează
strcpy(b, a); // CORECTOperatorul
=nu funcționează pe vectori (și deci nici pe șiruri de caractere).
strcat
- concatenarea (lipirea) a două șiruri
strcat(destinatie, sursa);Adaugă conținutul lui sursa la
sfârșitul lui destinatie.
char s[50] = "Buna ";
strcat(s, "ziua");
fout << s; // Buna ziua
strcat(s, "!");
fout << s; // Buna ziua!Pas cu pas
Înainte: s = "Buna " (5 caractere + '\0')
strcat(s, "ziua"):
- caută '\0' în s (poziția 5)
- copiază "ziua" începând de la poziția 5
- pune '\0' la final
După: s = "Buna ziua" (9 caractere + '\0')
Atenție la dimensiune
Vectorul destinație trebuie să fie suficient de mare pentru a încăpea ambele șiruri:
char s[5] = "Buna";
strcat(s, " ziua"); // GREȘIT! Depășire - s are doar 5 pozițiistrcmp -
compararea a două șiruri
int rezultat = strcmp(a, b);Compară lexicografic (ca în dicționar) și returnează:
| Rezultat | Semnificație |
|---|---|
0 |
Șirurile sunt egale |
< 0 (negativ) |
a este înaintea lui
b (a < b) |
> 0 (pozitiv) |
a este după b (a
> b) |
char a[] = "abc";
char b[] = "abd";
int r = strcmp(a, b);
if (r == 0) {
fout << "Egale";
} else if (r < 0) {
fout << "a vine inainte de b";
} else {
fout << "a vine dupa b";
}Output: a vine inainte de b
(pentru că 'c' < 'd')
Exemple
| a | b | strcmp(a, b) | Explicație |
|---|---|---|---|
"abc" |
"abc" |
0 | Identice |
"abc" |
"abd" |
< 0 | 'c' < 'd' |
"abd" |
"abc" |
> 0 | 'd' > 'c' |
"ab" |
"abc" |
< 0 | "ab" e mai scurt |
"abc" |
"ab" |
> 0 | "abc" e mai lung |
"Ana" |
"ana" |
< 0 | 'A' (65) < 'a' (97) |
Important: literele mari au coduri ASCII mai mici decât cele mici, deci
"Ana"<"ana".
Verificare egalitate: nu folosi
== pe șiruri! Folosește
strcmp(a, b) == 0:
if (strcmp(s, "parola") == 0) {
fout << "Acces permis";
}strchr -
căutarea unui caracter
char *poz = strchr(s, 'a');Caută prima apariție a caracterului
'a' în șirul s. Returnează un
pointer către acea poziție, sau
NULL dacă nu există.
char s[] = "Informatica";
char *p = strchr(s, 'a');
if (p != NULL) {
fout << "Gasit la pozitia " << (p - s);
} else {
fout << "Nu exista";
}Output: Gasit la pozitia 6
De ce p - s?
p este un pointer către caracterul găsit,
s este un pointer către începutul șirului.
Diferența p - s dă indicele
(poziția) în vector.
strstr -
căutarea unui subșir
char *poz = strstr(s, sub);Caută prima apariție a subșirului
sub în șirul s.
char s[] = "Buna ziua frumoasa";
char *p = strstr(s, "ziua");
if (p != NULL) {
fout << "Gasit la pozitia " << (p - s);
} else {
fout << "Nu exista";
}Output: Gasit la pozitia 5
strtok
- împărțirea în cuvinte (tokenizare)
char *cuv = strtok(s, separatori);Împarte șirul s în “tokeni” (cuvinte) pe baza
separatorilor dați.
#include <fstream>
#include <cstring>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
char s[1001];
int main()
{
fin.getline(s, 1001);
char *cuv = strtok(s, " ");
while (cuv != NULL) {
fout << cuv << endl;
cuv = strtok(NULL, " ");
}
return 0;
}date.in:
Ana are mere rosiidate.out:
Ana
are
mere
rosiiCum funcționează?
- Primul apel:
strtok(s, " ")- caută primul cuvânt dins, despărțit de spații. - Apelurile următoare:
strtok(NULL, " ")- continuă căutarea de unde a rămas. - Când nu mai sunt cuvinte, returnează
NULL.
Separatori multipli
Putem specifica mai mulți separatori:
char *cuv = strtok(s, " ,.;:!?");Aceasta împarte textul la spații, virgule, puncte, etc.
Cum funcționează strtok intern?
strtok modifică șirul original!
Înlocuiește fiecare separator găsit cu '\0',
transformând efectiv șirul într-o serie de subșiruri.
De exemplu, "Ana are mere" devine:
A n a \0 a r e \0 m e r e \0
De aceea:
- Nu folosi
strtokpe un șir constant ("text") - Dacă ai nevoie de șirul original, fă o copie înainte
La apelurile ulterioare cu NULL, funcția își
amintește intern unde a rămas.
Tabel rezumativ
| Funcție | Ce face | Exemplu |
|---|---|---|
strlen(s) |
Lungimea șirului | strlen("abc") = 3 |
strcpy(dest, src) |
Copiază src în dest | strcpy(b, a) |
strcat(dest, src) |
Lipește src la sfârșitul dest | strcat(s, "!") |
strcmp(a, b) |
Compară a cu b | 0 dacă egale |
strchr(s, c) |
Caută caracterul c | Pointer sau NULL |
strstr(s, sub) |
Caută subșirul sub | Pointer sau NULL |
strtok(s, sep) |
Împarte în cuvinte | Pointer sau NULL |
Problema completă: sortarea cuvintelor
Citim o propoziție și afișăm cuvintele în ordine alfabetică.
#include <fstream>
#include <cstring>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
char s[1001];
char cuvinte[100][101]; // maxim 100 de cuvinte, fiecare de maxim 100 caractere
int nrCuv;
int main()
{
fin.getline(s, 1001);
// Împărțim în cuvinte
char *p = strtok(s, " ");
while (p != NULL) {
strcpy(cuvinte[nrCuv], p);
nrCuv++;
p = strtok(NULL, " ");
}
// Sortăm (bubble sort pe șiruri)
for (int i = 0; i < nrCuv - 1; i++) {
for (int j = i + 1; j < nrCuv; j++) {
if (strcmp(cuvinte[i], cuvinte[j]) > 0) {
char aux[101];
strcpy(aux, cuvinte[i]);
strcpy(cuvinte[i], cuvinte[j]);
strcpy(cuvinte[j], aux);
}
}
}
// Afișăm
for (int i = 0; i < nrCuv; i++) {
fout << cuvinte[i] << " ";
}
return 0;
}date.in:
mere ana banane cireasa anadate.out:
ana ana banane cireasa mereCe observăm?
- Interschimbarea șirurilor se face cu
strcpy(prin variabila auxiliarăaux), nu cu= - Compararea se face cu
strcmp, nu cu<sau> cuvinte[100][101]este o matrice de caractere: fiecare linie este un cuvânt
Greșeli frecvente
1. Lipsa lui
#include <cstring>
Fără această bibliotecă, funcțiile strlen,
strcpy, etc. nu sunt recunoscute.
2. Depășire la
strcat și strcpy
char s[5] = "ABC";
strcat(s, "DEFGH"); // GREȘIT! Depășirea vectoruluiVectorul destinație trebuie să fie suficient de mare.
3. Compararea cu
== în loc de strcmp
if (a == b) // GREȘIT - compară adresele
if (strcmp(a, b) == 0) // CORECT - compară conținutul4. strtok pe șir
constant
strtok("Ana are", " "); // GREȘIT! Modifică un șir constantstrtok modifică șirul original. Folosește-l doar
pe vectori char[].
5.
Uitarea lui NULL la apelurile ulterioare
strtok
char *p = strtok(s, " "); // primul apel: cu s
p = strtok(s, " "); // GREȘIT! Reîncepe de la capăt
p = strtok(NULL, " "); // CORECT! Continuă de unde a rămas6. strlen în
condiția for
for (int i = 0; i < strlen(s); i++) // LENT! strlen se recalculează la fiecare pasSalvează lungimea într-o variabilă înainte de buclă.
Ce să reții
- Biblioteca
cstringoferă funcții gata făcute pentru operații pe șiruri. strlen- lungimea,strcpy- copiere,strcat- concatenare.strcmp- comparare (returnează 0 dacă egale, < 0 sau > 0 altfel).strchr- caută caracter,strstr- caută subșir,strtok- împarte în cuvinte.- Nu folosim
=pentru copiere sau==pentru comparare pe șiruri. strtokmodifică șirul original și foloseșteNULLla apelurile ulterioare.- Mereu verificăm dimensiunile vectorilor la
strcpyșistrcat.