Atestia

Lucrul cu fișiere în C++ la atestatul de informatică

Citirea din fișiere text cu ifstream: matrici, șiruri de caractere, citire până la sfârșit, structuri și sortare după o valoare calculată — cu problemele de atestat în care apar.

15 din cele 40 de probleme de programare din sesiunea Dolj 2026 citesc datele dintr-un fişier. Vestea bună: ifstream se folosește exact ca cin, iar odată ce știi cele trei moduri de citire, partea de fişiere devine mecanică și te poți concentra pe logica problemei.

Scheletul de bază

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

int main() {
    ifstream f("date.in");      // deschidere
    // ... citire cu f >> sau f.getline
    f.close();                  // inchidere
}

ifstream e „ruda" lui cin pentru fişiere. Tot ce știi despre cin >> funcționează identic cu f >>. Diferă doar două lucruri: îl deschizi cu numele fişierului și îl închizi la final.

f.close() nu schimbă rezultatul la programe mici, dar e cerut de barem — scrie-l.

Atenție la sursa datelor. Multe enunțuri citesc datele principale din fişier, dar parametrii de la tastatură: liniile de interschimbat, cuvântul căutat. Sunt fluxuri separate — f >> pentru fişier, cin >> pentru tastatură. Confuzia face programul să pară blocat.

Cele trei moduri de citire

Alegerea depinde de ce conține fişierul. E singura decizie reală pe care o iei.

1. Știi câte valori sunt

Formatul cel mai comun: prima linie spune cât urmează.

int n;
f >> n;
for (int i = 0; i < n; i++) f >> x[i];

Pentru matrici, n e dimensiunea și urmează două bucle imbricate:

for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
        f >> a[i][j];

Toate cele 9 probleme cu matrici folosesc acest tipar, cu fişierul mat.in. Detaliile de parcurgere — linii, coloane, diagonale — sunt explicate pe pagina dedicată matricilor.

2. Nu știi câte valori sunt

Când fişierul conține doar numere, fără un n la început, citești până se termină:

int n = 0;
while (f >> x[n]) n++;

Citirea returnează o valoare care devine false când nu mai are ce citi, deci bucla se oprește singură. La final, n conține exact numărul de valori.

Același tipar funcționează și pe cuvinte, pentru că >> se oprește automat la spații:

while (f >> cuvant) { /* ... */ }

Probleme: valorile distincte și maximul · numerele distincte din două fişiere

Două fişiere? Citește-le în același vector, fără să resetezi n. A doua buclă continuă de unde s-a oprit prima, iar de acolo ai o singură problemă.

3. Un rând întreg de text

Când fişierul conține o propoziție, cu spații și semne de punctuație:

char s[201];
f.getline(s, 201);

f >> s nu merge aici — s-ar opri la primul spațiu și ai prelua doar primul cuvânt.

Dimensiunea e 201 pentru „cel mult 200 de caractere": mai trebuie un loc pentru terminatorul '\0', pe care C++ îl adaugă la final. Parcurgerea merge până la el, deci nu ai nevoie de lungime:

for (int i = 0; s[i] != '\0'; i++) { /* ... */ }

Probleme: numărul de vocale · aparițiile unui cuvânt

Lucrul cu caractere

Două tehnici acoperă majoritatea subiectelor cu text.

Conversia majusculă → minusculă, ca să nu scrii zece comparații:

if (c >= 'A' && c <= 'Z') c = c + 32;

Funcționează pentru că, în ASCII, literele mici sunt cu exact 32 de poziții după cele mari ('A' = 65, 'a' = 97). Verificarea intervalului e necesară — altfel strici cifrele și semnele de punctuație.

Compararea cuvintelor se face cu strcmp, nu cu ==:

if (strcmp(cuvant, cautat) == 0) nr++;

== compară adresele din memorie, nu conținutul. Iar strcmp returnează 0 la egalitate, nu 1 — valoarea returnată e diferența în ordine alfabetică. Necesită #include <cstring>.

Citind cuvânt cu cuvânt cu f >> cuvant, delimitarea se rezolvă singură: masini nu va fi niciodată egal cu si. Dacă ai căuta subşiruri cu strstr, ai număra și aparițiile din interiorul altor cuvinte.

Structuri și sortare după o valoare calculată

Când fişierul conține perechi de numere care formează o entitate — un număr complex, o fracție, un elev — se folosește struct. Astfel datele rămân lipite la sortare.

Tiparul are trei câmpuri: datele originale plus valoarea după care sortezi, calculată o singură dată la citire:

struct Fractie {
    int a, b;                   // datele din fisier
    double valoare;             // ce folosesti la comparatii
};

f >> fr[i].a >> fr[i].b;
fr[i].valoare = (double)fr[i].a / fr[i].b;

Conversia (double) e obligatorie. Între doi int, a / b dă împărțire întreagă: 1 / 4 ar fi 0, nu 0.25, iar sortarea ar ieși complet greșită.

Sortarea interschimbă structura întreagă, deci câmpurile nu se desperechează:

if (fr[j].valoare < fr[i].valoare) {    // "<" crescator, ">" descrescator
    Fractie aux = fr[i];
    fr[i] = fr[j];
    fr[j] = aux;
}

Probleme: ordonarea fracțiilor · modulele numerelor complexe

Formatarea numerelor reale

Când enunțul cere un anumit număr de zecimale:

#include <iomanip>
cout << fixed << setprecision(2) << x;      // mereu 2 zecimale: 5.00

Se scrie o singură dată, înainte de buclă — setarea rămâne activă.

Diferența care contează: cu fixed numeri zecimalele; fără fixed, setprecision numără cifrele semnificative, iar zecimalele nule dispar (5 în loc de 5.00). Citește exemplul din enunț ca să vezi care formă se cere.

Greșeli care se repetă

Toate problemele din această categorie

Fiecare are rezolvare completă în C++, explicată pas cu pas.