Șiruri de caractere

Ce sunt șirurile de caractere?

Cum declarăm, citim și afișăm șiruri de caractere în C++ pentru BAC.

char[] versus string -- de ce folosim char[] la BAC

La BAC-ul la informatică, șirurile de caractere se declară întotdeauna cu char[], nu cu string. Dacă folosești string, poți pierde puncte.

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

Aceasta este singura librărie pentru șiruri pe care o folosim. Nu includem <string> sau <cctype>.


Declararea unui șir -- ce dimensiune dăm?

Dimensiunea șirului trebuie gândită în funcție de enunț:

Dacă enunțul spune "cel mult N caractere", declari char s[N+1] (plus 1 pentru \0). De exemplu, "cel mult 20 de caractere" => char s[21].

Dacă șirul se modifică prin adăugare de caractere, trebuie să te gândești cât de mare poate deveni. De exemplu, dacă adaugi - între fiecare pereche de cuvinte dintr-un text de 100 de caractere, rezultatul poate crește cu până la 3 * (nr_cuvinte - 1) caractere -- deci ai nevoie de mai mult.

Dacă nu știi exact cât de mare va fi șirul, folosește 256 ca valoare sigură pentru texte scurte sau 1001 pentru texte mai lungi.

char s[101];    // dacă enunțul spune "cel mult 100 de caractere"
char s[256];    // valoare sigură când nu ai o limită clară

Șirul auxiliar t

Șirul auxiliar t are de obicei aceeași dimensiune ca s, sau mai mare dacă rezultatul final poate fi mai lung:

char s[201];    // text de cel mult 200 de caractere
char t[201];    // auxiliar de aceeași dimensiune -- dacă nu adaugi caractere
char t[400];    // auxiliar mai mare -- dacă rezultatul poate fi aproape dublu, aducem și șirul s la aceeași valoare.

Caracterul nul \0

Un șir de caractere în C++ se termină cu caracterul special \0 (caracterul nul). El nu e vizibil, dar este prezent și semnalează sfârșitul șirului.

char s[21] = "bac";  // în memorie: b a c \0
// s[0]='b', s[1]='a', s[2]='c', s[3]='\0'

Greșeli frecvente

Nu poți atribui direct un șir cu = după declarare:

char s[21];
s = "bac";        // GREȘIT -- eroare de compilare!
strcpy(s, "bac"); // CORECT

Nu poți compara șiruri cu ==:

if (s == t)          // GREȘIT -- compară adrese, nu conținut!
if (strcmp(s, t)==0) // CORECT

Citirea unui șir: cin >> și cin.getline

Există două moduri de citire a unui șir, și trebuie să știi exact când să folosești fiecare.


cin >> s (fără spații)

char s[N+1];  // N = lungimea maximă din enunț
cin >> s;

Citește caractere până la primul spațiu, tab sau enter. Spațiile nu sunt incluse în șir.

Exemplu: dacă introduci informatica cpp, s va conține doar informatica.

Când folosești: când citești un singur cuvânt.


cin.getline(s, N+1) (cu spații)

char s[N+1];  // N = lungimea maximă din enunț
cin.getline(s, N+1);

Citește o linie întreagă, inclusiv spațiile, până la enter. Enter-ul nu e inclus în șir.

Când folosești: când citești un text cu mai multe cuvinte separate prin spații.

Notă: Al doilea parametru al getline trebuie să fie dimensiunea bufferului declarat, nu o altă valoare.

Problema clasică: mix de cin >> și getline

Dacă citești un număr cu cin >> n și apoi un șir cu cin.getline, trebuie să "consumi" enter-ul rămas:

int n;
char s[N+1];
cin >> n;
cin.ignore();         // consumă enter-ul rămas
cin.getline(s, N+1);

Fără cin.ignore(), getline va citi un șir gol.


Afișarea unui șir

cout << s;      // afișează tot șirul până la \0
cout << s[i];   // afișează un singur caracter

Accesul la un caracter

char s[21] = "bac";
cout << s[0]; // b
cout << s[1]; // a
cout << s[2]; // c
// s[3] = '\0' (sfârșitul șirului)

Parcurgerea unui șir

char s[N+1];
cin >> s;
for (int i = 0; i < strlen(s); i++) {
    cout << s[i] << " ";
}

Sau varianta clasică BAC cu while:

int i = 0;
while (s[i] != '\0') {
    cout << s[i];
    i++;
}

strlen -- lungimea unui șir

#include <cstring>

strlen(s) returnează numărul de caractere din șir, fără a număra caracterul \0.

char s[256] = "bac";
cout << strlen(s); // afișează 3

Atenție la folosirea strlen în for

// Varianta corectă dar mai lentă:
for (int i = 0; i < strlen(s); i++) { ... }

// Varianta mai eficientă:
int n = strlen(s);
for (int i = 0; i < n; i++) { ... }

În prima variantă, strlen e apelată la fiecare iterație. La BAC ambele sunt acceptate.


strlen și tipul returnat

La BAC declarăm întotdeauna:

int n = strlen(s);

Și folosim n în loc de strlen(s) în bucle.


Greșeli frecvente

char s[256] = "bac";
cout << sizeof(s);    // 256 -- dimensiunea bufferului, NU lungimea șirului!
cout << strlen(s);    // 3   -- lungimea reală

Nu confunda sizeof cu strlen!


Șir gol

char s[256] = "";
cout << strlen(s); // 0
// s[0] = '\0' direct