Programare Competitivă

Fișiere text

Până acum, toate programele noastre citeau date de la tastatură (cin) și afișau rezultate pe ecran (cout).

Dar la concursuri (inclusiv Olimpiada), datele se citesc dintr-un fișier și rezultatele se scriu în alt fișier.


De ce fișiere?

  • La concursuri, evaluatorul nu tastează datele - le pune într-un fișier.
  • Rezultatul tău trebuie să apară într-un fișier pe care evaluatorul îl verifică.
  • Fișierele pot conține cantități mari de date, imposibil de tastat manual.

Ce avem nevoie?

Pentru a lucra cu fișiere în C++, folosim biblioteca fstream:

#include <fstream>

Aceasta ne oferă:

  • ifstream - pentru citire din fișier (input file stream)
  • ofstream - pentru scriere în fișier (output file stream)

Citirea dintr-un fișier

Forma generală

#include <fstream>
using namespace std;
ifstream fin("date.in");

int main()
{
    int x;
    fin >> x;

    return 0;
}

Ce face fiecare linie?

  1. ifstream fin("date.in"); - deschide fișierul date.in pentru citire. Se pune după using namespace std;, ca variabilă globală.
  2. fin >> x; - citește o valoare din fișier, exact ca cin >> x.

fin funcționează identic cu cin, dar citește din fișier în loc de tastatură. Tot ce știi despre cin se aplică și la fin.


Scrierea într-un fișier

Forma generală

#include <fstream>
using namespace std;
ofstream fout("date.out");

int main()
{
    fout << 42 << endl;

    return 0;
}

Ce face fiecare linie?

  1. ofstream fout("date.out"); - deschide (sau creează) fișierul date.out pentru scriere. Se pune tot ca variabilă globală.
  2. fout << 42 << endl; - scrie în fișier, exact ca cout.

fout funcționează identic cu cout, dar scrie în fișier în loc de pe ecran.


Structura standard a unui program cu fișiere

Aceasta este structura pe care o vom folosi mereu:

#include <fstream>
using namespace std;
ifstream fin("nume.in");
ofstream fout("nume.out");

int main()
{
    // citim cu fin, scriem cu fout

    return 0;
}

Declarăm fin și fout global, imediat după using namespace std;. Așa sunt accesibile oriunde în program.


Primul exemplu complet

Problema: citim două numere din numere.in și scriem suma lor în numere.out.

#include <fstream>
using namespace std;
ifstream fin("numere.in");
ofstream fout("numere.out");

int main()
{
    int a, b;
    fin >> a >> b;

    fout << a + b;

    return 0;
}

numere.in:

12 18

numere.out:

30

Citirea mai multor valori

La fel ca la cin, putem citi mai multe valori:

fin >> a >> b >> c;

Sau într-o buclă:

int n;
fin >> n;

for (int i = 1; i <= n; i++) {
    int x;
    fin >> x;
    // prelucrăm x
}

Exemplu: suma a n numere din fișier

suma.in:

5
3 7 2 9 4
#include <fstream>
using namespace std;
ifstream fin("suma.in");
ofstream fout("suma.out");

int main()
{
    int n;
    fin >> n;

    int suma = 0;

    for (int i = 1; i <= n; i++) {
        int x;
        fin >> x;
        suma = suma + x;
    }

    fout << suma;

    return 0;
}

suma.out:

25

Exemplu: maximul din fișier

maxim.in:

6
3 8 2 15 4 7
#include <fstream>
using namespace std;
ifstream fin("maxim.in");
ofstream fout("maxim.out");

int main()
{
    int n;
    fin >> n;

    int x;
    fin >> x;
    int maxim = x;

    for (int i = 2; i <= n; i++) {
        fin >> x;
        if (x > maxim) {
            maxim = x;
        }
    }

    fout << maxim;

    return 0;
}

maxim.out:

15

Transformarea unui program cu cin/cout în fișiere

Regula este simplă - înlocuim:

Tastatură/Ecran Fișier
#include <iostream> #include <fstream>
cin >> x fin >> x
cout << x fout << x

Și adăugăm ifstream fin(...) și ofstream fout(...) după using namespace std;.

Exemplu - înainte (tastatură):

#include <iostream>
using namespace std;

int main()
{
    int a, b;
    cin >> a >> b;
    cout << a + b;
    return 0;
}

După (fișiere):

#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int main()
{
    int a, b;
    fin >> a >> b;
    fout << a + b;
    return 0;
}

Restul codului rămâne identic. Doar sursa și destinația datelor se schimbă.


Folosirea ambelor: iostream și fstream

Poți folosi ambele simultan - de exemplu, citești din fișier dar afișezi și pe ecran (util la depanare):

#include <iostream>
#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int main()
{
    int a, b;
    fin >> a >> b;

    int suma = a + b;

    cout << "Suma este: " << suma << endl; // pe ecran (pentru tine)
    fout << suma; // în fișier (pentru evaluator)

    return 0;
}
Sfat pentru concursuri

La OJI și alte concursuri, evaluatorul citește doar fișierul de ieșire. Ce afișezi pe ecran cu cout nu contează.

Poți folosi cout pentru a verifica rapid ce face programul tău, dar nu uita să scrii rezultatul final în fișier cu fout.


Numele fișierelor

  • Numele fișierelor sunt date în enunțul problemei (ex: date.in, date.out).
  • Trebuie scrise exact cum apar în enunț (cu litere mici, cu extensia corectă).
  • Fișierul de intrare trebuie să existe deja (altfel programul nu poate citi).
  • Fișierul de ieșire este creat automat dacă nu există.

Greșeli frecvente

1. Fișierul de intrare nu există

Dacă fișierul date.in nu se află în același folder cu programul, citirea eșuează fără eroare vizibilă - variabilele rămân neinițializate.


2. Confuzia între ifstream și ofstream

  • ifstream = citire (input)
  • ofstream = scriere (output)

Dacă le inversezi, programul nu funcționează.


3. Uitarea lui #include <fstream>

Fără această bibliotecă, ifstream și ofstream nu sunt recunoscute.


4. Numele greșit al fișierului

ifstream fin("Date.in"); // GREȘIT dacă fișierul e "date.in"

Numele trebuie să fie exact - pe unele sisteme, literele mari și mici contează.


5. Declararea în main() în loc de global

La concursuri, cel mai simplu este să declari fin și fout global (după using namespace std;). Așa nu trebuie să le transmiți la funcții și sunt accesibile oriunde.


Ce să reții

  • La concursuri, citim din fișier (ifstream) și scriem în fișier (ofstream).
  • Declarăm fin și fout global, imediat după using namespace std;.
  • fin funcționează ca cin, fout funcționează ca cout.
  • Includem #include <fstream> în loc de (sau pe lângă) #include <iostream>.
  • Transformarea e mecanică: înlocuim cin cu fin și cout cu fout.
  • Fișierul de intrare trebuie să existe, cel de ieșire se creează automat.
  • La Olimpiadă, numele fișierelor sunt date în enunț - trebuie scrise exact.

Probleme

pbinfoCastel4

pbinfoBete1