Funcțiile din cstring

strlen, strcpy, strcat, strcmp, strchr și strstr: ce face fiecare, ce capcane are și cum se combină.

Ce ai la dispoziție

Toate cer #include <cstring> și sunt permise la bac.

funcțiece face
strlen(s)lungimea șirului, fără terminator
strcpy(d, s)copiază s peste d
strncpy(d, s, k)copiază cel mult k caractere
strcat(d, s)adaugă s la sfârșitul lui d
strcmp(a, b)compară alfabetic
strchr(s, c)caută un caracter
strstr(s, t)caută un subșir
strtok(s, sep)taie șirul în bucăți

strlen

char s[] = "informatica";
cout << strlen(s);       // 11

Numără caracterele până la '\0', deci durează cât lungimea șirului. De aceea nu o pui în condiția unei bucle.

strcpy și strcat

char a[50] = "bac", b[50] = "2026";
strcat(a, b);            // a devine "bac2026"
strcpy(b, a);            // b devine "bac2026"

Amândouă scriu în primul parametru și au aceeași capcană: nu verifică dacă încape.

char mic[5];
strcpy(mic, "text foarte lung");   // scrie peste memoria de după

Nu primești nicio eroare, dar programul devine imprevizibil. Destinația trebuie declarată destul de mare. La strcat, cât suma lungimilor plus unu.

Nu poți atribui șiruri cu =:

char a[50], b[50] = "text";
a = b;              // nu compilează
strcpy(a, b);       // corect

strcmp

strcmp(a, b)

întoarce 0 dacă șirurile sunt identice, un număr negativ dacă a este alfabetic înaintea lui b și unul pozitiv dacă este după.

if (strcmp(a, b) == 0) cout << "identice";
if (strcmp(a, b) < 0)  cout << "a este primul alfabetic";

Cea mai frecventă greșeală de la șiruri:

if (a == b)                 // GREȘIT: compară adrese, nu text
if (strcmp(a, b) == 0)      // corect

Prima variantă compilează și este aproape întotdeauna falsă, chiar dacă textele sunt identice.

A doua capcană este semnul. strcmp întoarce 0 la egalitate, deci if (strcmp(a, b)) înseamnă „sunt diferite", invers față de cum te-ai aștepta.

Comparația este după coduri ASCII, deci literele mari vin înaintea celor mici: "Zebra" este înaintea lui "anason". Dacă vrei ordine alfabetică adevărată, adu totul la aceleași litere înainte de comparație.

strchr și strstr

Amândouă întorc adresa primei apariții sau NULL dacă nu au găsit nimic.

if (strchr(s, 'a') != NULL)
    cout << "contine litera a";

if (strstr(s, "bac") != NULL)
    cout << "contine cuvantul bac";

Pentru poziție, scazi adresa de început:

char *p = strstr(s, "bac");
if (p != NULL)
    cout << "prima aparitie pe pozitia " << p - s;

p - s este diferența dintre două adrese, adică numărul de caractere dintre ele. Asta e chiar poziția, numărată de la 0.

Pentru toate aparițiile, reiei căutarea de după cea găsită:

char *p = strstr(s, "ana");
while (p != NULL) {
    cout << p - s << " ";
    p = strstr(p + 1, "ana");
}

Scrii p + 1, nu p. Altfel găsești la nesfârșit aceeași apariție.

strtok

Funcția taie un șir în bucăți, după niște separatori.

char s[] = "unu doi trei";
char *p = strtok(s, " ");
while (p != NULL) {
    cout << p << "\n";
    p = strtok(NULL, " ");
}

Are două particularități la care nu te-ai aștepta:

Primul apel primește șirul, celelalte primesc NULL. Funcția reține singură unde a rămas.

Șirul original este distrus. strtok înlocuiește separatorii cu '\0'. Dacă mai ai nevoie de text, fă o copie înainte cu strcpy.

Poți da mai mulți separatori deodată: strtok(s, " ,.;") taie după oricare dintre ei. E util la textele cu semne de punctuație.

Un exemplu complet

Se citesc un text și un cuvânt. Să se afișeze de câte ori apare cuvântul în text, ca subșir.

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

char s[256], t[32];

int main() {
    cin.getline(s, 256);
    cin.getline(t, 32);

    int cate = 0;
    char *p = strstr(s, t);
    while (p != NULL) {
        cate++;
        p = strstr(p + 1, t);
    }

    cout << cate;
    return 0;
}

Programul numără și aparițiile suprapuse. Pentru textul aaaa și cuvântul aa dă 3. Dacă enunțul cere doar aparițiile care nu se suprapun, avansezi cu p + strlen(t) în loc de p + 1.

De reținut

  • strcmp întoarce 0 la egalitate. Nu compara șiruri cu ==.
  • strcpy și strcat nu verifică dimensiunea destinației.
  • Șirurile nu se atribuie cu =.
  • strchr și strstr întorc o adresă sau NULL. Poziția este p - s.
  • Reia căutarea de la p + 1, altfel bucla nu se termină.
  • strtok distruge șirul original și primește NULL la apelurile următoare.