Sunteți pe pagina 1din 64

C ap it o l ul V I :

F işiere

V I.1. Fiş iere tex t

V I .1 .1 N o Ń i u ne a d e f i ş i e r d e d a t e

NoŃiunea de fişier vă este cunoscută încă din primele ore de informatică.


Atunci aŃi învăŃat să realizaŃi un desen sau să scrieŃi un text, pe care l-aŃi salvat,
unde credeŃi, într-un fişier ! Fiecare program C++, "butonat" caracter cu caracter
de la tastatură, este de fapt tot un fişier, numit sursa programului. Tot la începutul
anului, aŃi aflat că un sistem de operare este un ansamblu de programe, adică o
colecŃie de fişiere, având rolul de a asigura exploatarea propriu-zisă a
calculatorului. În concluzie, putem spune că aŃi făcut cunoştinŃă până acum cu o
mare varietate de tipuri de fişiere.
AŃi învăŃat tot în primele capitole că fişierele sunt memorate pe suporturi
externe, numite discuri (hard-disk, floppy-disk, CD etc.), care le păstrează în
permanenŃă (adică spunem că aceste suporturi sunt nevolatile).
Orice fişier se caracterizează printr-un nume sub care este identificat de
către sistemul de operare, nume alcătuit din două părŃi: numele propriu-zis dat de
utilizator şi extensia care indică tipul fişierului, separate prin caracterul "punct".
De exemplu: ecuatii.pas, cerere.doc, imagine.bmp etc.
Numim fişier, o colecŃie de informaŃii care satisfac un anumit scop,
memorate pe un suport extern, şi accesată printr-un nume (numele fişierului).
În continuare vom vedea că şi programele C++ pot lucra cu fişiere. Până
acum am învăŃat că datele cu care lucrează un program (constante, variabile,
tablouri, mulŃimi, structuri etc.) pot fi citite de la tastatură. În timpul execuŃiei unui
program, aceste date sunt stocate în memoria internă RAM. Pentru că memoria
RAM este volatilă, ele se pierd odată cu încheierea execuŃiei programului, aşa
încât dacă vrem să mai executăm odată programul, trebuie să le introducem din
nou.
Acest fapt poate constitui o problemă serioasă, deoarece programele
concrete "din viaŃa reală" folosesc de obicei un volum mare de date. GândiŃi-vă
numai la o bibliotecă publică unde sunt câteva sute sau poate chiar mii de cărŃi.
Am învăŃat în capitolul "Înregistrări", unde am mai dat acest exemplu, că
informaŃiile despre cărŃile din bibliotecă (titlul, autorul etc.) pot fi memorate într-o
înregistrare şi pot fi citite de la tastatură. Dar ce face bibliotecara în condiŃiile în
care în momentul ieşirii din program toate datele se pierd ? Le introduce din nou

387
de fiecare dată când vrea să ruleze programul, spre exemplu fie şi numai pentru a
căuta o anumită carte ? Ar fi absurd ! Nu există decât o singură soluŃie: datele
respective să fie memorate într-un fişier, pe un disc, unde vor fi păstrate în
permanenŃă. Ajungem astfel la concluzia că şi datele cărŃilor din bibliotecă pot fi
păstrate într-un aşa-numit fişier de date.
Sistemul de operare "vede" fişierele de date la fel ca pe orice alte fişiere
(recunoscându-le, reamintim, prin numele lor), motiv pentru care şi asupra
acestora se pot aplica operaŃiile care se pot realiza cu orice fel de fişiere sub
controlul sistemului de operare: copiere, mutare, ştergere, redenumire etc.
În plus însă, un fişier de date poate fi scris sau citit de către utilizator.
Astfel, revenind la exemplul cu biblioteca:
 informaŃiile despre cărŃi vor fi scrise o singură dată într-un fişier de
date, unde vor fi păstrate în permanenŃă pe disc;
 de fiecare dată când este rulat, în loc să citească datele de la tastatură,
programul le va citi din respectivul fişier.
Categoric în acest moment aveŃi o nelămurire: cum poate fi scris un fişier
de date ? Răspunsul este foarte simplu: fie manual (prin intermediul unui editor de
texte, de exemplu poate fi folosit chiar editorul limbajului Pascal în care vă scrieŃi
sursele programelor), fie prin intermediul unui alt program.
Despre modul cum un program poate sa scrie într-un fişier de date sau
poate să citească dintr-un astfel de fişier, vom învăŃa în lecŃiile următoare.

V I .1 . 2 . C l a s i f i c a r e a f i ş i e r e l o r d e da t e

Din punctul de vedere al conŃinutului, fişierele de date în Pascal se împart


în trei categorii:
 fişiere cu tip: componentele sunt toate de acelaşi tip (predefinit, sau
definit de utilizator);
 fişiere text: datele sunt memorate ca o succesiune de caractere
dispuse pe unul sau mai multe rânduri;
 fişiere fără tip: informaŃiile sunt stocate sub forma unor blocuri de
octeŃi de dimensiune fixă.
Din punctul de vedere al accesului la componente, fişierele de date sunt de
două tipuri:
 cu acces secvenŃial: pentru a accesa o anumită componentă trebuie
parcurse toate componentele dinaintea acesteia;
 cu acces direct: orice componentă poate fi accesată imediat prin
intermediul numărului ei de ordine în fişier.

388
VI . 1 .3 . N o Ń i un e a d e f i ş i e r t e x t

Un fişier text conŃine una sau mai multe linii de caractere de lungime
variabilă. O astfel de linie se mai numeşte rând în fişier. Fiecare rând, mai puŃin
ultimul, se încheie printr-un "marcaj de sfârşit de linie" alcătuit din caracterele CR
("Carriadge Return ") şi LF ("Line Feed "). Sfârşitul fişierului este marcat prin
caracterul EOF ("End Of File ").
Caracterele dintr-un fişier text pot fi atât caractere tipăribile (litere mari şi
mici, cifre, caractere speciale), cât şi caractere netipăribile. Acestea din urmă se
mai numesc şi caractere albe (ENTER, LF, SPACE, BACKSPACE, TAB etc.).
Într-un fişier text, din cauză că rândurile de caractere au lungimi diferite,
nu putem identifica poziŃia unui anumit caracter faŃă de începutul fişierului. De
aceea, accesul într-un fişier text se face secvenŃial: pentru a ajunge la un caracter
oarecare din interiorul fişierului trebuie să "trecem" peste toate caracterele aflate
înaintea acelui caracter în fişier.
Pentru a putea prelucra datele dintr-un fişier text acesta trebuie deschis, iar
după încheierea prelucrării fişierul trebuie închis la loc.
Orice fişier text se caracterizează printr-o variabilă specială numită
indicator de fişier. Acest indicator "arată" în orice moment primul caracter din
fişier ce poate fi prelucrat.

V I .1 .4 . Cr e a r e a , de s c h i de r e a ş i î n c h i d e r e a
unui fi ş ie r t ex t

NoŃiunea de descriptor de fişier

Aşa cum am mai spus, orice fişier, inclusiv un fişier text, se caracterizează
printr-un nume sub care este identificat de către sistemul de operare (alcătuit din
două părŃi: numele propriu-zis dat de utilizator, şi extensia care indică tipul
fişierului, separate prin caracterul "punct ". De obicei, pentru fişierele text se
foloseşte extensia txt (de la "text") sau dat (de la "fişier de date"). De exemplu:
numere.txt, ecuatii.dat etc.
Pe de altă parte, un program C++ nu este capabil să recunoască numele
sub care este cunoscut un fişier de către sistemul de operare, motiv pentru care
avem nevoie de o variabilă care să identifice fişierul. O astfel de variabilă trebuie
declarată, la fel ca orice variabilă, în secŃiunea de declaraŃii a programului.
Variabilele care desemnează fişierele se numesc descriptori de fişier, şi aparŃin
unui tip de date predefinit, numit "tipul pointer către fişier". Astfel, dacă avem
două fişiere şi notăm cu f şi g descriptorii ataşaŃi lor, atunci declaraŃiile
descriptorilor ca variabile arată astfel:
389
Ex e mp l u : FILE *f,*g;
Pentru a vă face să înŃelegeŃi ce înseamnă tipul de date "pointer către tipul
fişier" şi ce semnificaŃie are caracterul "*" plasat în faŃa descriptorilor f şi g, ar
trebui să vă prezentăm toată teoria pointerilor în C++. Aceasta însă depăşeşte cu
mult cadrul materiei de clasa a IX-a, motiv pentru care singura soluŃie este, cel
puŃin deocamdată, să luaŃi lucrurile ca atare. În clasa a XI-a, când veŃi studia
capitolul "Pointeri", veŃi înŃelege în profunzime sensul declaraŃiilor de variabile de
genul celei de mai sus, dar până atunci va trebui să le folosiŃi pur şi simplu, fără să
vă mai bateŃi capul cu interpretarea lor.
Pentru a putea folosi efectiv un fişier text într-un program, trebuie făcută o
legătură între descriptorul de fişier (fişierul logic) şi numele sub care este
recunoscut de către sistemul de operare (fişierul fizic). Această legătură se numeşte
asignarea fişierului.

Asignarea, deschiderea şi închiderea unui fişier text


Pentru a putea fi prelucrat, un fişier trebuie deschis. În urma deschiderii,
indicatorul (pointerul) de fişier se poziŃionează la începutul fişierului, pe primul caracter.
Pentru deschiderea unui fişier text, apelăm funcŃia predefinită fopen, cu
prototipul în header-ul <stdio.h>, funcŃie care primeşte doi parametri.
Sintaxa: <descriptor>
>=fopen(<nume_fisier>,<atribut>);

─ primul parametru, <nume_fisier>, reprezintă numele fizic sub care este


identificat fişierul de către sistemul de operare (alcătuit din numele propriu-zis,
caracterul "punct" şi extensie); acesta se transmite funcŃiei ca un şir de caractere şi
eventual poate conŃine şi calea spre folder-ul ce conŃine fişierul (cu menŃiunea că
separatorul folosit între subfolder-ele din cale este "\\" în loc de "\");
─ al doilea parametru, <atribut>, este un caracter ce identifică scopul
pentru care deschidem fişierul, putând fi: "r" dacă dorim să deschidem fişierul
pentru citire, respectiv "w" dacă deschidem fişierul în vederea scrierii în el.
FuncŃia returnează identificatorul descriptorului pe care-l vom ataşa
fişerului în program.
După deschidere, fişierul va fi referit în continuare în tot programul numai
prin descriptorul său. Practic, odată cu apelul funcŃiei fopen s-a realizat o
legătură între numele sub care e recunoscut fişierul de către sistemul de operare
(fişierul fizic) şi descriptorul acestuia în program (fişierul logic).
Exemplu:
Presupunem că vrem să realizăm un program care foloseşte două fişiere text, aflate
pe partiŃia C în folder-ul ELEVI subfolder-ul CLASA_X, cu numele "fis1.txt" respectiv
"fis2.txt", şi că din primul fişier programul urmează să citească date iar în al doilea va
scrie date. Mai întâi declarăm ca variabile doi descriptori f şi g aferenŃi celor două fişiere:
FILE *f, *g;

390
Pentru a deschide fişierul "fis1.txt" cu atributul "citire", asignând totdată
acestuia descriptorul f, vom scrie instrucŃiunea:
f=fopen("C:\\ELEVI\\CLASA_X\\fis1.txt","r");
Dacă fişierul "fis1.txt" s-ar fi aflat în directorul curent, era suficient
f=fopen("fis1.txt","r");
Ca să deschidem fişierul "fis2.txt" cu atributul "scriere" şi să asignăm
acestuia descriptorul g este necesară instrucŃiunea:
g=fopen("C:\\ELEVI\\CLASA_X\\fis2.txt","w");

Închiderea unui fişier text se realizează cu ajutorul funcŃiei fclose, cu


prototipul tot în <stdio.h>, care primeşte ca parametru descriptorul fişierului şi
nu returnează nimic.

Sintaxa: fclose(<descriptor>);

Exemplu:
Pentru a închide fişierele cu descriptorii f şi g deschise în exemplul anterior, vom scrie:
fclose (f);
fclose (g);
Nu putem închide deodată ambele fişiere printr-o instrucŃiune de genul
{fclose(f,g);}.

Testarea sfârşitului de rând şi de fişier


Aşa cum am spus, un fişier text este alcătuit din mai multe rânduri de
caractere, existând nişte "marcaje" care identifică sfârşitul fiecărui rând, respectiv
sfârşitul fişierului (referit prin cuvântul "eof", de la "end of file"). Pentru testarea
sfârşitului de fişier, se poate apela funcŃia predefinită feof, cu prototipul în
<stdio.h>, care primeşte ca parametru descriptorul fişierului şi returnează:
─ zero, dacă pointerul de fişier nu a ajuns la sfârşitul acestuia (cu sens de "fals");
─ o valoare diferită de zero, dacă s-a atins sfârşitul de fişier (cu sens de "adevărat").
Fireşte că într-un program putem să testăm valoarea returnată de către
feof şi în funcŃie de aceasta să stabilim acŃiunea programului în continuare.
Sintaxa: feof(<descriptor>);

Ex e mp l u :
if (feof(f)) // cu sensul “dacă feof(f) este diferit de zero”
.......

AŃi înŃeles ? Probleme cu răspuns scurt

► 1. DefiniŃi noŃiunea de fişier pe caz general, apoi precizaŃi ce se înŃelege prin


fişier de date.
391
► 2. De ce tipuri pot fi fişierele din punctul de vedere al modului de acces la
informaŃiile conŃinute în el ?
► 3. Ce este un fişier text ?

► 4. Din cine este alcătuit marcajul de sfârşit de rând într-un fişier text ?

► 5. Ce rol are descriptorul (pointerul) de fişier ?

► 6. Ce se înŃelege prin asignarea unui fişier ?

► 7. În câte moduri poate fi deschis un fişier ?

► 8. Care este deosebirea între funcŃiile eoln şi seekeoln ?

► 9. Pentru fiecare dintre funcŃiile predefinite enumerate în coloana A), alegeŃi


din coloana B) acŃiunea sa:
Coloana A): Coloana B):
A.1. fopen B.1. Deschide un fişier text pentru scriere
A.2. fscanf B.2. Închide un fişier text deschis anterior
A.3. fclose B.3. Deschide un fişier text pentru adăugare la sfârşit
A.4. fprintf B.4. Stabileşte legătura între numele unui fişier text şi descriptorul său
A.5. append B.5. Deschide un fişier text pentru citire

► 10. Pentru fiecare dintre afirmaŃiile de mai jos, răspundeŃi cu "adevărat" sau "fals".
a) Un rând al unui fişier text poate conŃine cel mult 255 de caractere.
b) Un fişier text poate conŃine caractere tipăribile şi caractere albe.
c) Într-un fişier text datele sunt memorate sub formă de blocuri de octeŃi de lungime variabilă.
d) Următoarea declaraŃie de variabilă defineşte corect descriptorul f aferent unui fişier text:
FILE *f;
e) Următoarea instrucŃiune asignează corect descriptorul f fişierului nr.dat.
f=fopen("nr.dat","r");

VI .1.4 . Citi re a dint r - un f iş ie r te x t .


Scrierea într - un fişi er text

Dintr-un fişier text putem citi valori ale unor variabile de tip caracter, şir
de caractere şi numeric. Deorece şirurile de caractere vor face obiectul unui capitol
din clasa a X-a, deocamdată ne ocupăm doar de citirea variabilelor de tip caracter
şi a celor numerice.

A) Citirea variabilelor de tip caracter


Într-un parametru de tip char se poate citi caracterul la care se află
indicatorul de fişier. După citirea unui caracter, indicatorul avansează la caracterul
următor. Citirea unui caracter dintr-un fişier se realizează cu ajutorul funcŃiei
fgetc, care primeşte ca parametru descriptorul de fişier şi returnează caracterul
citit. Prototipul funcŃiei se găseşte în header-ul "stdio.h".
392
<caract>=fgetc(<descriptor>);

Exemplu: &$?
#*
Fie fişierul cu descriptorul f având următorul conŃinut:
# include <stdio.h> InstrucŃiunea
# include <iostream.h> {f=fopen("C:\\car.txt","r");} asignează
char c; descriptorul f fişierului "car.txt" aflat în
FILE *f; rădăcina partiŃiei C, şi deschide acest fişier cu
void main ()
atributul "r", adică pentru citire. Ciclul while
{ realizează citirea fişierului caracter cu caracter.
f=fopen("C:\\car.txt","r"); IniŃial, imediat după deschiderea fieşierului,
while (!feof(f)) pointerul (indicatorul) de fişier se poziŃionează
{ automat la începutul fişierului, înaintea primului
c=fgetc(f); caracter. Cât timp acest pointer nu a juns la sfârşitul
putchar(c); fişierului, adică atâta timp cât "not feof(f) este
}
}
adevărat" {while (!feof(f))}:
− citeşte un caracter din fişierul f în variabila c
{c=fgetc(f);};
− afişează caracterul citit {putchar(c);};
Dacă fişierul este cel din figură, în urma execuŃiei
programului se va reproduce "ad-literam" pe ecran
conŃinutul său. Astfel, se va afişa caracterele "&$?"
pe un rând, apoi caracterele "#*". ObservaŃi că
compilatorul "vede" sfârşitul unui rând şi reuşeşte
să treacă automat la rândul al doilea (ca şi cum ar
citi marcajul de sfârşit de rând ca pe un caracter).

B) Scrierea unui caracter într-un fişier


Un caracter poate fi scris într-un fişier text cu ajutorul funcŃiei fputc, cu
prototipul tot în "stdio.h". Scrierea va avea loc începând cu poziŃia curentă a
pointerului de fişier. La sfârşitul scrierii, pointerul se va poziŃiona imediat după
caracterul tocmai scris.
Ex e mp l u : fputc(<descriptor>,<caract>);

char c;
FILE *f;
.............
fputc(f,’A’);
c=’B’;
fputc(f,c);

În fişierul cu descriptorul f va fi scris mai întâi caracterul 'A', transmis direct ca


parametru, apoi caracterul 'B', transmis ca parametru prin intermediul variabilei c. Prin
urmare, fişierul va avea conŃinutul din figură.
393
AB

C) Citirea variabilelor de tip numeric


O secvenŃă de caractere dintr-un fişier text cuprinsă între două caractere
albe, poate fi privită ca un număr, dacă respectă formatul specific de număr
(conŃine numai cifre, punctul zecimal şi caracterele '+', '-', 'e', 'E'). Pentru
ca un astfel de număr să poată fi citit într-o variabilă de un tip numeric, mai este
necesar să existe o compatibilitate între tipul de date în care se încadrează
numărul şi tipul de date al variabilei în care se citeşte.
Pentru citirea variabilelor de tip numeric dintr-un fişier există o funcŃie
numită fscanf, foarte asemănătoare ca şi concepŃie şi mod de lucru cu funcŃia
scanf (utilizată pentru citirea de la tastatură). Practic, singura deosebire care apare
la fscanf faŃă de scanf constă în faptul că fscanf are un parametru în plus:
primul parametru este descriptorul fişierului din care facem citirea; mai departe,
sintaxa este identică.
fscanf (<descriptor>,<param_control>,&<var1>,&<var2>,…);

─ <descriptor> → descriptorul fişierului din care facem citirea;


─ <param_control> → parametru de control ce conŃine succesiunea de
specificatori de format aferenŃi variabilelor care se citesc, între aceşti specificatori
putându-se folosi separatori (spaŃiu, virgulă, etc);
─ <var1>,<var2>,… → Identificatorii variabilelor care se citesc.
La fel ca şi la scanf, identificatorii variabilelor ce se citesc trebuie
precedaŃi de semnul "&", adică funcŃiei se transmit de fapt adresele lor, excepŃie
făcând variabilele de tip şir de caractere (aşa cum am spus şi atunci când am
prezentat funcŃia scanf, motivul pentru care variabilele de tip şir nu trebuie
precedaŃi de operatorul "&" Ńine de teoria pointerilor şi va putea fi înŃeles abia
atunci când veŃi parcurge capitolul despre pointeri; în esenŃă este vorba despre
faptul că numele unei variabile de tip vector de caractere reprezintă chiar adresa
primului său element).
Aşa cum am spus, parametrul de control conŃine specificatorii de format
aferenŃi variabilelor ce se citesc, iar între specificatorii respectivi pot apărea
separatori (spaŃiu, virgulă, etc.). Aceşti separatori trebuie să reproducă identic
separatorii existenŃi în fişier între valorile care se citesc.

Ex e mp l u :
Fie fişierul text cu descriptorul f, având conŃinutul ca în 315∪-34.65
desenul alăturat (prin '∪' am simbolizat caracterul "spaŃiu ").

394
Presupunem că dorim să citim cele două numere din fişier, 315 şi -34.65, în
două variabile x şi y. Fireşte că cel mai indicat ar fi ca tipurile celor două variabile, pe care
le dăm la declarare, să coincidă cu tipurile valorilor pe care urmează să le găzduiască. Mai
concret, variabila x ar trebui să fie de tipul int, iar y de tipul float.
int x; float y;
InstrucŃiunea de citire este:
fscanf (f,"%d %f", &x, &y);
În urma execuŃiei instrucŃiunii vom avea x=315 şi y=-34,65.
În parametrul de control "%d %f", primul specificator de format "%d"
corespunde variabilei x de tipul int, iar al doilea specificator "%f" se asociază variabilei
y de tipul float. SpaŃiul prezent între cei doi specificatori în parametrul de control,
identifică tocmai spŃiul aflat între cele două valori în fişier.
Evident că tipurile variabilelor x şi y în care se citesc numerele din fişier nu
trebuie neapărat să fie identice cu tipurile valorilor citite, dar este necesar să fie
compatibile. Astfel, putem avea şi alte variante în privinŃa declarării celor două variabile,
dar trebuie să fim atenŃi să modificăm corespunzător şi specificatorii de format din
parametrii de control.
float x,y;
fscanf (f,"%f %f", &x, &y); // rezultă x←
← 315.0 şi y←
←-34.65
sau
int x,y;
fscanf (f,"%d %d", &x, &y); // rezultă x←
← 315 şi y←
← -34

Dacă de exemplu, cele două valori s-ar fi găsit în fişier una sub
alta ca în figura alăturată, atunci în parametrul de control al funcŃiei 315
-34.65
fscanf, între cei doi specificatori de format trebuia să punem marcatorul
de sfârşit de rând "\n", pentru a "comanda" saltul la rând nou în fişier
după citirea primului număr.
fscanf (f,"%d\n%f", &x, &y);

D) Scrierea variabilelor de tip numeric într-un fişier

Se realizează cu ajutorul funcŃiei fprintf, foarte asemănătoare cu funcŃia


fprintf care realizează tipărirea pe ecran, singura deosebire fiind aceeaşi ca în
cazul perechii (scanf,fscanf): primul parametru este descriptorul de fişier.

fprintf (<descriptor>,<param_control>,<var1>,<var2>,…);

Separatorii care dorim să apară între valorile descrise în fişier, vor fi


reproduşi ca atare între specificatorii de format în parametrul de control.
Ex e mp l u :
int x=-3, y=2, z=5;
float a=-2.1, b=0.66;
..............
fprintf (f,"%d %d %d\n%f %f",x,y,z,a,b);
395
Asocierea între variabile şi specificatorii de fomat este următoarea: %d← ←x, %d←←y,
←z, %f←
%d← ←a, %f← ←b. Separatorii ce apar între specificatori în parametrul de control arată că:
− se scriu valorile lui x, y şi z în această ordine, separate printr-un spaŃiu;
− se face un salt la rând nou, graŃie secvenŃei Escape "\n";
− se scriu valorile lui a şi b pe al doilea rând, separate tot printr-un spaŃiu.
În consecinŃă fişierul va arăta astfel:
-3∪2∪5
2.1∪0.66

PoziŃionarea într-un fişier. FuncŃiile ftell şi fseek


FuncŃia ftell returnează poziŃia la care se află indicatorul de fişier faŃă
de începutul fişierului, măsurată în număr de octeŃi (caractere). FuncŃia primeşte ca
parametru descriptorul de fişier.
<poz>= ftell (<descriptor>);

FuncŃia fseek realizează poziŃionarea indicatorului într-un anumit loc în


cadrul unui fişier identificat prin descriptorul său.
fseek (<descriptor>,<nr>,<org>)

Practic, funcŃia fseek(<descriptor>,<nr>,<org>) realizează


mutarea indicatorului în fişierul cu descriptorul <descriptor>, la un număr de
<nr> octeŃi, raportat la originea <org>. Originea arată punctul faŃă de care este
"măsurată" deplasarea: 0→ faŃă de începutul fişierului, 1→ faŃă de poziŃia curentă,
2→ faŃă de sfârşitul fişierului.

Exemplu:
Să vedem ce valori va afişa programul următor, dacă fişierul f arată ca mai jos.

1 11 -4 12 8 -9 5

(prin " " am notat caracterul "spaŃiu ")


#include <stdio.h>
void main ()
{
FILE *f; int a,b,c,x,p;
f=fopen("valori.txt","r");
fscanf(f,"%d %d %d",&a,&b,&c);
p=ftell(f);
fseek(f,7,1);
fscanf(f,"%d",&x);
printf("\n%d %d %d",p,!feof(f),x);
}
396
Fişierul este deschis cu atributul "r", adică pentru citire, şi i se asociază
descriptorul f. Prima instrucŃiune de citire fscanf(f,"%d %d %d",&a,&b,&c) va citi
corect în variabilele întregi a, b şi c primele trei numere din fişier. Astfel, vom avea a=1,
b=11, c=-4.
După citirea de mai sus, indicatorul va ajunge la şapte octeŃi faŃă de începutul
fişierului. De ce ? Prin citire "a sărit" peste un caracter al valorii 1, un spaŃiu, două
caractere ale valorii 11, încă un spaŃiu, două caractere ale valorii -4. Valoarea returnată de
către funcŃia ftell(f) este atribuită variabilei p, deci p=7.
În urma apelului fseek(f,7,1) se realizează o mutare a indicatorului în fişierul
f, cu şapte octeŃi, faŃă de poziŃia curentă. Deoarece indicatorul a ajuns la caracterul ‘4‘ citit
ultimul, el va ajunge să se poziŃioneze pe cifra 9. Cele şapte poziŃii peste care "va sări"
sunt: caracterul "spaŃiu" de după -4, cele două caractere ale numărului 12, spaŃiul de după
numărul 12, caracterul ce reprezintă cifra 8, spaŃiul de după acesta, şi semnul "-" care
urmează. Următoarea instrucŃiune din program, fscanf(f,"%d",&x), va reuşi să citească
în variabila x doar cifra 9, deoarece semnul "-" a fost "sărit" !
În sfârşit, funcŃia feof(f), apelată ca parametru la printf, testează sfârşitul de
fişier. Ea returnează 0, dacă nu s-a ajuns la sfârşitul fişierului, şi o valoare nenulă, dacă
indicatorul se află la sfârşit de fişier. În cazul nostru, după citirea lui x=9 din fişier,
indicatorul nu a ajuns la sfârşitul fişierului, feof(f) returnează 0, iar !feof(f) va fi 1
("not" 0 este 1).
Aşadar, valorile afişate de către funcŃia printf sunt, în ordine, 7, 1, 9.

V I .1 . 5 . P r e l u c r a r e a f i ş i e r e l o r t e x t
c u ins tr ument e c ar e fol ose s c obiec t e

În C++, prelucrarea fişierelor text se poate face şi cu ajutorul unor


instrunmente mai "evoluate", care utilizează aşa-numita "programare pe obiecte".
Întrucât, la fel ca pointerii, şi capitolul "Obiecte" se studiază deabia în clasa
a XI-a, ne este aproape imposibil să explicăm pe înŃelesul vostru mecanismul de
funcŃionare a instrucŃiunilor care tratează fişierele din punct de vedere obiectual.
De aceea, din nou suntem nevoiŃi, aşa cum am făcut când am prezentat declararea
descriptorilor de fişier ca variabile, să vă rugăm să luaŃi ca atare anumite simboluri
pe care le veŃi întâlni, fără a încerca să înŃelegeŃi semnificaŃia lor. Pentru a vă face,
cât de cât, o imagine asupra a ceea ce înseamnă programarea pe obiecte, o să
încercăm o definiŃie rudimentară a noŃiunii de "obiect", dar, aşa cum am spus, fără
a intra în amănunte.
Extensia "++" a limbajului C++, ne permite să definim tipuri abstracte de
date, care să cuprindă, pe lângă date de diverse tipuri, şi funcŃii pentru prelucrarea
respectivelor date. Un astfel de tip se numeşte clasă. Datele şi funcŃiile care
alcătuiesc o clasă poartă denumirea de membri ai clasei. FuncŃiile membre ale
unei clase se mai numesc şi metode. Datele membre ale unei clase sunt de obicei
variabile, simple sau structurate (vectori, matrici, şiruri, etc).
397
În momentul de faŃă nu putem să vă dăm nici cel puŃin un exemplu de
"clasă", câtă vreme nu aŃi studiat nici măcar funcŃiile în C++. La începutul clasei a
IX-a aŃi învăŃat doar că instrucŃiunile unui program C++ pot fi grupate în mai
multe entităŃi numite funcŃii, şi că, pe lângă funcŃiile pe care le definim noi, în
cadrul unui program putem folosi nişte aşa-numite "funcŃii predefinite ale
limbajului". Acestea au fost scrise de către autorii limbajului, fac parte intrisecă
din limbaj, si le putem utiliza oricând în programe, în care scop este suficient să le
apelăm. Dealtfel, pe parcursul clasei a IX-a aŃi întâlnit numeroase programe care
apelau funcŃii predefinite precum sqrt, floor, abs, etc. Ei bine, cam la fel se
pune problema şi în ceea ce priveşte clasele şi obiectele. Atunci când scriem un
program putem să ne definim propriile clase, dar, pe de altă parte, limbajul C++
este prevăzut cu nişte clase predefinite, care nu mai trebuie proiectate, fiind posibil
să le folosim direct, la fel cum folosim funcŃiile predefinite. O astfel de clasă
predefinită este ceea ce numim "clasa fişier", cu numele fstream, concepută
pentru utilizarea fişierelor text. Mai multe lucruri despre clase nu vă spunem,
pentru că oricum nu aŃi mai înŃelege nimic mai departe !
DefiniŃia în sine a acestei clase, împreună cu toate funcŃiile şi metodele
predefinite pentru prelucrarea fişierelor text, se găsesc în header-ul fstream.h.
De aceea, în orice program în care dorim să folosim un fişier text tratat obiectual,
pentru a putea prelucra acel fişier cu ajutorul funcŃiilor predefinite dedicate acestui
scop, este necesar ca la începutul programului să includeam header-ul
fstream.h.
#include <fstream.h>

În lecŃiile anterioare v-am prezentat funcŃiile predefinite fopen, fclose,


feof, fscanf şi fprintf, cu ajutorul cărora se poatre prelucra un fişier în
versiunea "C standard", fără a folosi obiectele specifice extensiei "++". A venit
momentul să vă spunem care sunt instrumentele necesare pentru prelucrarea
obiectuală a unui fişier, adică să descoperiŃi instrumentele echivalente funcŃiilor de
mai sus, pentru deschiderea şi închiderea unui fişier, respectiv pentru citire, scriere
şi testarea sfârşitului de fişier.

Asignarea, deschiderea şi închiderea unui fişier text

Sintaxa: fstream <descr>(<nume>,<tip>)

 fstream → este numele "clasei fişier", cu ajutorul căreia se tratează fişierele


ca şi obiecte, aflată, aşa cum spuneam, în header-ul fstream.h (faptul că
header-ul şi clasa se numesc la fel, e o simplă coincidenŃă);
 <descr> → reprezintă descriptorul ataşat fişierului (care se notează de obicei
cu f, g, h, etc.);
 <nume> → acest parametru desemnează numele fizic sub care este recunoscut
398
fişierul de către sistemul de operare (alcătuit din numele propriuzis, caracterul
"punct" şi extensia; la fel ca şi în cazul deschiderii cu fopen, acesta poate să
conŃină şi calea de acces la fişier, alcătuită dintr-un lanŃ de folder-e şi
subfolder-e, separate între ele prin "\\"; în absenŃa unei astfel de căi, se
subînŃelege faptul că fişierul în cauză se află în folder-ul curent;
 <tip> ← este un parametru care identifică tipul operaŃiei ce urmează a fi
executată asupra fişierului, şi poate avea două forme, "ios::in" şi
"ios::out", cu următoarele semnificaŃii:
– dacă vrem să citim din fişier parametrul este ios::in ("in"
provine de la "input", adică "intrare");
– dacă vrem să scriem în fişier parametrul este ios::out ("out"
provine de la "output", adică "ieşire")
Rolul simbolulului"::" este imposibil de explicat la nivelul clasei a IX-a,
fiind vorba despre referirea unui obiect ce aparŃine unei clase, aspect care,
precum spunem mai înainte, va fi studiat deabia în clasa a XI-a.
Prin această instrucŃiune s-a realizat automat atât asignarea descriptorului
pentru fişierul respectiv, cât şi deschiderea lui, în vederea citirii din el sau scrierii
în el.

Ex e mp l u :
♥ fstream f("numere.txt",ios::in);
− deschide pentru citire fişierul numere.txt, cu descriptorul f, aflat în folder-ul curent;
♥ fstream g("numere2.txt,ios::out);
− deschide pentru scriere fişierul numere2.txt, cu descriptorul g, aflat în folder-ul curent;
♥ fstream f("D:\\Fisiere\\numere.txt",ios::in);
− deschide pentru citire fişierul numere.txt, cu descriptorul f, aflat pe partiŃia
"D" în folder-ul "Fisiere";
♥ fstream g("D:\\Fisiere\\numere2.txt",ios::out);
− deschide pentru scriere fişierul numere2.txt, cu descriptorul g, aflat pe
partiŃia "D" în folder-ul "Fisiere";

După ce am terminat de prelucrat un fişier text, el trebuie închis.


InstrucŃiunea de închidere este următoarea:
Sintaxa: <descr>.close()

 <descr> → reprezintă descriptorul ataşat fişierului;


 close() → este funcŃia predefinită, fără parametrii, care realizează efectiv
închiderea;

Ex e mp l u :
f.close();
Închide fişierul cu descriptorul f;
399
După cum aŃi observat, închiderea unui fişier se realizează la fel,
indiferent dacă a fost deschis pentru citire sau pentru scriere. PrezenŃa caracterului
"punct" între descriptor şi identificatorul close iarăşi nu poate fi explicată
momentan. Ea Ńine tot de teoria obiectelor, mai precis de modul în care este
referită funcŃia close ca membră a "clasei fişier" fstream.

Citirea dintr-un fişier text

Citirea dintr-un fişier text tratat obiectual este similară cu citirea de la


tastatură, cu deosebirea că cuvântul cheie cin se înlocuieşte cu descriptorul
fişierului.
Sintaxa: <descr> >> var1 >> var2 >> varn

La un apel al instrucŃiunii, putem citi deodată mai multe variabile, iar


pentru aceasta este suficient să enumerăm identificatorii var1, var2,...,varn ai
acestora, punând în faŃa fiecăruia simbolul ">>".
Din nou ne este imposibil să vă facem să înŃelegeŃi în profunzime de unde
şi până unde această înlocuire a lui cout cu descriptorul fişierului. Pentru a vă
face o imagine vagă asupra mecanismului în cauză, trebuie să vă spunem că, din
punct de vedere al programării pe obiecte, tastatura este privită tot ca un fişier, dar
unul mai special, numit fişierul standard de intrare, de unde se preiau date de
intrare, iar cuvântul cheie cin nu este altceva decât descriptorul acestui fişier
special. Cu alte cuvinte, în loc să citim din fişierul standard de intrare cu
descriptorul cin, vrem să citim dintr-un fişier text "obişnuit", identificat printr-un
descriptor, şi de aceea înlocuim cuvântul cin cu identificatorul descriptorului de
fişier.
În timpul citirii, compilatorul sare automat peste toate caracterele albe,
adică peste tot ceea ce înseamnă spaŃii, tab-uri şi marcaje de sfârşit de rând. Acesta
este un mare avantaj, spre deosebire de citirea cu fscanf, unde trebuia să avem
evidenŃa tuturor caracterelor albe, şi să le citim ca atare. De asemenea, la citirea cu
fscanf trebuia să ştim exact pentru fiecare valoare citită câte caractere şi eventual
câte zecimale are, pentru a include aceste informaŃii în specificatorul de format,
lucru care aici nu e cazul.
Exemplu:
Fie fişierul date.in cu descriptorul f, având conŃinutul din imaginea de mai jos,
precum şi secvenŃa de program următoare:
long a,b,c;
float x; 7 -11 3
fstream f("C:\\Fisiere\\date.in",ios::out); 9.25
f >> a >> b >> c >> x;
f.close();

400
Printr-o singură instrucŃiune, trebuie citite din fişier patru variabile, şi anume a, b,
c şi x. Ca să reuşească citirea, în fişier trebuie să existe patru valori, ale căror tipuri trebuie
să fie compatibile cu tipul variabilelor în care vrem să le citim. Dacă ne uităm cu atenŃie,
observăm potrivirea: în fişier avem trei valori întregi şi una reală, în această ordine, iar
dintre variabile, primele trei sunt de tipul int şi a patra de tipul float. Prin urmare, în
urma citirii, variabilelele vor primi valorile a=7, b=-11, c=3 şi x=9.25. Faptul că primele
trei valori sunt pe un rând iar a patra valoare pe al doilea rând nu afectează citirea, întrucât
marcajul de sfârşit de rând va fi "sărit" automat, la fel ca şi spaŃiile dintre numere.

Scrierea într-un fişier text

Scrierea într-un fişier text tratat obiectual este foarte asemănătoare cu


afişarea pe ecran, singura deosebire constând în faptul că cuvântul cheie cout se
înlocuieşte cu descriptorul fişierului. Este vorba aici despre o similitudine de genul
celei întâlnite în cazul citirii: atunci când afişăm ceva pe monitor, ecranul acestuia
este considerat fişierul standard de ieşire cu descriptorul cout.

Sintaxa: <descr> << val1 << val2 << ... << valn

La un apel al instrucŃiunii putem scrie deodată mai multe valori, iar


simbolurile val1,val2,...,valn identifică aceste valori. Ele pot fi, la fel ca şi
în cazul scrierii pe ecran, constante numerice, caractere, texte (care de fapt sunt
constante şir de caractere), valori ale unor variabile, şi valori ale unor expresii.
Ex e mp l u :
long a=2,b=5;
float x=3.14;
fstream f("date.out",ios::out);
f << a << " $$ " << b << "\n" << x << " " << (a+b)/2.;
f.close();
Am deschis fişierul date.out, cu descriptorul f, pentru a scrie în el (fapt
consfinŃit de parametrul "ios::out". Avem variabilele a şi b de tip întreg cu valorile 2
respectiv 5, şi variabila x de tipul float cu valoarea 3.14. InstrucŃiunea de scriere în
fişierul f este
f << a << " $$ " << b << "\n" << x << " " << (a+b)/2.;
InstrucŃiunea va începe să scrie pe primul rând al fişierului următoarele elemente:
− valoarea variabilei a, adică 2;
− şirul de caractere " $$ ";
− valoarea variabilei b, adică 5;
− marcajul de salt la rând nou "\n";
Urmare a comenzii de scriere a acestui caracter netipăribil, se va trece la al doilea
rând în fişier, unde se vor tipări una după alta;
− valoarea variabile x, adică 3.14;
− caracterul "spaŃiu";
401
− valoarea expresiei "(a+b)/2.", adică 3.5 (calculată ca împărŃire reală, graŃie
operatorului "punct" ataşată constantei întregi 2).
În concluzie, fişierul va arăta astfel după execuŃia instrucŃiunii:

2 $ 5
3.14 3.5

Testarea sfârşitului de fişier

Se realizează cu ajutorul funcŃiei eof(), fără parametrii, a cărei sintaxă


este foarte asemănătoare cu cea a funcŃiei close().

Sintaxa: <descr>.eof()

FuncŃia returnează 1 dacă s-a atins sfârşitul de fişier, respectiv 0 în caz contrar.

Exemplu:
Presupunem că avem un fişier cu descriptorul f, în care se găseşte un şir de numere
separate prin spaŃii, şi vrem să citim acest şir şi să-l afişăm pe ecran. Pentru aceasta, vom citi
numerele din fişier pe rând, în aceeaşi variabilă x, într-un ciclu care se va executa atâte timp
cât nu s-a atins sfârşitul de fişier, adică atâta timp cât funcŃia f.eof() nu returnează 1. La
fiecare pas, citim un număr din fişier în variabila x şi îl afişăm pe ecran.
while (!f.eof()) do
{
f >> x;
cout << x<
}

AplicaŃie R.VI.1. Şir de numere citite dintr-un fişier


Se citeşte un şir de numere întregi din fişierul "numere.txt". 5
Fişierul conŃine: pe primul rând numărul n de elemente ale şirului, apoi, 2
pe fiecare din următoarele n rânduri, câte un element. Să se afişeze suma -3
elementelor pozitive ale şirului. Exemplu: dacă fişierul este cel din 8
0
figură, atunci programul va tipări valoarea 15. -7

Rezolvare
:
 Asignăm fişierului dat descriptorul f şi îl deschidem pentru citire, cu atributul
"r". Presupunând că fişierul a fost creat în directorul curent, instrucŃiunea de asignare şi
deschidere este {f=fopen("numere.txt","r");}. Citim valoarea lui n de pe primul
402
rând din fişier {fscanf(f,"%d\n",&n);}. IniŃializăm cu 0 suma S a elementelor
pozitive din şir.

 Cele n elemente ale şirului vor fi citite succesiv din fişier în aceeaşi variabilă
x. Folosim un ciclu for, în care contorul i va număra elementele citite. Astfel, valorile lui
i vor fi pe rând 1,2,...,n, indicând la al câtâlea element al şirului am ajuns cu citirea
(pentru i=1 citim primul element, apoi pentru i=2 al doilea element, etc). La fiecare pas:
− citim în variabila x un element al şirului, aflat pe un rând în fişier
{fscanf(f,"%d/n ",&x);};
− testăm dacă elementul tocmai citit în x este pozitiv, iar în caz afirmativ îl
adăugăm la S {if (x>0) S+=x;}.
Programul se încheie cu închiderea fişierului şi afişarea lui S.
#include <iostream.h>
#include <stdio.h>
FILE *f;
int i,x,n,S;
void main ()
{
// asignare si deschidere fisier
f=fopen("numere.txt","r");
fscanf(f,"%d\n",&n); // citeste numarul de elemente de pe primul rand din fisier
S=0;
for (i=1; i<=n; i++) // citeste pe rand cele n elemente, din fisier in variabila x
{
fscanf(f,"%d/n",&x);
cout << x << " ";
// pentru fiecare x, daca este pozitiv, atunci il adauga la suma S a elementelor pozitive
if (x>0)
S+=x;
}
cout << "\nSuma elementelor pozitive este " << S;
}

ÎncercaŃi singuri !
►1. (Bacalaureat iulie 2009, varianta 1)
Fişierul text BAC.TXT conŃine, pe o singură linie, cel mult 1000 de
numere naturale nenule cu cel mult 4 cifre fiecare, numerele fiind separate prin
câte un spaŃiu. ScrieŃi un program care citeşte de la tastatură un număr natural
nenul n (n<=999) şi numerele din fişierul BAC.TXT şi care afişează pe ecran,
separate prin câte un spaŃiu, toate numerele din fişier care sunt divizibile cu n.
Dacă fişierul nu conŃine niciun astfel de număr, atunci se va afişa pe ecran mesajul
NU EXISTA.
Exemplu: dacă fişierul bac.txt conŃine numerele:
3 100 40 70 25 5 80 6 3798
atunci pentru n=10 pe ecran se va afişa:
100 40 70 80
403
►2. (Bacalaureat iulie 2001, varianta 1)
ScrieŃi un program Pascal care citeşte din fişierul text BAC.TXT 4000 de
numere naturale de cel mult trei cifre fiecare, apoi afişează pe ecran câte numere
pare şi câte numere impare există în fişier. Numerele sunt scrise pe prima linie a
fişierului, cu câte un spaŃiu între ele.
De exemplu, pentru fişierul BAC.TXT cu următorul conŃinut:
3 4 98 5 7 2 ... 2, unde 2 apare de 3995 ori, se vor afişa pe ecran
numerele 3997 şi 3.
►3. (Bacalaureat iulie 2009, varianta 42)
Fişierul text NUMERE.TXT conŃine pe prima linie un număr natural n
(0<n<100000) iar pe doua linie, separate prin câte un spaŃiu, n numere naturale
formate din cel mult două cifre.
a) ScrieŃi un program care determină în mod eficient, din punct de vedere
al timpului de executare, dacă numerele situate pe a doua linie a fişierului sunt în
ordine strict crescătoare. În caz afirmativ, programul va afişa pe ecran mesajul DA,
altfel va afişa mesajul NU.
Exemplu: dacă fişierul NUMERE.TXT are următorul conŃinut:
7
3 5 2 1 5 23 1
atunci pe ecran se va afişa: NU
b) DescrieŃi succint, în limbaj natural, metoda de rezolvare folosită,
explicând în ce constă eficienŃa ei (3 – 4 rânduri).

AplicaŃie R.VI.2. Intervale


(Bacalaureat iulie 2009, varianta 23)
Fişierul BAC.TXT conŃine pe prima linie un număr natural nenul n
(1 ≤ n ≤ 1 0 0 0 ), iar pe fiecare din următoarele n linii câte două numere întregi a şi b
(1 ≤ a ≤ b ≤ 3 2 0 0 0 ), fiecare pereche reprezentând un interval închis de forma [a,b]
pe axa numerelor. ScrieŃi un program care citeşte numerele din fişier, apoi
determină un interval dintre cele citite care conŃine cel mai mare număr de valori
întregi dintre toate intervalele formate. Programul va afişa pe un rând al ecranului,
separate printr-un spaŃiu, capetele intervalului astfel determinat. În cazul în care
există mai multe intervale care îndeplinesc această proprietate, se va tipări acela a
cărei extremitate dreaptă este minimă în raport cu celelalte.
Exemplu: Dacă fişierul BAC.TXT are conŃinutul din figură, 4
pe ecran se vor afişa valorile 6 şi 13; numărul maxim de valori 17 24
întregi conŃinute de intervalele din fişier este 8, există două -2 3
intervale care cuprind în ele 8 valori întregi, respectiv [17,24] şi 9 15
[6,13], iar dintre acestea, intervalul [8,15] are capătul din 6 13
dreapta mai mic.

404
Rezolvare
:
 Definim o variabilă nr, în care, la citirea fiecărui interval de forma [a,b],
memorăm numărul valorilor întregi din intervalul respectiv, care este b-a+1 (de exemplu,
intervalul [17,24] conŃine 24-17+1=8 valori întregi). Mai avem nevoie de încă două
variabile:
− nrmax = numărul maxim de valori intregi dintre toate intervalele [a,b], pe
care îl iniŃializăm cu -MAXINT (cel mai mic număr întreg posibil);
− cmin = cel mai mic dintre capetele din dreapta ale intervalelor care conŃin exact
nrmax valori intregi, pe care îl iniŃializăm cu MAXINT (cel mai mare întreg posibil).
Asignăm descriptorul f fişierului BAC.TXT şi îl deschidem pentru citire (cu
parametrul ios::in la funcŃia fstream). Apoi, de pe primul rând al fişierului, citim
valoarea lui n, reprezentând numărul de intervale {f >> n;}.
 Ştiind că avem de citit din fişier n rânduri, proiectăm un ciclu for, în care
contorul i nu are alt rol decât acela de a număra citirile, parcurgând pe rând valorile
1,2,...,n. La fiecare pas trebuie să actualizăm, dacă este cazul, intervalul care
îndeplineşte ambele condiŃii din enunŃ, şi care trebuie afişat. Pentru aceasta, vom parcurge
în cadrul fiecărui pas următoarea succesiune de operaŃii:
 Citim de pe un rând al fişierului, în variabilele a şi b, cele două numere care
reprezintă capetele unui interval de forma [a,b] {f >> a >> b;};
 Calculăm numărul nr al valorilor întregi din intervalul [a,b] astfel format
{nr=b-a+1;};
 Există două situaŃii în care se modifică intervalul cu număr maxim de valori
întregi şi capătul din dreapta minim, şi anume:
– dacă numărul valorilor întregi din intervalul [a,b] tocmai citit este mai
mare decât numărul maxim (nr>nrmax)
SAU
– dacă am dat de un interval [a,b] care conŃine un număr de valori
întregi întâlnit şi la alt interval, ŞI capătul din dreapta al intervalul este
mai mic decât capătul minim (b<cmin)
Într-un cuvânt, condiŃia care impune actualizarea intervalului [a,b] cerut
este: (nr>nrmax) || (nr==nrmax && b<cmin)
Dacă este îndeplinită condiŃia de mai sus, înseamnă că intervalul [a,b]
curent îndeplineşte ambele cerinŃe, deci:
– Noul capat minim cmin devine capatul b al intervalului curent
{cmin=b;};
– Noul nrmax devine numărul nr al valorilor întregi din intervalul
{nrmax=nr;};
– Salvăm capetele a şi b ale intervalului curent în variabilele cap1 şi
cap2, pentru că, cel puŃin pentru moment, acesta este intervalul selectat
ce trebuie afişat {cap1=a; cap2=b}.
for (i=1; i<=n; i++)
{
f >> a >> b;
cout << endl << "[" << a << "," << b << "]";
nr=b-a+1;
if ((nr>nrmax) || (nr==nrmax && b<cmin))
405
{
cmin=b;
nrmax=nr;
cap1=a;
cap2=b;
}
}
 La finele ciclului, în variabila nrmax avem numărul maxim de valori întregi
dintre toate intervalele, iar în cap1 şi cap2 am salvat capetele intervalului cu nrmax valori
întregi, care în plus mai au şi capătul din dreapta minim. Ca atare, programul se încheie cu
afişarea acestor valori şi închiderea fişierului f.

// Bac 2009, II.4 / var 29


#include <iostream.h>
#include <conio.h>
#include <fstream.h>
#include <values.h>

void main ()
{
clrscr();
int n,i,a,b,nr,nrmax,cmin,cap1,cap2;
fstream f("bac.txt",ios::in);
f >> n; // citeste numarul n de intervale
nrmax=-MAXINT; // nrmax = numarul maxim de valori intregi aflate in intervalele
date
cmin=MAXINT;
// cmin = capatul din dreapta cel mai mic dintre interv. care contin nrmax valori intregi
cout << "Intervalele citite din fisier sunt: ";
// citeste cele n intervale, si, pentru fiecare interval, actualieaza nrmax si cmin
for (i=1; i<=n; i++)
{
f >> a >> b;
cout << endl << "[" << a << "," << b << "]";
nr=b-a+1;
if ((nr>nrmax) || (nr==nrmax && b<cmin))
{
cmin=b;
nrmax=nr;
// in cap1 si cap2 actualizam capetele intervalului care indeplineste cele doua conditii
cap1=a;
cap2=b;
}
}
cout << endl << "Intervalul este [" << cap1 << "," << cap2 <<
"]";
cout << endl << "Si contine " << nrmax << " valori intregi";
f.close();
getch();
}

406
ÎncercaŃi singuri !

► 1. Fişierul text "triunghi.txt" conŃine pe fiecare linie câte trei


numere separate prin câte un spaŃiu. Nu se cunoaşte câte astfel de triplete sunt în
fişier. Pentru fiecare dintre aceste triplete să se verifice dacă pot reprezenta laturile
unui triunghi (sunt pozitive şi suma a oricare două este mai mare decât al treilea
număr); în caz afirmativ se va stabili natura triunghiului: isoscel, echilateral,
oarecare.
► 2. (Bacalaureat iulie 2009, varianta 81)
Fişierul text NUMERE.IN conŃine, pe fiecare linie a sa, câte două numere
naturale mai mici sau egale decât 10000, despărŃite printr-un spaŃiu. ScrieŃi un
program care să afişeze pe ecran, unul sub altul, cel mai mare număr de pe fiecare
linie, ca în exemplu.
Exemplu: dacă fişierul NUMERE.IN are conŃinutul din figură:
12 14
110 12
4 -8
atunci pe ecran se afişează: 14
110
4

AplicaŃie R.VI.3. Sortarea unui şir de numere citit din fişier


(Bacalaureat august 2000, varianta 2)
În fişierul text "BAC.TXT" se află mai multe numere naturale de cel mult
trei cifre fiecare, numere despărŃite între ele prin câte un spaŃiu. ScrieŃi un program
care crează un alt fişier text numit "BAC2.TXT" care să conŃină aceleaşi numere din
fişierul "BAC.TXT", câte unul pe linie, în ordinea crescătoare a valorii acestora.
Rezolvare
:
 Asignăm fişierelor "BAC.TXT" şi "BAC2.TXT" descriptorii f respectiv g.
Deschidem fişierul f pentru citire (cu atributul "r") şi fişierul g pentru scriere (cu atributul "w").

 Citim şirul de numere din fişier într-un vector v, folosind un ciclu while. La
fiecare pas citim un număr din fişier, adăugându-l ca element nou la sfârşitul vectorului.
Notăm cu i poziŃia la care am ajuns cu adăugarea în vector. Evident valoarea
iniŃială a lui i este 0, pentru că la început vectorul este gol şi primul element care se va
adăuga în el va ocupa poziŃia 0. Cât timp nu am ajuns la sfârşitul rândului în fişier {not
seekeoln(f)}:
 citim un număr din fişier, în elementul v[i] al vectorului
{fscanf(f,"%d",&v[i]);}
 "pregătim" poziŃia următoare la sfârşitul vectorului v, poziŃie pe care se va
memora numărul ce va fi citit la pasul următor al ciclului {i++;}
407
Valoarea finală a lui i reprezintă numărul de elemente ale vectorului {n=i;}.
i=0;
while (!feof(f))
{
fscanf(f,"%d",&v[i]);
cout << v[i] << endl;
i++;
}
n=i;

Exemplu:
Presupunem că fişierul conŃine şirul 12, -3, 8. IniŃial i=0.
Pasul 1: end of file ? nu ⇒ citeşte v[0]=12, i=i+1=0+1=1;
Pasul 2: end of file ? nu ⇒ citeşte v[1]=-3, i=i+1=1+1=2;
Pasul 3: end of file ? nu ⇒ citeşte v[2]=8, i=i+1=2+1=3;
Pasul 4: end of file? da ⇒ iese din ciclu.
n=i ⇒ n=3 numărul de elemente ale vectorului.

 Sortăm crescător vectorul v. Reamintim pe scurt algoritmul de sortare:


 Fiecare din elementele v[0],v[1],...,v[n-2] va juca pe rând rolul unui
aşa numit pivot. Parcurgem pivoŃii într-un ciclu în care contorul i ia pe rând
valorile 0,1,..,n-2 şi la fiecare pas al ciclului, comparăm pivotul v[i] cu
toate elementele aflate după el, v[i+1],...,v[n-1]. În acest scop,
parcurgem poziŃiile acestor elemente într-un alt ciclu cu j=i+1,...,n-1,
şi pentru fiecare element v[j], dacă este mai mare decât pivotul v[i],
atunci interschimbăm v[j] cu v[i] prin "metoda paharelor".
for (i=0; i<=n-2; i++)
for (j=i+1; j<=n-1; j++)
if (v[j]<v[i])
{
temp=v[i];
v[i]=v[j];
v[j]=temp;
}

 Scriem vectorul sortat în fişierul g, fiecare element pe câte un rând.


Parcurgem într-un ciclu poziŃiile i=0,1,...,n-1 ale elementelor vectorului, şi la fiecare
pas scriem elementul v[i] în fişierul g (cu parametrul de control "%d\n", pentru a se
asigura scrierea fiecărui element pe câte un rând).
for (i=0; i<=n-1; i++)
fprintf(g,"%d\n",v[i]);

 În final închidem cele două fişiere, cu procedurile fclose(f) respectiv


fclose(g).

#include <iostream.h>
#include <stdio.h>
FILE *f,*g;
int n,i,j,temp,v[20];

408
void main ()
{
// citeste elementele vectorului din fisier, intr-un ciclu
f=fopen("C:\\BAC.TXT","r");
g=fopen("C:\\BAC2.TXT","w");
i=0;
while (!feof(f))
{
fscanf(f,"%d\n",&v[i]);
cout << v[i] << endl;
i++;
}
n=i;
// sorteaza crescator vectorul
for (i=0; i<=n-2; i++)
for (j=i+1; j<=n-1; j++)
if (v[j]<v[i])
{
temp=v[i];
v[i]=v[j];
v[j]=temp;
}
// scrie vectorul sortat in fisierul de iesire
for (i=0; i<=n-1; i++)
fprintf(g,"%4d",v[i]);
fclose(f);
fclose(g);
cout << "\nS-a scris vectorul sortat in fisierul vect.out";
}

ÎncercaŃi singuri !

► 1. (Bacalaureat iulie 2009, varianta 99 – enunŃ adaptat)


Pe prima linie a fişierului text DATE.TXT se află un număr natural nenul
n (n<=1000), iar pe a doua linie un şir de n numere întregi nenule, depărŃite
prin câte un spaŃiu, fiecare având cel mult nouă cifre.
a) ScrieŃi un program care citeşte numerele din fişier şi ordonează
descrescător doar numerele pozitive din şir, fără a modifica poziŃiile numerelor
negative. Programul va afişa, pe ecran, pe o singură linie, şirul obŃinut după
ordonare, numerele fiind despărŃite prin câte un spaŃiu. În locul fiecărui număr
negativ din şirul citit se va afişa valoarea 0. RealizaŃi un program eficient din
punct de vedere al spaŃiului de memorie folosit.
Exemplu: dacă fişierul DATE.TXT conŃine:
7
32 -491 23 -328 213 51 -4
pe ecran se va afişa: 213 0 51 0 32 23 0
b) DescrieŃi succint, în limbaj natural, metoda utilizată, justificând
eficienŃa acesteia.

409
AplicaŃie R.VI.4. Matrice în fişier text
Se citeşte o matrice din fişierul text "mat.in". Fişierul conŃine:
• pe primul rând numărul m de linii şi numărul n de coloane ale
matricii;
• pe fiecare din următoarele m rânduri, elementele unei linii a matricii,
separate prin spaŃii.
Să se interschimbe între ele două linii date L1, L2, scriindu-se matricea
rezultată în fişierul "mat.out" (elementele fiecărei linii a matricii pe un rând).
Exemplu: mat.in mat.out
4 3 1 5 9
L1=1, L2=2 1 5 9 3 7 11
2 6 10 2 6 10
3 7 11 4 8 12
Rezolvare 4 8 12
:
 Citim matricea a cu m linii şi n coloane din fişierul f, deschis pentru citire. De
pe primul rând din fişier se citesc m şi n. Apoi, într-un ciclu, contorul i va lua pe rând
valorile 0,1,...,m-1 şi pentru fiecare i:
− citim linia i a matricii de pe un rând din fişier: într-un alt ciclu, parcurgem
coloanele j=0,1,...,n-1 ale liniei i şi citim din fişier fiecare element
a[i][j];
− trecem în fişier la rândul următor, cu fscanf(f,"\n").

 În continuare citim numerele de ordine L1 şi L2 ale liniilor care urmează să


fie interschimbate, validând condiŃia ca acestea să fie cuprinse în intervalul 0..m-1.

 Interschimbăm în matrice liniile L1 şi L2 între ele, folosind algoritmul cunoscut


din capitolul "Tablouri": într-un ciclu, parcurgem "în paralel" coloanele celor două linii,
j=0,1,..,n-1, şi pentru fiecare coloană j, interschimbăm între ele elementele aflate pe
respectiva coloană în cele două linii, adică a[L1][j] cu a[L2][j], prin metoda "paharelor".
În continuare trebuie să scriem în fişierul g matricea a rezultată după
interschimbare. Pentru aceasta, parcurgem într-un ciclu liniile i=0,1,..,m-1 ale matricii,
şi pentru fiecare i:
− scriem linia i a matricii pe un rând din fişier: într-un alt ciclu, parcurgem
coloanele j=0,1,...,n-1 ale liniei i şi scriem în fişier fiecare element
a[i][j];
− trecem pe rândul următor în fişier.
Prezentăm în continuare programul complet:
# include <iostream.h>
# include <stdio.h>
int i,j,m,n,temp,L1,L2,a[20][20];
FILE *f,*g;
void main ()
{
f=fopen("c:\\mat.in","r");
410
g=fopen("c:\\mat.out","w");
// citeste numarul de linii si coloane m, n si elementele matricii a, din fisierul f
fscanf (f,"%d%d\n",&m,&n);
for (i=0; i<=m-1; i++)
{
for (j=0; j<=n-1; j++)
fscanf(f,"%d",&a[i][j]);
fscanf(f,"\n");
}
do
{
cout << "\nDati liniile care se vor interschimba: \n";
cin >> L1 >> L2;
} while (L1<0 || L1>m-1 || L2<0 || L2>m-1);
// interschimba intre ele liniile L1 si L2, coloana cu coloana
for (j=0; j<=n-1; j++)
{
temp=a[L1][j];
a[L1][j]=a[L2][j];
a[L2][j]=temp;
}
// scrie matricea rezultata dupa interschimbare in fisierul g
for (i=0; i<=m-1; i++)
{
for(j=0; j<=n-1; j++)
fprintf (g,"%5d ",a[i][j]);
fprintf (g,"\n");
}
cout << "\n S-a scris matricea rezultata, in fisierul mat.out";
fclose(f);
fclose(g);
}

ÎncercaŃi singuri !

► 1. Se citeşte o matrice din fişierul text 'matrice.in'. Fişierul conŃine:


− pe primul rând numărul m de linii şi numărul n de coloane ale matricii;
− pe fiecare din următoarele m rânduri, elementele unei linii a matricii,
separate prin spaŃii.
Să se interschimbe între ele două coloane date C1, C2, scriindu-se matricea
rezultată în fişierul 'matrice.out' (elementele fiecărei linii a matricii pe un rând).
► 2. Se citeşte o matrice din fişierul 'mat.txt'. Fişierul conŃine:
− pe primul rând numărul m de linii şi numărul n de coloane ale matricii;
− pe fiecare din următoarele m rânduri, elementele unei linii a matricii,
separate prin spaŃii.
Să se elimine o linie L din matrice şi să se afişeze pe ecran matricea
rezultată (valoarea lui L se citeşte de la tastatură).

411
AplicaŃie R.VI.5. Numere din fişier cu prima cifră pară
(Bacalaureat iulie 2008, varianta 88)
Fişierul DATE.IN conŃine cel mult 100000 de numere naturale, scrise
toate pe un rând şi separate prin spaŃii, fiecare număr având cel mult nouă cifre. Să
se realizeze un program care scrie în fişierul DATE.OUT, pe o singură linie,
separate prin câte un spaŃiu, toate numerele din fişierul DATE.IN care au prima
cifră pară. (prima cifră a unui număr este considerată cea mai semnificativă, adică
cea mai din stânga).
Exemplu:
dacă fişierul DATE.IN conŃine numerele
45 123 68 8 134 56 876 6666 2 5 123 65
atunci în fişierul DATE.OUT se vor găsi următoarele valori:
45 68 8 876 6666 2 65

Rezolvare
:
 Mai întâi asignăm descriptorul f fişierului 'DATE.IN' şi îl deschidem pentru
citire cu parametrul "ios.in" {fstream f("date.in",ios::in);}, precum şi
descriptorul g fişierului 'DATE.OUT', pe care îl deschidem pentru scriere cu parametrul
"ios.out" {fstream g("date.out",ios::out);}.

 Vom citi succesiv numerele din fişierul f, în aceeaşi variabilă x. Întrucât nu


ştim câte valori se găsesc în fişier, încheierea citirii se va produce în momentul în care am
ajuns la sfârşitul rândului pe care se află toate numerele, care de fapt coincide cu sfârşitul
fişierului. Aşadar, cât timp cât nu s-a atins sfârşitul de fişier (adică atâta timp cât funcŃia
f.eof() returnează 0 (condiŃie care se poate scrie sub forma "!f.eof()"), executăm
următoarele acŃiuni:
 Citim un număr din fişier în variabila x (cu cin);
 Extragem cifrele lui x cu algoritmul cunoscut, pentru a ajunge la prima cifră;
iniŃializăm un deîmpărŃit d cu numărul x, apoi proiectăm un ciclu de
împărŃiri succesive ale lui d la 10, care se execută atâta timp cât d este diferit
de 0; la fiecare pas, extragem o cifră în variabila c (ca fiind restul împărŃirii
lui d la 10), apoi pregătim împărŃirea următoare (noul deîmpărŃit d va fi
câtul împărŃirii curente, d div 10);
d=x;
while (d)
{
c=d%10;
d/=10;
}
 După ce am încheiat extragerea cifrelor numărului citit în variabila x la un
pas al primului ciclu, avem certitudinea că ultima cifră extrasă, adică
valoarea lui c cu care s-a ieşit din ciclu, reprezintă prima cifră a lui x; testăm
dacă această cifră este pară (adică dacă restul împărŃirii lui c la 2 este 0), iar
în caz afirmativ scriem în fişierul g respectiva cifră c, urmată de un spaŃiu

412
(pentru că toate valorile care îndeplinesc condiŃia cerută trebuie scrise pe un
singur rând al fişierului de ieşire).
if (!(c%2))
g << x << " ";

 În final, mai afişăm pe ecran un mesaj care anunŃă construirea fişierului


DATE.OUT, şi închidem fişierele f şi g.

// Bac 2008, varianta 88


#include <iostream.h>
#include <conio.h>
#include <fstream.h>

void main ()
{
clrscr();
long x,d;
int c;
fstream f("f:\\Fisiere\\date.in",ios::in);
fstream g("f:\\Fisiere\\date.out",ios::out);
while (!f.eof()) // cat timp nu am ajuns la sfarsitul fisierului
{
// citeste un numar din fisierul f in variabila x
f >> x;
// extrage cifrele lui x
d=x;
while (d)
{
c=d%10;
d/=10;
}
// daca ultima cifra extrasa (prima din numar) este para, scrie numarul x in fisierul g
if (!(c%2))
g << x << " ";
}
cout << endl << "S-au scris numerele cerute in fisierul
date.out";
f.close();
g.close();
getch();
}

ÎncercaŃi singuri !
► 1. (Bacalaureat iunie 2008, varianta 72)
Pe prima linie a fişierului text BAC.IN se află un număr natural n
(0<n≤≤1000), iar pe a doua linie n numere reale pozitive, despărŃite prin câte un spaŃiu.
RealizaŃi un program care citeşte datele din fişierul de intrare, apoi scrie în fişierul
BAC.OUT, pe o singură linie, despărŃite prin câte un spaŃiu, acele numere din fişierul de
intrare a căror parte întreagă este număr prim. Dacă nu există nici o valoare în fişierul
BAC.IN cu proprietatea cerută, atunci se va afişa mesajul NU.
413
Exemplu: dacă fişierul BAC.IN are conŃinutul din figură,
6
12.095 31.567 5.789 789.834 1234.923 2.345

atunci după execuŃia programului, în fişierul BAC.OUT se găseşte următorul


şir de numere: 31.567, 5.789, 2.345

► 2. (Bacalaureat iunie 2008, varianta 74)


Fişierul BAC.IN conŃine pe prima linie un număr natural n (0<n≤ ≤5000), iar
pe a doua linie n numere naturale de cel mult nouă cifre fiecare, separate prin câte un
spaŃiu. Să se scrie un program care citeşte n, apoi cele n numere naturale din fişierul
BAC.IN şi scrie în fişierul text BAC.OUT, pe câte o linie fiecare, numerele de pe a doua
linie a fişierului BAC.IN care au exact patru cifre.
Exemplu:
BAC.IN BAC.OUT
6 1124
23 1124 567 89013 5586 1200 5586
1200

AplicaŃie R.VI.6. Fişiere identice


ScrieŃi un program care verifică dacă două fişiere date sunt identice sau nu
(conŃin exact aceleaşi caractere) şi afişează un mesaj corespunzător.
Rezolvare
:
 Folosim o variabilă "semafor" e, a cărei valoare va indica "starea" condiŃiei
testate. Astfel, valoarea finală a lui e va fi: 1 dacă fişierele cu descriptorii f şi g sunt
identice, respectiv 0 în caz contrar. Aplicăm metoda reducerii la absurd: presupunem
iniŃial că fişierele sunt identice iniŃializând e cu 1, apoi încercăm să găsim cazul contrar.
Într-un ciclu, citim "în paralel" fişierele, caracter cu caracter. Cât timp e este 1 şi
nu am ajuns la sfârşitul unuia din fişiere {!(feof(f) || !feof(g))}
 citeşte un caracter c1 din fişierul f şi un caracter c2 din fişierul g;
 dacă găseşte o pereche de caractere (c1,c2) diferite, atunci fişierele nu mai
pot fi identice, deci e devine 0.
 Dacă până acum fişierele sunt identice, mai trebuie testată o posibilitate. Aşa
cum am proiectat ciclul, nu rezultă de nicăieri dacă ieşirea din el s-a produs din cauză ca s-
a atins sfârşitul ambelor fişiere, sau urmare a faptului că s-a ajuns doar la sfârşitul unuia
dintre ele. A doua situaŃie apare atunci când unul din fişiere conŃine nişte caractere în plus
faŃă de celălalt, caz în care fişierele nu mai sunt identice, chiar dacă caracterele testate
coincid. Acest caz se analizează separat. Dacă e sfârşitul lui f şi nu e sfârşitul lui g
{feof(f) && !feof(g)}, atunci variabila e ia valoarea 0. Acelaşi lucru se întâmplă şi
în situaŃia inversă: este sfârşitul lui g dar nu este sfârşitul lui f.
 În final, testăm valoarea variabilei e şi în funcŃie de aceasta tipărim un mesaj.

414
# include <stdio.h>
# include <iostream.h>
char c1,c2;
FILE *f,*g;
int e;
void main ()
{
f=fopen("c:\\1.txt","r");
f=fopen("c:\\2.txt","r");
e=1; // in final, e va fi 1 daca fisierele sunt identice, respectiv 0 in caz contrar
// citeste cate un caracter din cele doua fisiere si verifica egalitatea caracterelor
while (e && !(feof(f) || !feof(g)))
{
c1=fgetc(f);
c2=fgetc(g);
if (c1!=c2)
e=0;
}
// daca pana acum fisierele coincid, e posibil ca unul din ele sa aiba caractere in plus fata de celalalt
if (e)
if (feof(f) && !feof(g))
e=0;
if (!feof(f) && feof(g))
e=0;
fclose(f);
fclose(g);
if (e)
cout << "\n Fisiere identice";
else
cout << "\n Fisiere diferite";
}

ÎncercaŃi singuri !
► 1. (Bacalaureat iunie 2004, varianta 1)
ScrieŃi programul care creează fişierul text BAC.TXT ce conŃine pe prima
sa linie, în ordine, toate literele mari ale alfabetului englez aflate în alfabet după o
literă mare dată de la tastatură.
Exemplu: dacă se citeşte litera R, atunci BAC.TXT va conŃine: STUVWXYZ

► 2. (Bacalaureat iunie 2004, varianta 1)


Fişierul text BAC.TXT conŃine, pe prima linie, un şir de exact 1000 de
caractere (litere, cifre şi spaŃii). ScrieŃi un program care citeşte de la tastatură un
număr natural n (0<n≤1000) şi afişează pe ecran câte caractere cifră există printre
primele n caractere din fişier.
De exemplu, dacă BAC.TXT conŃine: mx 12 5 3a63abc12 fcccc...c

415
(unde litera c apare la sfârşit de 981 de ori) iar de la tastatură se citeşte valoarea
n=11, atunci se va afişa pe ecran numărul 5, deoarece în şirul format din primele
11 caractere există cinci caractere cifră (cele subliniate).

AŃi înŃeles ? Probleme cu răspuns scurt

►1. Care dintre următoarele operaŃii nu sunt posibile într-un fişier text ?
a) Modificarea unor valori în fişier, fără folosirea altor fişiere sau structuri de date.
b) Deschiderea pentru scriere.
c) Testarea sfârşitului de fişier.
d) Deschiderea pentru citire.

►2. Fie un fişier identificat prin descriptorul f şi deschis cu atributul "w". Fie de
asemenea două variabile întregi x şi y, ale căror valori sunt cunoscute. Care dintre
instrucŃiunile de mai jos pot fi executate astfel încât valorile celor două variabile să fie
scrise în fişier fiecare pe alt rând ?
a) fprintf(f,"%d\n%d",x,y);
b) fprintf("%d\n%d",x,y,f);
c) fprintf(f,"\n%d%d\n",x,y);
d) fprintf("\n%d%d\n",x,y,f);

►3. Câte numere se vor găsi în fişierul “nr.txt” după execuŃia programului următor ?
#include <stdio.h>
void main ()
{
int v[9]={0,1,0,0,2,3,0,4,5},i;
FILE *f;
f=fopen("nr.txt","w");
i=0;
while(i<9)
{
while(v[i])
{
fprintf(f,"%3d",v[i]); i++;
}
fprintf(f,"%3d",99);
i++;
}
fclose(f);
}

a) 4 b) 8 c) 9 d) 10

►4. Presupunem că pe hard-disk există fişierul “car.txt” cu următorul conŃinut:

AbCdEfGhIj

416
Ştiind că în conformitate cu standardul ASCII literele mari au coduri succesive
începand cu 65 ('A'← ← 65, 'B'← ←66, etc.), iar literele mici au coduri succesive începand cu
97 ('a'←← 97, 'b'← ← 98, etc.), precizaŃi care va fi conŃinutul fişierului “car2.txt” după
execuŃia programului următor:
#include <stdio.h>
void main ()
{
char c1,c2;
FILE *f,*g;
f=fopen("car.txt","r");
g=fopen("car2.txt","w");
c1=96;
while (!feof(f))
{
c2=fgetc(f);
printf("%c",c2);
if (c2>c1) fputc(c2-32,g);
c1=c2;
}
fclose(f); fclose(g);
}

a) bdfhj b) BDFHJ c) acegi d) ACEGI

►5. DeduceŃi ce valoare va afişa programul următor, presupunând că în fişierul


cu descriptorul f se găsesc pe un rând, separate prin spaŃii, numerele:
1 3 0 0 2 -3 0 -4 -1
#include <stdio.h>
#include <math.h>
void main()
{
FILE *f;
int s=1,i=0,a[20];
f=fopen("numere.txt","r");
while (!feof(f))
{
i++;
fscanf(f,"%d ",&a[i]);
if (a[i]) s*=abs(a[i]);
}
printf("\n%d",s);
fclose(f);
}

a) 1 b) 72 c) -72
d) Programul conŃine erori de sintaxă.

►6. DeduceŃi ce valoare va afişa programul de mai jos, 3 3


dacă fişierul text are următorul conŃinut: 1 2 3
4 5 6
#include <stdio.h> 7 8 9
void main()
{
FILE *f;
417
int i,j,m,n,S=0,a[20][20];
f=fopen("continut.txt","r");
fscanf(f,"%d %d",&m,&n);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
fscanf(f,"%d ",&a[i][j]);
if ((i+j)%2) S+=a[i][j];
}
}
fclose(f);
printf("%d",S);
}

a) 0 b) 8 c) 20 d) 25

►7. Se dă fişierul identificat prin descriptorul f, cu următorul conŃinut:


33 1 -45 18 6

Ce instrucŃiune trebuie scrisă în loc de "....", astfel încât programul următor să


tipărească 85 ?
#include <stdio.h>
void main ()
{
FILE *f;
int x,y;
f=fopen("valori.txt","r");
fseek(f,-6,2);
fscanf(f,"%d",&y);
..................
fscanf(f,"%d",&x);
printf("\n%d%d" ,x,y);
fclose(f);
}

a) fseek(f,11,0); b) fseek(f,-2,2);
c) fseek(f,2,1); d) fseek(f,3,1);

418
Aprofundare

Probleme rezolvate

R.VI.7 El im in ă ri în tr - u n ş ir d i n f iş ier
(Bacalaureat iulie 2008, varianta 3)
ScrieŃi un program care citeşte din fişierul BAC.TXT un şir s de cel mult un
milion de numere naturale, fiecare număr având cel mult patru cifre, şi care
determină numărul de componente ale şirului obŃinut prin eliminarea din cele două
extremităŃi ale lui s a unui număr minim de componente, astfel încât şirul rezultat să
înceapă şi să se termine cu un număr par. Fişierul conŃine cel puŃin un număr par, iar
numerele din fişier sunt separate printr-un singur spaŃiu. Programul va afişa pe ecran
numărul de componente ale şirului obŃinut. Se cere un algoritm eficient din punctul
de vedere al timpului de executare şi al spaŃiului de memorie folosit.
Exemplu: dacă fişierul BAC.TXT conŃine numerele
1 245 22 67 34 29 345 8 354 11 7 34 12 45 39 41 26 67 89 1011
se va afişa pe ecran valoarea 15, deoarece sunt eliminate numerele
subliniate, iar şirul rămas este format din 15 numere.

Rezolvare
:
Întrucât şirul din fişier poate conŃine până la un milion de numere, nu este deloc
eficient să-l memorăm într-un vector. Nici subşirul cuprins între primul şi ultimul element
par nu trebuie salvat nicăieri, deoarece ne interesează numai lungimea acestuia, deci este
suficient să reŃinem doar poziŃiile capetelor sale. În concluzie, putenm citi valorile din şir
una după alta, în aceeaşi variabilă x.
Notăm cu p1 şi p2 poziŃia primului, respectiv ultimului element par (evident,
iniŃial, aceste variabile vor avea valoarea 0, iar în timpul citirii şirului se vor actualiza
corespunzător). În variabila k vom memora poziŃia din şir a numărului la care am ajuns cu
citirea în fişier (care la început va fi desigur tot 0). Declanşăm un ciclu care se va executa
atâta timp cât nu am ajuns la sfârşitul fişierului ("!f.eof()"), şi în care la fiecare pas:
 citim un număr din fişier în variabila x;
 incrementăm cu 1 valoarea lui k, pentru a reŃine în k poziŃia pe care o ocupă
numărul tocmai citit din fişier (astfel, plecând de la k=0, la citirea primului
număr avem k=1, apoi la a doua citire k=2, ş.a.m.d.);
 dacă valoarea lui x este număr par ("!(x%2)"), actualizăm p1 sau p2, astfel:
– dacă variabila p1 are valoarea iniŃială 0, înseamnă că x-ul tocmai citit
este primul număr par din şir, deci poziŃia p1 a primului element par
este tocmai poziŃia k a acestui x (p1=k);
– în caz contrar, înseamnă că am trecut de primul număr par, şi valoarea x
tocmai citită este momentan ultimul element par, deci actualizăm

419
poziŃia p2 prin atribuirea similară p2=k (desigur, este posibil ca la pasii
următori să mai citim în x şi alte valori pare, caz în care p2 se va
modifica din nou);
După încheierea ciclului de citire a şirului, determinăm în variabila lung
lungimea subşirului alcătuit din primul şi ultimul element par, subşir delimitat de poziŃiile
p1 şi p2 (în felul acesta am simulat doar eliminarea din şir a elementelor aflate înaintea
primei valori pare şi a celor situate după ultima valoare pară, nefiind necesară ştergerea
propriuzisă a lor). Dacă în şir au fost găsite cel puŃin două valori pare, atunci p1 şi p2 vor
avea valori nenule, iar lungimea lung va fi |p2-p1+1| (într-adevăr, de exemplu, dacă
subşirul cuprins între prima şi ultima valoare pară are capetele date de p1=8 şi p2=13,
atunci el are este alcătuit din şase elemente, adică |13-8+1| elemente, cu poziŃiile
8,9,10,11,12,13). Numai că există şi două cazuri particulare, în care valoarea lui lung
nu se mai încadrează în formula de mai sus. Aşa de pildă, dacă există un singur element
par, atunci în final p1 va fi diferit de 0, şi p2 a rămas cu valoarea iniŃială 0, iar lungimea
subşirului va fi 1. De asemenea, dacă subşirul nu are nici un element par, atunci p1=p2=0
şi lung va fi 0. Înglobăm cazul general şi cele două cazuri particulare într-o instrucŃiune
"if-else" imbricată pentru a stabili valoarea lui lung, după care afişăm p1, p2 şi lung,
şi închidem fişierul.

// Bac 2008, varianta 3


#include <iostream.h>
#include <conio.h>
#include <fstream.h>
#include <math.h>

void main ()
{
clrscr();
int x,p1,p2,k,lung;
fstream f("C:\\fisiere\\bac6.txt",ios::in);
p1=p2=k=0; // p1 si p2 = capetele subsirului cuprins intre primul si ultimul element
par
cout << "Sirul din fisier este:\n";
while (!f.eof()) // cat timp nu am ajuns la sfarsitul fisierului
{
f >> x; // citeste un numar din fisier in variabila x
k++; // k = pozitia pe care o ocupa numarul x in fisier
cout << x << " ";
// actualizeaza p1 daca x este primul numar par, respectiv p2 in caz contrar
if (!(x%2))
{
if (!p1)
p1=k;
else
p2=k;
}
}
// stabileste valoarea lui lung = lungimea subsirului dintre primul si ultimul element par
if (!p1 && !p2)
lung=0;
else
if (p1 && !p2)
420
lung=1;
else
lung=abs(p2-p1+1);
cout << endl << "Pozitiile capetelor sunt " << p1 << " si " <<
p2;
cout << endl << "Nr de componente ale subsirului cerut este " <<
lung;
f.close();
getch();
}

ObservaŃie:
Rezolvarea de mai sus este super-elegantă, pentru că reuşeşte să actualizeze atât
p1 cât şi p2 într-un singur ciclu. Desigur, se putea proiecta o soluŃie mai "băbească" în
care să tratăm separat cele două capete, în două cicluri, după cum urmează:
− într-un prim ciclu, citim numere din fişier succesiv, în variabila x, până la
întâlnirea primului element par, moment în care actualizăm p1 cu poziŃia k a numărului la
care am ajuns;
− într-un al doilea ciclu, citim tot succersiv restul şirului, până la întâlnirea
sfârşitului de fişier, şi actualizăm p2 de fiecare dată când întâlnim un număr par, ultima
valoare a lui p2 fiind cea care ne interesează.
Chiar dacă nu este atât de conchisă, şi această rezolvare e la fel de eficientă ca cea
dată de noi, pentru că la urma urmei tot o singură parcurgere a şirului are loc !

R.VI.8 Cel ma i ma r e nu mă r
(Bacalaureat iulie 2008, varianta 24)
Fişierul BAC.TXT conŃine pe prima linie un număr natural care poate
conŃine până la un milion de cifre din mulŃimea {0,1,2,...,9}. Cifrele
numărului nu sunt separate prin spaŃii. ScrieŃi un program care afişează cel mai
mare număr ce se poate obŃine din cifrele numărului aflat în fişier. Se va utiliza un
algoritm eficient din punctul de vedere al timpului de executare şi resurselor de
memorie folosite.
Exemplu: dacă fişierul conŃine numărul 24174800...01, unde cifra 0 se
repetă de 2000 de ori, atunci pe ecran se va afişa 874421100...0.
Rezolvare
Este
:
evident faptul că nu putem citi numărul din fişier într-o variabilă de tip
întreg, deoarece, potrivit enunŃului, acesta poate avea până la un milion de cifre. Nici
memorarea cifrelor numărului într-un vector de cifre nu este recomandabilă, deoarece
contravine cerinŃei privitoare la eficienŃa algoritmului.
Vom folosi un vector nr cu 10 elemente, în care poziŃiile i iau ca valori
elementele mulŃimii {0,1,2,...,...,9}, şi fiecare element nr[i] va stabili de câte ori
apare cifra respectivă i în cadrul numărului din fişier.
După asignarea descriptorului f pentru fişierul 'bac.txt' şi deschiderea
acestuia în vederea citirii (folosind funcŃia fstream), iniŃializăm cu 0 întreg vectorul nr.
Într-un ciclu, contorul i, va parcurge poziŃiile elementelor vectorului nr, de la 0 la 9, şi la
fiecare pas facem atribuirea nr[i]:=0.
421
Mai departe, trecem la citirea numărului din fişier, cifra cu cifra. Atâta timp cât
nu am ajuns la sfârşitul fişierului {while !f.eof()}, la fiecare pas:
− Citim o cifra din fişier, ca şi caracter, în variabila c {f >> c;};
− Afişăm cifra respectivă pe ecran, sub forma caracterului-cifră c;
− Incrementăm cu 1 acel element din vectorul nr care contorizează apariŃiile
respectivei cifre în fişier. Dar poziŃia unui element în vectorul nr este tocmai o cifră, iar
noi din fişier am citit în variabila c caracterul-cifră aferent, deci apare acum problema
trecerii de la caracterul-cifră la cifra aferentă. După cum ştiŃi, codurile ASCII ale
caracterelor-cifră '0','1','2',...,'9' sunt succesive, începând cu 48. Prin urmare,
diferenŃa dintre codul unui caracter-cifră oarecare c şi codul caracterului-cifră '0', este
chiar cifra respectivă. De exemplu; dacă am citit caracterul c='4', codul acestuia este 52,
codul cifrei '0' este 48, iar diferenŃa 52-48 este tocmai cifra 4. Aşadar, pentru a obŃine
cifra ca valoare numerică, este suficient să facem diferenŃa dintre codurile ASCII, care se
scrie sub forma c-'0'. Şi cum această cifră reprezintă poziŃia elementului ce trebuie
incrementat în vectorul nr, vom avea atribuirea {nr[c-'0']++}.
De pildă, pentru numărul 24174800...01 (în care cifra 0 se repetă de 2000 de
ori), în final vectorul nr va arăta astfel:

poziŃia '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'
elementul 2000 2 1 0 2 0 0 1 1 0

Pentru a afişa cel mai mare număr care se poate forma cu cifrele din fişier, este
suficient să parcurgem vectorul nr în ordine inversă. Un contor i va parcurge poziŃiile de
la 9 până la 0, reprezentând cifrele zecimale, şi la fiecare pas vom scrie cifra i de atâtea ori
cât ne spune valoarea nr[i], cea care a stabilit numărul de apariŃii. Prin urmare, la fiecare
pas al acestui ciclu, pentru fiecare valoare a lui i, vom avea un alt ciclu, în care contorul j
va număra de la 1 la nr[i], şi pentru fiecare valoare a lui j afişăm cifra i (dacă de
exemplu, la un anumit pas al primului ciclu, pentru o anumită valoare a lui i, elementul
nr[i] a rămas cu valoarea iniŃială 0, adică cifra respectivă nu apare deloc în număr, atunci
în al doilea ciclu contorul j va evolua de la 1 la 0, deci al doilea ciclu nu se va executa
deloc şi, ca atare, cifra în cauză nu se va afişa).
Programul se încheie cu închiderea fişierului f.

// Bac 2008, III.2, var 24


#include <iostream.h>
#include <fstream.h>
#include <conio.h>

void main ()
{
int i,j;
long nr[10];
char c;
clrscr();
fstream f("F:\\fisiere\\bac.txt",ios::in);
// initializeaza vectorul nr care va memora numarul de aparitii ale cifrelor
for (i=0; i<=9; i++)
nr[i]=0;
cout << "Numarul citit din fisier este " << endl;
// citeste numarul cifra cu cifra din fisier si actualizeaza vectorul nr
422
while (!f.eof())
{
f >> c;
cout << c;
nr[c-'0']++;
}
cout << endl << "Cel mai mare numar este: " << endl;
// afiseaza vectorul nr
for (i=9; i>=0; i--)
for (j=1; j<=nr[i]; j++)
cout << i;
f.close();
getch();
}

R.VI.9 Elemente pare şi impare


Se citeşte un şir de numere întregi din fişierul text SIR.IN. Toate
elementele şirului sunt scrise în fişier pe un singur rând, separate prin spaŃii. Nu se
cunoaşte numărul elementelor. Să se scrie în fişierul SIR.OUT elementele distincte
ale şirului citit, "grupate" pe două rânduri: pe primul rând se vor scrie elementele
pare în ordine crescătoare, iar pe al doilea rând elementele impare în ordine
crescătoare. Nu se va folosi nici un algoritm de sortare.
Exemplu: dacă fişierul "sir.in" conŃine numerele
2 7 2 15 3 8 7 8 14 21 4 2 2 4 8
3 7 15 21
atunci fişierul 'sir.out' va avea următorul conŃinut:

Rezolvare
:
Vom crea doi vectori, fie aceştia a şi b, unul pentru elementele pare, iar celălalt
pentru elementele impare ale şirului citit. Mai întâi citim toate numerele din fişier într-un
vector v, folosind un ciclu. Mai notăm cu n1 şi n2 numărul de elemente din vectorii a
respectiv b. IniŃializăm cu 0 un indice i. Cât timp nu am ajuns la sfârşitul fişierului de
intrare, identificat prin descriptorul f, citim un număr din fişier în elementul v[i] (cu
fscanf), apoi incrementăm contorul i. În felul acesta, numerele din fişier vor fi adăugate
succesiv la sfârşitul vectorului v, iniŃial gol. Valoarea finală a lui i reprezintă numărul de
elemente ale vectorului v, pe care îl memorăm în variabila n.
Într-un ciclu for, parcurgem pe rând elementele v[i] ale vectorului v, cu
i=0,1,...,n-1. Pentru fiecare element v[i], testăm dacă este par, şi:
 În caz afirmativ, căutăm pe v[i] în vectorul elementelor pare a, proces pe
care îl vom controla cu ajutorul unei variabile "semafor" gata1, iniŃializată
cu 0 (cu sens de "false", adică "nu e gata"). În timpul acestei căutări,
parcurgem vectorul a deja existent cu un contor k1 (iniŃializat cu 0), şi
procedăm astfel:
• Comparăm pe v[i] cu fiecare element a[k1], atâta timp cât nu am ajuns
la sfârşitul vectorului a şi gata1 este 0. Dacă întâlnim un element a[k1]
egal cu v[i], înseamnă că elementul v[i] nu mai trebuie adăugat,

423
pentru că există deja în vectorul a, deci vom ieşi forŃat din ciclu prin
atribuirea gata1=1. Dacă am ajuns la un element a[k1] mai mare decât
v[i], atunci trebuie să inserăm pe v[i] în vectorul a, exact în locul în
care am ajus cu căutarea, adică pe poziŃia dată de valoarea la care a ajuns
contorul k1. Inserarea se face prin prin mutarea cu o poziŃie mai la
dreapta a tuturor elementelor care urmează după poziŃia cu pricina k1. În
sfârşit, dacă nu e nici un din cele două situaŃii anterioare (adică
a[k1<v[i]), trecem la următorul element, prin incrementarea lui k1;
• dacă la finele acestei căutări variabila gata1 a rămas cu valoarea 0,
înseamnă că elementul v[i] nu a fost găsit în vectorul a al elementelor
pare, şi trebuie să-l adăugăm la sfârşitul acestuia.
 În caz contrar procedăm analog, dar cu vectorul b în locul vectorului a;

#include <iostream.h>
#include <stdio.h>
int v[30],a[30],b[30];
FILE *f,*g;
int i,k1,k2,n,n1,n2,j,gata1,gata2;
void main ()
{
// asignare si deschidere fisiere
f=fopen("c:\\sir.in","r");
g=fopen("c:\\sir2.out","w");
// citim numerele din fisier in vectorul v
i=0;
while (!feof(f))
{
fscanf(f,"%d",&v[i]);
i++;
}
n=i; // n =nr. elementelor citite
// afiseaza sirul citit din fisier
cout << n << endl ;
for (i=0; i<=n-1; i++)
cout << v[i] << " ";
n1=n2=0;
// n1 si n2 =numarul elementelor din vectorii a si b, unde a=vectorul numerelor pare,
// iar b=vectorul numerelor impare
for (i=0; i<=n-1; i++) // parcurge elementele v[i] ale vectorului v
{
if (!(v[i]%2))
{
// daca elementul v[i] este par, atunci il cauta in vectorul a
k1=0; gata1=0;
while (k1<=n1-1 && !gata1)
{
if (a[k1]==v[i])
gata1=1; // daca l-a gasit, iese fortat din ciclu
else
if (a[k1]>v[i])
// insereaza elementul in vectorul a pe pozitia necesara astfel incat
424
// vectorul sa ramana sortat crescator}
{
for (j=n1-1; j>=k1; j--)
a[j+1]=a[j];
a[k1]=v[i];
n1++;
gata1=1;
}
else
k1++;
} // de la while
// daca nu s-a gasit elementul v[i] in vectorul a, atunci il adauga la sfarsit
if (!gata1)
{
a[n1]=v[i];
n1++;
}
} // de la primul if din for
else
{
// daca elementul v[i], memorat in x, este impar, atunci il cauta in vectorul b
k2=0; gata2=0;
while (k2<=n2-1 && !gata2)
{
if (b[k2]==v[i])
gata2=1; // daca l-a gasit, iese fortat din ciclu
else
if (b[k2]>v[i])
// insereaza elementul in vectorul a pe pozitia necesara astfel incat
// vectorul sa ramana sortat crescator
{
for (j=n2-1; j>=k2; j--)
b[j+1]=b[j];
b[k2]=v[i];
n2++;
gata2=1;
}
else
k2++;
} // de la while
// daca nu s-a gasit elementul v[i] in vectorul b, il adauga la sfarsit
if (!gata2)
{
b[n2]=v[i]; n2++;
}
} // de la else
} // de la primul for
cout << endl << "S-a scris fisierul de iesire";
for (i=0; i<=n1-1; i++)
fprintf(g,"%d ",a[i]);
fprintf(g,"\n");
for (i=0; i<=n2-1; i++)
fprintf(g,"%d ",b[i]);
fclose(f); fclose(g);
}
425
R.VI.10 F iş ier c u n u me r e pr im e
ScrieŃi un program eficient care citeşte de la tastatură două numere
naturale n, m (5<n<m≤ ≤ 109 ) şi scrie în fişierul text "BAC.TXT" toate numerele
prime din intervalul închis [n,m] . Numerele se scriu în ordine crescătoare, câte
10 numere pe fiecare linie a fişierului, numerele dintr-o linie fiind despărŃite între
ele prin câte un spaŃiu. De exemplu, dacă se introduc de la tastatură valorile 87 şi
239 , atunci fişierul "BAC.TXT" va avea următorul conŃinut:

89 97 101 103 107 109 113 127 131 137


139 149 151 157 163 167 173 179 181 191
193 197 199 211 223 227 229 233 239

Rezolvare
:
Asignăm descriptorul g fişierului "bac.txt" şi deschidem fişierul pentru
scriere. Citim de la tastatură valorile lui n şi m. Într-un ciclu, variabila k va parcurge toate
numerele naturale de la n la m inclusiv. Pentru fiecare dintre aceste valori ale lui k:
 Verificăm dacă numărul k este prim. IniŃializăm cu 1 o variabilă ok, de tip
semafor presupunând că numărul este prim (la final, valoarea lui ok, 0 sau 1
va indica "starea" condiŃiei testate). Apoi parcurgem într-un alt ciclu posibilii
divizori ai lui k, aceştia fiind j=2,3,...,[k/2]. La fiecare pas, dacă j
este divizor al lui k, variabila ok ia valoarea 0.
 Dacă ok a rămas cu valoarea 1, înseamnă că numărul k este prim, deci acesta
trebuie scris în fişierul g. Dificultatea problemei constă în faptul că trebuie
scrise câte zece numere pe un rând. Pentru aceasta avem nevoie de o variabilă
p care în timpul parcurgerii intervalului (n,m) ne va indica la al câtâlea număr
am ajuns pe rândul curent în fişier. Înaintea ciclului iniŃializăm p=1, iar în
ciclu, înainte de scrierea unui număr prim k mai facem o testare:
 dacă p<=10 vom scrie valoarea lui k pe rândul curent, acolo unde a
ajuns indicatorul de fişier;
 în caz contrar, trecem pe rând nou în fişier şi "resetăm" contorul p prin
atribuirea p=1 (reluând astfel numărătoarea de la capăt), apoi scriem
valoarea lui k.
# include <iostream.h>
# include <stdio.h>
int p,k,j,m,n,ok;
FILE *g;
void main ()
{
g=fopen ("c:\\bac.txt","w");
cout << "n, m="; cin >> n >> m;
p=1; // variabila p va indica la al catalea nr suntem pe randul curent in fisier
for (k=n; k<=m; k++) // in variabila k trec pe rand numerele naturale de la n la m inclusiv

426
{
// testeaza daca numarul k este prim
ok=1;
for (j=2; j<=k/2; j++)
if (k%j==0) ok=0;
if (ok) // in cazul in care k este prim, il scrie in fisierul g
if (p<=10)
{
fprintf (g,"%4d",k); p++;
}
else
{
fprintf (g,"\n"); p=1;
fprintf (g,"%4d",k);
}
}
cout << "\nS-au scris numerele prime in fisier";
fclose(g);
}

Probleme propuse

Probleme suplimentare
► 1. (Bacalaureat iulie 2009, varianta 3)
Fişierului text NR.TXT conŃine pe o singură linie, separate prin câte un
singur spaŃiu, cel mult 100 de numere naturale, fiecare număr având cel mult 4
cifre. Să se scrie un program care citeşte toate numerele din fişier şi scrie pe ecran,
pe o singură linie, separate prin câte un spaŃiu, în ordine crescătoare, toate
numerele din fişier care au cel puŃin trei cifre. Dacă fişierul nu conŃine astfel de
numere se va afişa mesajul NU EXISTA.
Exemplu: dacă fişierul conŃine numerele 123 17 3844 459 9 68
atunci pe ecran se vor afişa valorile:
123 3844 459

► 2. (Bacalaureat iulie 2009, varianta 2)


Fişierul text NR.TXT conŃine pe o singură linie, separate prin câte un
singur spaŃiu, cel mult 100 de numere întregi, fiecare număr având cel mult 4
cifre. ScrieŃi un program care citeşte numerele din fişierul NR.TXT şi afişează pe
ecran, separate prin câte un spaŃiu, în ordine crescătoare, toate numerele naturale
nenule din fişier. Dacă nu există astfel de numere se va afişa mesajul NU EXISTA.
Exemplu: dacă fişierul NR.TXT conŃine numerele:
-3 -10 0 7 -5 7 51 -800 6 3798,
atunci pe ecran se va afişa: 7 7 51 6 3798
IndicaŃii: Într-un ciclu, cât timp nu am ajuns la sfârşitul fişierului, citim
succesiv numerele din fişier în aceeaşi variabilă x. La fiecare pas, pentru fiecare x citit,
ca să verificăm dacă valoarea lui x este un număr natural, este suficient să testăm dacă
x>0 şi x=[x].
427
► 3. (Bacalaureat iulie 2009, varianta 2..)
Fişierul text BAC.TXT conŃine pe prima linie numărul natural n,
1<=n<=10000, pe următoarele n linii un tablou unidimensional de n numere
întregi, iar pe ultima linie două numere întregi a şi b (a≤b ) separate de
un spaŃiu. Fiecare dintre cele n numere, precum şi valorile a şi b, au cel 4
-2
mult patru cifre.
72
ScrieŃi un program care afişează pe ecran cel mai mic număr 14
natural din intervalul închis [a,b] care se găseşte în şirul dat. Dacă nu 25
există un astfel de număr, programul afişează textul NU. 8 35
Exemplu: dacă fişierul BAC.TXT are conŃinutul alăturat,
programul afişează valoarea 14.
► 4. (Bacalaureat iulie 2000, varianta 2)
ScrieŃi un program care generează toate numerele prime strict mai mici
decât x (x număr natural). Valoarea variabilei x se citeşte de la tastatură. Numerele
prime generate vor fi scrise în fişierul text BAC.TXT, câte unul pe linie.
Exemplu: pentru x=10 se vor scrie în fişier numerele 2, 3, 5 şi 7.
► 5. Se citesc de la tastatură două numere întregi a şi b. RealizaŃi un
program care crează un fişier text ce va conŃine, pe un singur rând separate prin
spaŃii, toate numerele naturale cuprinse între a şi b alcătuite numai din cifre
identice.
Exemplu:
Pentru a=10 şi b=250, fişierul de ieşire va arăta astfel:
11 22 33 44 55 66 77 88 99 111 222

IndicaŃii: Într-un ciclu, parcurgem în contorul i toate numerele naturale de la a


la b, şi pentru fiecare i testăm dacă este format numai din cifre identice, iar în caz
afirmativ scriem în fişier respectiva valoare a lui i. Pentru a verifica proprietatea
cerută, folosim metoda reducerii la absurd, adică presupunem iniŃial că acel i este
alcătuit numai din cifre identice, iniŃialiozând cu 1 o variabilă ok cu sens logic, apoi
căutăm cazul contrar. În acest scop extragem cifrele lui i şi dacă am găsit două cifre
alăturate diferite între ele, atunci ok ia valoarea 0.
► 6. (Bacalaureat iulie 2009, varianta 5)
ScrieŃi un program care citeşte de la tastatură un număr natural n cu cel
mult 8 cifre (n<=10) şi care creează fişierul text NR.TXT ce conŃine numărul n şi
toate prefixele nenule ale acestuia, pe o singură linie, separate prin câte un spaŃiu,
în ordine descrescătoare a valorii lor.
Exemplu: pentru n=10305 fişierul NR.TXT va conŃine numerele:
10305 1030 103 10 1

► 7. (Bacalaureat iulie 2001, varianta 4)


ScrieŃi un program Pascal care citeşte de la tastatură un număr n (n<=109)
şi creează fişierul text BAC.TXT, care să conŃină toate pătratele perfecte mai mici
sau egale cu n, despărŃite între ele prin câte un spaŃiu. Algoritmul corespunzător
428
programului trebuie să aibă în vedere o prelucrare cât mai eficientă ca timp de
executare şi spaŃiu de memorie utilizat.
Exemplu: pentru n=68, conŃinutul fişierului BAC.TXT este următorul:
0 1 4 9 16 25 36 49 64

► 8. (Bacalaureat iulie 2009, varianta 8)


ScrieŃi un program care citeşte de la tastatură un număr natural n (n≤50) şi
care afişează pe prima linie a fişierului BAC.TXT primele n numere pare,
0 2 4
pe a doua linie primele n-1 numere pare,..., pe linia n primul număr par.
0 2
Numerele vor fi afişate pe fiecare linie în ordine crescătoare şi vor fi 0
separate prin câte un spaŃiu.
Exemplu: dacă n=3 fişierul BAC.TXT va avea conŃinutul din figură.
IndicaŃii: Folosim două cicluri. În primul, contorul i va număra rândurile de la
1 la n, iar în al doilea contorul j va trece în revistă numerele afişate pe fiecare linie i,
respectiv primele i numere naturale pare. Dacă în cazul primului ciclu putem folosi un
for, pentru al doilea ne va trebui un while (iniŃial j=0, ciclul se execută cât timp j<=i,
şi la fiecare pas facem j=j+2).
► 9. (Bacalaureat iulie 2001, varianta 6)
ScrieŃi un program Pascal care citeşte de la tastatură un număr natural n,
(0<n<=15 ) şi crează un fişier text cu numele 'A.TXT' ce conŃine pe prima linie
un caracter A , pe a doua linie două caractere A nedespărŃite prin spaŃii, pe linia a
treia trei caractere A nedespărŃite prin spaŃii etc. Ultima linie a fişierului trebuie să
fie linia a n -a care să conŃină n caractere A nedespărŃite prin spaŃii.
A
Exemplu: AA
dacă se citeşte n=4 , fişierul 'A.TXT' creat trebuie să fie: AAA
AAA
► 10. (Simulare Bacalaureat, iulie 2005)
ScrieŃi programul Pascal care citeşte de la tastatură un
număr natural nenul n şi creează fişierul text BAC.TXT ce conŃine: 1 1 1 1
2 2 2
pe prima linie n numere de 1, pe a doua linie n-1 numere egale cu 3 3
2, pe a treia linie n-2 numere egale cu 3, etc., pe ultima linie 1
conŃinând o singură dată numărul n. De exemplu, dacă se citeşte AAA
n=4, atunci ’bac.txt’ va avea conŃinutul din figură.

► 11. (Bacalaureat iulie 2008, varianta 84)


ScrieŃi un program care citeşte de la tastatură un număr natural
nenul n, apoi construieşte fişierul STELUTE.TXT, astfel încât acesta să *
conŃină: pe prima linie un singur caracter ’*’, pe a doua linie două **
caractere ’*’, …, pe a n-a linie n caractere ’*’, apoi, în continuare n- ***
****
1 caractere ’*’ pe linia n+1, n-2 caractere ’*’ pe linia n+2,…, ultima ***
linie, cea cu numărul de ordine 2*n-1 conŃinând, la fel ca şi prima, un **
singur caracter ’*’. *
Exemplu: pentru n=4, fişierul va avea conŃinutul din figură:

429
► 12. (Bacalaureat iulie 2009, varianta 58)
Fişierul text BAC.TXT conŃine, pe o singură linie, cel puŃin două şi cel
mult 100 de numere naturale nenule distincte de cel mult patru cifre fiecare,
numerele fiind separate prin câte un spaŃiu. ScrieŃi un program care citeşte
numerele din fişier şi scrie pe ecran, în ordine crescătoare, cele mai mici două
numere dintre cele citite. Se cere un algoritm eficient de rezolvare.
Exemplu: dacă fişierul BAC.TXT conŃine numerele:
1017 48 310 5710 162
atunci se va afişa: 48 162
IndicaŃii: Un algoritm eficient trebuie să evite memorarea numerelor într-un
vector, motiv pentru care le vom citi pe rând într-un ciclu, în aceeaşi variabilă x, cât timp
nu am ajuns la sfâtşitul fişierului. Notăm cu min1 cel mai mic număr din fişier iar cu min2
al doilea număr ca mărime, şi iniŃializăm ambele variabile cu MAXINT. Pentru fiecare x
citit, facem două testări:
− dacă x este mai mic decât min1, atunci el devine noul min1;
− dacă x>min1 dar în acelaşi timp x<min2, atunci x devine noul min2.
► 13. (Bacalaureat iulie 2009, varianta 15)
În fişierul text BAC.IN se găsesc, pe o singură linie, separate prin câte un
spaŃiu, mai multe numere naturale de cel mult şase cifre fiecare. Se cere să se
determine şi să se afişeze pe ecran ultimul număr impar din fişierul BAC.IN. Dacă
în fişier nu există niciun număr impar se va scrie pe ecran mesajul Nu există
numere impare.
Exemplu: dacă fişierul BAC.IN conŃine valorile: 12 6 25 68 13 8
24 31 42 se va afişa 31.
a) DescrieŃi în limbaj natural un algoritm eficient, din punct de vedere al
spaŃiului de memorie şi al timpului de executare, pentru rezolvarea acestei
probleme, explicând în ce constă eficienŃa acestuia.
b) ScrieŃi programul corespunzător algoritmului descris.
► 14. (Bacalaureat iulie 2009, varianta 14)
Fişierul text BAC.TXT conŃine mai multe numere naturale cu cel mult şase
cifre fiecare, câte un număr pe fiecare linie a fişierului. ScrieŃi un program care
afişează pe ecran toate numerele din fişier, câte cinci numere pe fiecare linie,
separate prin câte un spaŃiu, cu excepŃia ultimei linii care poate conŃine mai puŃin
de 5 numere.
Exemplu: dacă fişierul conŃine numerele:
2 8 4 7 3 9 5 4 1 8 2 4 2 8 4 7 3
atunci pe ecran se vor afişa următoarele trei rânduri: 9 5 4 1 8
2 4

IndicaŃii: Cerându-se doar afişarea succesivă a numerelor, le putem citi pe


rând în aceeaşi variabilă x, până la întâlnirea sfârşitului de fişier, fără a avea nevoie de
un vector. Ca să afişăm câte cinci numere pe un rând avem nevoie de un contor care să
numere de la 1 la 5, şi pe care, de fiecare dată când ajunge la valoarea 5, îl
reiniŃializăm cu 1.

430
► 15. (Bacalaureat iulie 2009, varianta 80)
Fişierul text BAC.IN conŃine cel mult 1000 de numere naturale cu cel
mult patru cifre fiecare, despărŃite prin câte un spaŃiu. ScrieŃi un program care
citeşte numerele din fişier şi afişează pe ecran, în ordine crescătoare, acele numere
din fişier care au cifrele egale. Dacă fişierul nu conŃine niciun astfel de număr, se
va afişa pe ecran mesajul NU EXISTA.
Exemplu: dacă fişierul BAC.IN conŃine numerele: 30 44 111 7 25 5
atunci pe ecran se va afişa 5 7 44 111.
► 16. (Bacalaureat iulie 2009, varianta 47)
Fişierul text BAC.TXT conŃine pe prima linie un număr natural n
(n<100), iar pe a doua linie, separate prin câte un spaŃiu, n numere naturale, mai
mici decât 30000 fiecare. ScrieŃi un program care citeşte de la tastatură un număr
natural k (k<10) precum şi numerele din fişierul BAC.TXT apoi determină şi
afişează pe ecran, cu câte un spaŃiu între ele, toate numerele de pe a doua linie a
fişierului care conŃin în scrierea lor cifra memorată în variabila k. Dacă nu există
un asemenea număr pe a doua linie a fişierului, se afişează pe ecran mesajul NU.
Exemplu: dacă se citeşte de la tastatură k=2, iar fişierul are conŃinutul din
imagine, atunci pe ecran se afişează numerele: 234 202 427 92
8
234 5678 317 809 202 427 92 6004

► 17. (Bacalaureat iulie 2009, varianta 94)


Fişierul text BAC.TXT conŃine pe fiecare linie câte un număr întreg format
din cel mult patru cifre. Se ştie că fişierul conŃine cel puŃin un număr. ScrieŃi un
program eficient atât din punct de vedere al timpului de executare cât şi din punct
de vedere al spaŃiului de memorie utilizat, care citeşte de la tastatură un număr real
x, apoi determină şi afişează acel număr din fişierul BAC.TXT care are valoarea
cea mai apropiată de valoarea lui x.
Exemplu: dacă fişierul BAC.TXT are conŃinutul alăturat, iar de 4
la tastatură se citeşte valoarea -3.85, programul va afişa valoarea -5. -5
a) DescrieŃi succint, în limbaj natural, metoda de rezolvare -6
-984
folosită, explicând în ce constă eficienŃa ei (3 – 4 rânduri).
1345
b) ScrieŃi un program C/C++ care rezolvă problema conform -1
metodei descrise.
► 18. (Bacalaureat iulie 2009, varianta 97)
Pe prima linie a fişierului text DATE.TXT se află un număr natural n
(0<nδ10000), iar pe a doua linie un şir de n numere naturale, depărŃite prin câte
un spaŃiu, fiecare având cel mult patru cifre.
a) ScrieŃi un program care citeşte numerele din fişier şi afişează, pe ecran,
valorile din şir, în ordinea crescătoare a cifrei unităŃilor. Dacă două numere din şir
au aceeaşi cifră a unităŃilor nu contează care dintre ele va fi afişat primul. RealizaŃi
un program eficient din punct de vedere al timpului de executare.
Exemplu: dacă fişierul DATE.TXT conŃine:
431
7
32 491 26 328 213 500 422

atunci pe ecran se va afişa: 500 491 32 422 213 26 328


b) DescrieŃi succint, în limbaj natural, metoda utilizată, justificând
eficienŃa acesteia.
► 19. (Bacalaureat iulie 2009, varianta 89)
Fişierul text BAC.TXT conŃine pe mai multe rânduri cel mult 50000 de
numere naturale din intervalul închis [0, 99], numerele de pe acelaşi rând fiind
separate prin câte un spaŃiu.
a) ScrieŃi un program care afişează pe ecran, în ordine crescătoare, acele
numere din fişier care au cel puŃin k divizori, k fiind un număr natural (k<20) citit de
la tastatură, utilizând un algoritm eficient din punct de vedere al timpului de executare.
Dacă un număr care corespunde cerinŃei apare de mai multe ori, se va afişa o singură
dată. Numerele vor fi afişate pe ecran separate prin câte un spaŃiu.
Exemplu: dacă fişierul conŃine numerele: 15 36 33 36 1 19 1 24 2,
iar pentru k se citeşte valoarea 5, se vor afişa numerele 12 24 36.
b) DescrieŃi succint, în limbaj natural, algoritmul utilizat, justificând
eficienŃa acestuia.
► 20. Se citeşte o matrice a din fişierul MATRICE.TXT. Fişierul conŃine:
− pe primul rând două numere întregi m şi n, separate prin câte un spaŃiu;
− pe fiecare din următoarele m rânduri, cel n elemente ale unei linii a unei
matrice a cu m linii * n coloane;
RealizaŃi un program care scrie în fişierul DIAG.TXT, pe un singur rând
separate prin spaŃii, elementele pare de sub diagonala principală a matricii a,
ordonate crescător.
IndicaŃii: Citim mai întâi valşorile lui m şi n de pe primul rând al fişierului, apoi,
într-un ciclu cu i=1,2,...,m, parcurgem rândurile din fişier, care sunt de fapt liniile
matricii. Pentru fiecare rând i, parcurgem coloanele j de la 1 la i, deoarece ne
interesează doar elementele de sub diagonala principală. Pe acestea trebuie să le
adăugăm pe rând într-un vector v, pentru a le putea sorta crescător. Un al treilea contor
k, iniŃializat cu 1, va urmări poziŃia la care am ajuns cu adăugarea la sfârşitul
vectorului v. IniŃial k=1, şi pentru fiecare element de sub diagonala principală, după ce
l-am copiat în vector, facem k++ (pregătim următoarea "căsuŃă" în vector". După
încheierea celor două cicluri de parcurgere, mai trebuie să sortăm vectorul v, folosind
unul din algoritmii învăŃaŃi. Dacă sunteŃi ingenioşi, vă veŃi da seama că nici măcar nu
este necesar să completăm în memorie matricea !

► 21. Fişierul MAT.IN conŃine:


− pe primul rând două numere întregi m şi n, separate prin câte un spaŃiu;
− pe fiecare din următoarele m rânduri, cel n elemente ale unei linii a unei
matrice a cu m linii * n coloane;
RealizaŃi un program care construieşte şi scrie în fişierul MAT.OUT transpusa
matricii a, adică matricea obŃinută din a prin inversarea liniilor şi coloanelor între ele
432
(liniile devin coloane, iar coloanele devin linii). Matricea transpusă se va scrie în
fişierul MAT.OUT în acelaşi format ca şi cea din fişierul de intrare.
Exemplu: MAT.IN MAT.OUT
2 3 -1 2 7
7 -5 9 3 -5
-1 9

► 22. Fişierul TABLOU.IN conŃine m rânduri de numere întregi, pe fiecare


rând găsindu-se m numere separate prin spaŃii. Interpretând conŃinutul fişierului ca
un "tablou" cu m linii * n coloane de numere, realizaŃi un program care mută la
sfârşitul partea dreaptă a tabloului acele coloane care conŃin cel puŃin p elemente
nule (unde valoarea lui p se citeşte de la tastatură). Coloanele care îndeplinesc
condiŃia vor fi mutate exact în ordinea în care sunt parcurse de la stânga la dreapta,
iar celelalte coloane vor ocupa partea de început a tabloului, exact în ordine iniŃială.
Tabloul rezultat după mutare se va scrie în acelaşi format în fişierul TABLOU.OUT.
Exemplu: pentru p=3 şi fişierul TABLOU.IN de mai jos, noua ordine a
coloanelor în fişierul TABLOU.OUT va fi (2 4 5 1 3); coloanele 1 şi 3 au fost
mutate la sfârşit deoarece conŃin cel puŃin trei elemente nule.
TABLOU.IN TABLOU.OUT
2 1 0 0 1 9 1 0 1 9 2 0
0 0 0 3 1 2 0 3 1 2 0 0
0 7 4 3 1 7 7 3 1 7 0 4
0 0 0 3 1 0 0 3 1 0 0 0
5 2 0 6 1 0 2 6 1 0 5 0

► 23. (Bacalaureat iulie 2009, varianta 51)


Fişierul text DATE.IN conŃine pe prima linie un număr natural nenul n
(n≤≤100), iar pe a doua linie n numere naturale nenule separate prin câte un spaŃiu.
ScrieŃi un program care citeşte toate numerele din fişier, apoi construieşte în
memorie un tablou unidimensional a, ale cărui elemente vor fi cele n valori citite,
şi afişează pe ecran perechile de elemente de forma (ai,aj), unde 1<=i<j<=n, cu
proprietatea că ambele elemente ale perechii au aceeaşi paritate. Fiecare astfel de
pereche se va afişa pe câte o linie a ecranului, cu elementele sale separate prin câte
un spaŃiu. În cazul în care nu există nici o pereche cu proprietatea cerută, se va
afişa valoarea 0.
Exemplu: dacă fişierul DATE.IN are conŃinutul din 5
figură, atunci pe ecran se vor afişa perechile: (16,22), (16,6), 16 22 3 6 1
(22,6), (3,1).
IndicaŃii: De pe prima linie a fişierului citim valoarea lui n, apoi, într-un ciclu,
citim numerele de pe al doua linie în vectorul v (contorul i al ciclului va lua succesiv
valorile 0,1,...,n-1, şi la fiecare pas citim un număr din fişier în elementul a[i] al
vectorului). Odată construit vectorul, trebuie să formăm toate perechile de elemente de
forma (a[i],a[j]). Pentru aceasta, este suficient să formăm toate perechile de indici
433
de forma (i,j), în două cicluri, cu i=0,1,...,n-2 şi j=i+1,...,n-1. Pentru
fiecare astfel de pereche (a[i],a[j]), testăm dacă a[i] şi a[j] sunt ambele pare
SAU ambele impare, iar în caz afirmativ afişăm respectiva pereche.

► 24. Fişierul SIR.TXT conŃine pe primul rând un întreg n, iar pe al


doilea rând un şir de n numere întregi separate prin spaŃii. RealizaŃi un program
care determină perechile de elemente ale şirului (nu neapărat consecutive) cu
proprietatea că ambele elemente ale perechii au aceeaşi sumă a cifrelor. Prechile
astfel determinate vor fi scrise în fişierul PERECHI.TXT, fiecare pereche pe câte
un rând, cu cele două elemente ale sale separate prin spaŃii.
Exemplu: SIR.TXT PERECHI.TXT
6 5 122
5 301 122 62 401 17 5 401
122 401
62 17

► 25. (Bacalaureat iulie 2009, varianta 22)


ScrieŃi un program care citeşte din fişierul text BAC.TXT un numărul
întreg n (1≤n≤10000) şi un şir de n perechi de numere întregi (a,b)
(1≤≤ a≤ ≤ 32000), fiecare pereche fiind scrisă pe o linie nouă a fişierului, cu un
≤ b≤
spaŃiu între cele două numere. Programul afişează pe ecran pentru fiecare pereche
(a,b) cel mai mare număr natural din intervalul închis [a,b] care este o putere
a lui 2 sau numărul 0 dacă nu există nicio putere a lui 2 în intervalul respectiv.
Un număr p este putere a lui 2 dacă există un număr natural k astfel 3
încât p=2*k. 2 69
Exemplu: dacă fişierul BAC.TXT conŃine numerele din 10 20
figură, atunci se va afişa: 64 16 0. 19 25

► 26. Fişierul text TRIUNGHI.TXT conŃine pe fiecare linie câte trei


numere separate prin câte un spaŃiu. Nu se cunoaşte câte astfel de triplete sunt în
fişier. Pentru fiecare dintre aceste triplete să se verifice dacă pot reprezenta laturile
unui triunghi (sunt pozitive şi suma a oricare două este mai mare decât al treilea
număr); în caz afirmativ se va stabili natura triunghiului în funcŃie de laturi. Pe
ecran se va afişa pentru fiecare triplet, pe un rând, câte un mesaj 3 4 6
sugestiv de genul: "ISOSCEL", "ECHILATERAL", "OARECARE", "NU E 4 4 5
TRIUNGHI". 7 7 8
Exemplu: dacă fişierul are conŃinutul din figură, atunci pe 1 2 9
ecran se vor tipări următoarele rânduri: 3 3 3

OARECARE
ISOSCEL
ISOSCEL
NU E TRIUNGHI
ECHILATERAL

434
► 27. (Bacalaureat iulie 2009, varianta 31)
În fişierul NUMERE.TXT se află memorate, pe prima linie un număr natural
n (1≤n≤100), iar pe fiecare dintre următoarele n linii, câte două numere întregi
x,y (-100≤ ≤ x≤ ≤ 100 ), reprezentând capetele câte unui segment [x,y] desenat
≤ y≤
pe axa Ox a sistemului de coordinate carteziene.
a) ScrieŃi în limbajul C/C++ un program eficient din punct de vedere al
timpului de executare şi al spaŃiului de memorare, care citeşte din fişier datele
existente, determină segmentul rezultat în urma intersecŃiei tuturor celor n
segmente date şi afişează pe ecran două numere despărŃie printr-un spaŃiu ce
reprezintă capetele segmentului cerut. Dacă segmentele nu au niciun punct comun
se va afişa pe ecran valoarea 0. 5
b) DescrieŃi în limbaj natural algoritmul utilizat, justificând -7 10
eficienŃa acestuia. 3 20
Exemplu: dacă fişierul NUMERE.TXT are conŃinutul din -5 5
imagine, se va afişa pe ecran: 3 5 0 12
-8 30

► 28. Să se rezolve ecuaŃiile de gradul al doilea ale căror


coeficienŃi se găsesc în fişierul COEF.TXT. Fişierul conŃine pe fiecare linie trei
numere reale, separate prin spaŃii, reprezentând coeficienŃii unei ecuaŃii, şi nu se
cunoaşte numărul liniilor. Pentru fiecare ecuaŃie, se va scrie pe un rând al
ecranului: rădăcinile ecuaŃiei separate prin spaŃii dacă ecuaŃia este
rezolvabilă, respectiv mesajul 'nu are soluŃii' în caz contrar. 1 -3 2
Exemplu: dacă fişierul are conŃinutul din imagine, atunci pe 1 -2 1
1 1 -3
ecran se vor afişa următoarele rânduri: 1 -1 -2
1 2
1 1
nu are solutii
2 -1

► 29. (Bacalaureat iulie 2009, varianta 31)


Fişierul text NUMERE.IN conŃine, pe fiecare linie, câte două numere
naturale nenule mai mici sau egale decât 10000, despărŃite printr-un spaŃiu,
reprezentând numitorul şi numărătorul câte unei fracŃii. ScrieŃi un program care,
pentru fiecare linie k din fişierul NUMERE.IN, citeşte numitorul şi numărătorul
fracŃiei de pe această linie şi scrie în fişierul text NUMERE.OUT, tot pe linia k,
numitorul şi numărătorul acestei fracŃii, adusă la forma ireductibilă, ca în exemplu.
Exemplu: dacă fişierul NUMERE.IN are conŃinutul alăturat: 12 14
11 12
2 2
atunci fişierul NUMERE.OUT va avea următorul conŃinut: 6 7 4 8
11 12
1 1
1 2

435
► 30. În fişierul NR.TXT se găsesc n perechi de numere întregi.
1 3
Fişierul conŃine: pe primul rând valoarea lui n, apoi, pe fiecare din 1 2
următoarele n rânduri, elementele unei perechi separate printr-un spaŃiu. 2 2
Să se afişeze numărul perechilor cu proprietatea că media aritmetică a 3 9
celor două numere din pereche este egală cu o valoare dată M (unde M se -2 6
citeşte de la tastatură). 0 1
Exemplu: pentru M=2 şi fişierul din figură, programul va afişa
valoarea 3.
► 31. În fişierul SIR.IN se găseşte un şir de numere întregi, scrise toate
pe un rând, separate prin câte un spaŃiu. Nu se cunoaşte numărul de elemente ale
şirului. RealizaŃi un program care inserează între oricare două elemente ale şirului
media lor aritmetică. Elementele şirului rezultat după inserare, se vor scrie în
fişierul SIR.OUT, unul sub altul (câte unul pe fiecare rând).
IndicaŃii: A insera câte o valoare între oricare două elemente, înseamnă a face
o inserare înaintea fiecărui element începând cu al doilea până la ultimul. Altfel spus,
într-un ciclu, la fiecare pas:
− inserăm valoarea m=(v[i-1]+v[i])/2, înaintea elementului v[i], adică pe
poziŃia i; în acest scop, vom muta cu o poziŃie mai la dreapta toate elementele de la v[i]
inclusiv până la sfârşitul vectorului, adică într-un alt ciclu cu j de la i la n-1, facem
v[j+1]=v[j]. Apoi, aducem valoarea dorită m pe poziŃia i, prin simpla atribuire v[i]=m.
− facem i=i+1, pentru a merge la următorul element al vectorului iniŃial, adică
pentru a trece peste valoarea tocmai adăugată în vector.
► 32. (Bacalaureat iulie 2005, enunŃ modificat)
Fişierul text BAC.TXT conŃine pe prima sa linie un şir de maxim 1000 de
caractere, care pot fi litere cifre şi spaŃii. RealizaŃi programul Pascal care afişează
pe ecran câte caractere cifră există între al p-ulea şi al q-ulea caracter din fişier
(unde valorile poziŃiilor p şi q se citesc de la tastatură).
Exemplu: dacă p=2, q=8, iar fişierul BAC.TXT conŃine succesiunea de
caractere mx12a3pb55...5, unde cifra 5 se repetă de 961 ori, atunci programul va
afişa valoarea 3, deoarece între poziŃiile 2 şi 8 din fişier se găsesc trei caractere cifră.
► 33. (Bacalaureat iulie 2009, varianta 31)
Se citeşte de pe prima linie a fişierului text NUMERE.IN un număr natural
n (0<n<10000) iar de pe a doua linie a fişierului n numere naturale din
intervalul [1,100] şi se cere să se afişeze pe ecran, despărŃite prin câte un spaŃiu,
numărul sau numerele întregi din intervalul [1,100] care nu apar printre
numerele citite. Dacă pe a doua linie a fişierului apar toate numerele din intervalul
precizat, se va afişa mesajul NU LIPSESTE NICIUN NUMAR. AlegeŃi un algoritm
de rezolvare eficient din punctul de vedere al timpului de executare.
Exemplu: pentru fişierul NUMERE.IN cu următorul conŃinut:
12
4 2 3 1 6 5 7 8 9 11 10 100

se vor afişa valorile 12 13 … 99.


436
a) ExplicaŃi în limbaj natural metoda utilizată justificând eficienŃa acesteia
(4-6 rânduri)
b) ScrieŃi programul ce rezolvă problema enunŃată, corespunzător metodei
descrise la punctul a).
IndicaŃii: O metodă eficientă constă în folosirea unui vector v, cu poziŃii de la 1
la 100, în care fiecare element v[i] va memora numărul de apariŃii ale valorii i în
fişier. Mai întâi iniŃializăm tot vectorul v cu 0, apoi, pentru completarea vectorului, citim
succesiv într-un ciclu cele n numere din fişier, în aceeaşi variabilă x; pentru fiecare x
citit, incrementăm cu 1 elementul v[x] care ne indică numărul de apariŃii ale lui x în
fişier (am mai consemnat o apariŃie în plus faŃă de câte erau în acel moment. În final,
programul va trebui să parcurgă vectorul, şi pentru fiecare element v[i] egal cu 0 (cu
i=1,2,...,100), să afişeze poziŃia i.

► 34. Se dau două fişiere text. Primul dintre acestea, numit LITERE.TXT,
conŃine o mulŃime de litere mari distincte ale alfabetului englez, scrise pe un
singur rând, despărŃite prin câte un spaŃiu. Al doilea fişier, numit FRAZA.TXT
conŃine mai multe rânduri de text, scris numai cu litere mari, rânduri de lungimi
diferite. Nu se cunoaşte nici numărul caracterelor din primul fişier, nici numărul
rândurilor din cel de-al doilea. RealizaŃi un program care stabileşte câte din literele
existente în fişierul LITERE.TXT apar în fişierul FRAZA.TXT de cel puŃin p ori
(unde valoarea lui p se citeşte de la tastatură).
Exemplu: pentru p=4 şi fişierele:
FRAZA.TXT LITERE.TXT
MIE IMI PLACE MULT M I U S
INFORMATICA

programul va afişa valoarea 2, întrucât două dintre literele aflate în fişierul


LITERE.TXT, în speŃă ’M’ şi ’I’, apar în fişierul FRAZA.TXT de cel puŃin patru
ori.
► 35. (Bacalaureat iulie 2000, varianta 7)
Fişierul BAC2000.TXT este format din două linii. Prima linie este formată
dintr-un şir de cel puŃin una şi cel mult 100 de litere mari nedespărŃite prin spaŃii,
pe linia a doua aflându-se cel puŃin unul şi cel mult 100 de numere despărŃite prin
spaŃii. Numerele de pe a doua linie sunt valori întregi din intervalul
[-1000,1000]. ConŃinutul fişierului respectă întocmai precizările anterioare,
nefiind necesare validări.
ScrieŃi un program care să decidă dacă în fişier există tot atâtea litere pe
prima linie câte numere se găsesc pe a doua linie. Se va afişa pe ecran mesajul
"Da", dacă sunt tot atâtea litere pe prima linie câte numere sunt pe a doua linie, sau
mesajul "Nu" în caz contrar.
► 36. (Bacalaureat iulie 2006)
ScrieŃi un program care citeşte din fişierul BAC.TXT un şir S de maxim
100000 de numere naturale alcătuite din exact două cifre fiecare, şi afişează
437
distanŃa maximă care există între două elemente egale ale şirului. Definim distanŃa
dintre două elemente Si şi Sj, ca fiind modulul diferenŃei indicilor celor două
elemente, adică expresia |i-j|. Dacă şirul conŃine numai elemente distincte,
distanŃa cerută este 0. Se cere o metodă eficientă de rezolvare.
Exemplu: dacă pe prima linie a fişierului se află şirul
14 12 10 10 14 15 10 12 90
atunci se afişează valoarea 6, deoarece distanŃa maximă dintre două
elemente egale este 6 (s2=s8 şi 8-2=6).
► 37. (Bacalaureat iulie 2009, varianta 91)
Fişierul NUMERE.IN conŃine cel mult 5000 de numere reale, câte unul pe
fiecare linie. Se cere să se scrie un program care să citescă toate numerele din
fişier şi să afişeze pe ecran numărul de ordine al primei, respectiv al ultimei linii
pe care se află cel mai mare număr din fişier. Cele două valori vor fi
3.5
separate printr-un spaŃiu. AlegeŃi o metodă de rezolvare eficientă din 7
punct de vedere al spaŃiului de memorare şi al timpului de executare. -4
Exemplu: dacă fişierul are conŃinutul alăturat, pe ecran se vor 7
afişa numerele 2 6. 2
a) DescrieŃi succint, în limbaj natural, metoda de rezolvare aleasă, 7
explicând în ce constă eficienŃa ei. 6.3
b) ScrieŃi programul corespunzător metodei descrise. 5

► 38. (Bacalaureat iulie 2009, varianta 10)


a) ScrieŃi un program care citeşte de la tastatură un număr natural n
(0<n≤1000000) şi apoi n numere naturale nenule (cu cel mult şapte cifre
fiecare) ordonate crescător şi, utilizând un algoritm eficient din punct de vedere al
memoriei utilizate şi al timpului de executare, determină pentru fiecare număr citit
cea mai mare valoare mai mică sau egală cu acesta ce reprezintă o putere a lui 3.
Un număr natural y este putere a lui 3 dacă există un număr natural k astfel încât
y=3k. Numerele astfel determinate vor fi scrise în fişierul BAC.TXT, separate prin
câte un spaŃiu.
Exemplu: dacă n=5 şi cele 5 numere citite au valorile 4 5 9 12 28
fişierul BAC.TXT va avea conŃinutul: 3 3 9 9 27
b) DescrieŃi succint, în limbaj natural, algoritmul pe baza căruia a fost
scris programul de la punctul a), explicând în ce constă eficienŃa metodei folosite.
IndicaŃii: citim separat primul număr din fişier într-o variabilă x şi iniŃializăm
cu 2 o variabilă t. Apoi, în mod repetat, înmulŃim pe t cu 3 prin atribuirea t:=3*t,
până când t>x. Valoarea la care a ajuns t după acest ciclu este puterea căutată pentru
primul nunmăr din fişier. În continuare, pentru al doilea număr x, puterea cerută va fi
cu siguranŃă mai mare decât cea întâlnită la primul număr ! În consecinŃă, vom citi
succesiv celelalte n elemente ale şirului din fişier în aceeaşi variabilă x, şi, pentru
fiecare x citit, reluăm algoritmul înmulŃirilor cu 3, dar cu un amendament: la fiecare
nou x, variabila t nu va mai pleca de la 3, ci de la valoarea cu care a rămas la finele
căuării pentru x-ul anterior.

438
► 39. (Bacalaureat iulie 2009, varianta 87)
Fişierul text BAC.TXT conŃine un şir de cel mult 2008 numere naturale
nenule, cu cel mult 4 cifre fiecare, pe mai multe rânduri, numerele de pe acelaşi
rând fiind separate prin câte un spaŃiu.
a) ScrieŃi un program care citeşte de la tastatură un număr natural k şi
afişează pe ecran cel mai mare număr din fişierul BAC.TXT care este mai mic sau
egal cu numărul natural k, precum şi numărul de apariŃii ale acestuia în fişier,
folosind o metodă eficientă din punctul de vedere al timpului de executare. Cele
două valori vor fi afişate pe o linie a ecranului, separate printr-un spaŃiu. Dacă în
fişier nu există nici un număr mai mic sau egal cu k, se va afişa doar valoarea 0.
Exemplu: dacă în fişier avem numerele 31 2 63 71 8 63 5 281 şi
numărul citit este k=70, atunci pe ecran se vor afişa numerele: 63 2.
b) DescrieŃi succint, în limbaj natural, algoritmul utilizat, justificând
eficienŃa acestuia.
► 40. Se dă un fişier text care conŃine mai multe şiruri de numere întregi,
fiecare şir fiind scris pe câte o linie a fişierului (cu elementele separate prin spaŃii).
Nu se cunoaşte nici numărul şirurilor şi nici câte elemente conŃine fiecare şir.
AfişaŃi pe ecran numerele de ordine ale liniilor din fişier care conŃin şiruri
ordonate crescător.
Exemplu: pentru fişierul din figură se vor afişa valorile 1, 4 şi 5 deoarece
primul, al patrulea şi al cincilea rând din fişier conŃin şiruri ordonate crescător.
sir1.txt
1 3 5 7
8 7 5
12 14 15 10
33 66
0 1 2

Probleme de nota 10
► 41. (Bacalaureat iulie 2009, varianta 90)
Fişierul text BAC.TXT conŃine pe mai multe rânduri cel mult 50000 de
numere naturale, numerele aflate pe acelaşi rând fiind separate prin câte un spaŃiu.
Fiecare număr are cel mult patru cifre.
a) ScrieŃi un program care, utilizând un algoritm eficient din punct de
vedere al timpului de executare şi al spaŃiului de memorie folosit, determină
numărul din fişier care are cei mai mulŃi divizori. În cazul în care există mai multe
valori în fişier care au număr maxim de divizori, programul va afişa cea mai mică
dintre acestea.
Exemplu: dacă fişierul conŃine valorile 23 12 100 36 atunci se va afişa 36,
pentru că atât 100 cât şi 36 au număr maxim de divizori, dar 36 este cel mai mic.
b) DescrieŃi succint, în limbaj natural, algoritmul utilizat, justificând
eficienŃa acestuia.
439
► 42. Fişierul NR1.TXT conŃine:
− pe primul rând k numere naturale, n1, n2,...,nk, separate prin spaŃii;
− pe fiecare din următoarele k rânduri câte un şir de numere întregi
separate prin spaŃii: şirul de pe al doilea rând are n1 elemente, cel de pe al treilea
rând n2 elemente, etc., şirul de pe utlimul rând având nk elemente.
RealizaŃi un program care construieşte fişierul NR2.TXT care va conŃine
elementele maxime ale şirurilor aflate în fişierul NR1.TXT începând cu al doilea
rând. Aceste maxime se vor scrie în fişierul de ieşire toate pe un singur rând
separate printr-un spaŃiu.
Exemplu:
NR1.TXT NR2.TXT
3 6 5 8 11 8 4 12
2 11 -6
4 -2 8 -9 -5 0
0 1 2 3 4
12 3 9 -6 4 11 -8 1

► 43. (Bacalaureat iulie 2008, varianta 76)


Pe prima linie a fişierului BAC.TXT se găsesc numere naturale separate
prin câte un spaŃiu. Ele alcătuiesc mai multe şiruri crescătoare, sfârşitul fiecărui şir
fiind marcat de valoarea -1 (care nu face parte din şir). Ştiind că valorile prezente
în fişier nu depăşesc 10000, iar în total sunt cel mult 2000 de numere, scrieŃi un
program care să afişeze numerele comune tuturor şirurilor, în ordinea crescătoare a
valorilor lor.
Exemplu: dacă fişierul conŃine numerele:
2 3 3 4 5 8 9 -1 2 4 5 8 11 -1 2 3 5 8 12 -1
atunci pe ecran se vor afişa valorile 2, 5 şi 8.
IndicaŃii: O metodă eficientă se bazează pe faptul că intersecŃia este asociativă
şi pe particularitatea că elementele şirurilor sunt în ordine crescătoare. Se citesc primele
două şiruri şi se determină intersecŃia lor, apoi se citeşte al treilea şir şi se intersectează
cu rezultatul anterior, ş.a.m.d., până la epuizarea tuturor şirurilor. În calculul
interseŃiei, graŃie faptului că şirurile sunt ordonate, se poate folosi un algoritm bazat pe
interclasarea a doi vectori, având grijă ca înm şirul ce reprezintă intersecŃia să
memorăm doar valorile comune care nu au mai fost memorate deja la un pas anterior.
► 44 (Bacalaureat iulie 2009, varianta 68)
Fişierul text SIR.TXT conŃine pe prima linie un număr natural n
(1≤n≤10000) şi pe a doua linie, separate prin spaŃii, un şir crescător de n
numere naturale cu cel mult nouă cifre fiecare.
Numim platou într-un şir de valori o secvenŃă de elemente identice situate
pe poziŃii alăturate. Lungimea unui platou este egală cu numărul de elemente care
îl formează.
a) ScrieŃi un program care citeşte valorile din fişier şi, printr-o metodă
eficientă din punct de vedere al timpului de executare şi al spaŃiului de memorie
440
utilizat, afişează pe ecran, separate printr-un spaŃiu, lungimea maximă a unui
platou, precum şi valoarea care formează platoul. În cazul în care sunt mai multe
platouri de aceeaşi lungime se va afişa valoarea cea mai mare care formează unul
dintre aceste platouri.
Exemplu: dacă fişierul SIR.TXT are conŃinutul de mai jos,
10
111 2111 2111 2111 3111 4111 4111 51111 51111 51111

atunci programul va afişa pe ecran: 3 51111.


b) DescrieŃi succint, în limbaj natural, metoda utilizată la punctul a),
justificând eficienŃa acesteia.
► 45. (Bacalaureat iulie 2004)
Se citesc din fişierul BAC.TXT mai multe şiruri de numere naturale nenule,
sfârşitul fiecărui şir fiind marcat de o valoare 0 (care nu se consideră că face parte
din vreun şir). Ştiind că fiecare dintre şiruri este un şir strict crecător şi că în total
sunt cel mult 5000 de numere, scrieŃi un program care să realizeze afişarea tutror
numerelor nenule distincte din fişier în ordinea crescătoare a valorilor lor.
Exemplu: dacă fişierul conŃine: 4 9 12 30 0 5 7 10 12 14 20 0 4
9 10 0 atunci şirul afişat este: 4 5 7 9 10 12 14 20 30.

► 46. Se dă fişierul text NR.TXT care conŃine mai multe rânduri de


numere întregi, numerele de pe fiecare rând fiind separate prin spaŃii. ConstruiŃi
fişierul NR2.TXT care să conŃină numerele din fişierul de intrare în aceeaşi ordine,
dar grupate în linii de câte patru numere fiecare separate prin spaŃii (cu excepŃia
ultimului rând care poate să conŃină mai puŃin de patru numere).
Exemplu: NR.TXT NR2.TXT
3 11 8 25 1 159 3 11 8 25
17 10 1280 4 63 1 159 17 10
350 22 34 1280 4 63 350
22 34

IndicaŃii: Ideea de citire a mai multor rânduri de numere şi regrupare a lor pe


rânduri după un anumit criteriu, a fost întâlnită în problema rezolvată R.VI.8 din
secŃiunea “Aprofundare” a prezentului capitol, doar că, în loc să construim rânduri de
lungime cel mult p caractere, trebuie contorizate câte patru numere pe un rând. Pentru
aceasta vom folosi un contor: după fiecare citire a unui număr din fişier, dacă valoarea
contorului nu a ajuns la 4 el se incrementează, iar în caz contrar se “resetează”
marcând astfel inaugurarea unui nou rând.
► 47. (Bacalaureat iulie 2009, varianta 42)
Fişierul NUMERE.IN conŃine pe prima linie un număr natural n cuprins
între 0 şi 100000, iar pe a doua linie un şir de n numere reale, separate prin câte
un spaŃiu. Fiecare număr de pe al doilea rând este format din cel mult zece cifre,
incluzând partea zecimală. ScrieŃi un program care determină cifrele ce nu apar în
scrierea niciunuia dintre numerele din fişier. Respectivele cifre se vor afişa pe
ecran, în ordine crescătoare, toate pe un rând, separate prin câte un spaŃiu. În cazul
441
în care numerele existente în fişier utilizează toate cifrele bazei de numeraŃie 10
(0,1,...,9), pe ecran se va tipări mesajul "NU EXISTA".
Exemplu: dacă fişierul are conŃintul din figură, atunci pe ecran se vor afişa
valorile 4 şi 9.
5
-1.23 36 22.57 208 735.1

► 48. (Bacalaureat iulie 2009, varianta 44)


Fişierul text NUMERE.TXT conŃine pe prima linie un număr natural n
(0<n<100000), iar pe a doua linie, separate prin câte un spaŃiu, n numere
naturale formate din cel mult două cifre.
a) ScrieŃi un program care determină în mod eficient, din punct de vedere
al timpului de executare, toate numerele conŃinute de a doua linie a fişierului care
apar de cel puŃin două ori în acestă linie. Programul va afişa pe ecran numerele
determinate, o singură dată, în ordine crescatoare, pe aceeaşi linie, separate prin
câte un spaŃiu.
Exemplu: dacă fişierul NUMERE.TXT are conŃinutul din figură:
8
44 2 54 74 2 44 9 2
atunci pe ecran se va afişa: 2 44
b) DescrieŃi succint, în limbaj natural, metoda de rezolvare folosită,
explicând în ce constă eficienŃa ei (3 – 4 rânduri).
► 49. (Bacalaureat iulie 2009, varianta 21)
Fişierul text BAC.TXT conŃine pe prima linie două numere naturale, n şi
k, separate de un spaŃiu (3≤n≤10000, 2≤k≤n/2), iar pe a doua linie un şir de n
numere naturale, x1, x2, ..., xn, separate prin câte un spaŃiu, fiecare număr din acest
şir având cel mult patru cifre.
a) ScrieŃi un program care citeşte numerele din fişier şi determină,
utilizând o metodă eficientă din punct de vedere al timpului de executare, cel mai
mic indice i (1≤i≤n-k+1) pentru care suma termenilor xi, xi+1, ..., xi+k-1 este
maximă. Programul afişează valoarea lui i pe ecran.
Exemplu: pentru fişirul alăturat se afişează 2, deoarece suma maximă se
obŃine pentru 9+4+7.
7 3
2 9 4 7 5 2 9
b) ExplicaŃi succint, în limbaj natural, metoda utilizată la punctul a),
justificând eficienŃa acesteia.
► 50. (Bacalaureat iulie 2009, varianta 92)
ScrieŃi un program care citeşte din fişiere DATE.IN două numere naturale,
n şi m (1≤n≤100 şi m≤ ≤ n ), precum şi un şir de n numere reale distincte (aflate
toate pe un rând şi separate între ele prin câte un spaŃiu), apoi scrie în fişierul
442
DATE.OUT pe prima linie a ecranului cele mai mari m elemente din şirul citit (în
ordine crescătoare a valorilor lor), iar pe a doua linie cele mai mici m elemente din
şir (în ordine descrescătoare a valorilor lor). Numerele afişate pe aceeaşi linie vor
fi separate prin câte un spaŃiu.
Exemplu: dacă n=9, m=3, iar şirul este (14.2, 60, -7.5, -22, 33.8, 80,
4, 10, 3) se va afişa pe ecran:
33.8 60 80
3 -7.5 -22
IndicaŃii: O soluŃie pe cât de greoaie pe atât de ineficientă, ar presupune să
găsim pe rând cele m valori cerute astfel: determinăm mai întâi minimul din tot şirul,
apoi minimul din şirul care ar rămâne dacă am elimina minimul anterior, ş.a.m.d.,
procedeul repetându-se până când am localizat m astfel de minime. Rezolvarea eficientă
este banală, dar se bazează pe o observaŃie de fineŃe: dacă sortăm şirul crescător, atunci
cele mai mici m elemente vor fi primele m elemente, iar cele mai mari m elemente vor fi
ultimele m valori din şir !

► 51. Fişierul NUMERE.TXT are următorul conŃinut: pe primul rând se


găseşte un întreg p, iar următoarele rânduri conŃin numere întregi separate între ele
prin spaŃii (nu se ştie câte rânduri conŃine fişierul) şi nici câte valori se găsesc pe
un rând. Să se creeze un nou fişier text cu numere de pe cele n rânduri ale
fişierului de intrare, scrise în aceeaşi ordine, separate între ele printr-un singur
spaŃiu, astfel încât pe un rând să fie cel mult p caractere (cifre sau spaŃii). Pe
fiecare rând se vor scrie cât mai multe numere posibil (valorile lui n şi p nu se vor
copia şi ele în al doilea fişier).
Exemplu: Pentru fişierul de intrare: se obŃine fişierul:
12 56 234
10
1 346 23
12 56 234 1 346 23 35 647 23
35 647 23 6 87 3 98 45 32 6 87 3 98
2 45 45 32 2 45
425 7 34 68 568 3465 425 7 34
68 568
3465

► 52. (Bacalaureat iulie 2009, varianta 67)


Fişierul text NUMERE.TXT conŃine pe prima linie un număr natural n
(1≤n≤10000) şi pe a doua linie un şir crescător de n numere naturale, fiecare
având cel mult 9 cifre. Numerele de pe a doua linie sunt separate prin câte un
spaŃiu.
a) ScrieŃi un program care, utilizând o metodă eficientă din punct de
vedere al timpului de executare şi al spaŃiului de memorie, afişează pe ecran
elementele distincte ale şirului aflat pe a doua linie a fişierului.
Exemplu: dacă fişierul NUMERE.TXT are conŃinutul din figură,
7
111 111 111 2111 4111 71111 71111

atunci programul va afişa pe ecran 111 2111 4111 71111.


443
b) DescrieŃi succint, în limbaj natural, metoda utilizată la punctul a),
justificând eficienŃa acesteia.

►53. (Bacalaureat iulie 2009, varianta 66)


Fişierele text A.TXT şi B.TXT conŃin cel mult 10000 de numere
naturale cu cel mult 9 cifre fiecare, scrise fiecare pe câte o linie.
a) ScrieŃi un program care citeşte numerele din cele două fişiere şi, printr-
o metodă eficientă din punct de vedere al timpului de executare şi al spaŃiului de
memorie utilizat, afişează pe ecran câte dintre numerele din fişierul A.TXT sunt
strict mai mici decât toate numerele memorate în fişierul B.TXT.
Exemplu: dacă fişierele A.TXT şi B.TXT au conŃinuturile din imagine
41111 91111
81111 91111
11111 61111
91111 91111
51111 91111
111111 81111
31111 61111
431111 91111
61111
201111 B.TXT

A.TXT
atunci programul va afişa valoarea 4, deoarece 41111, 11111, 51111,
31111 sunt mai mici decât toate elementele din fişierul B.TXT.
b) DescrieŃi succint, în limbaj natural, metoda utilizată la punctul a),
justificând eficienŃa acesteia.
► 54. (Bacalaureat iulie 2000, varianta 3)
Pe prima linie a fişierului text BAC2000.TXT se găseşte o succesiune de
cel puŃin două şi cel mult 2000 de caractere, caractere ce pot fi doar litere mari şi
spaŃii. ScrieŃi un program Pascal care citeşte de la tastatură un număr natural k
(0<k<1000) şi stabileşte dacă există în fişier vreo literă care apare de exact k ori.
Programul care afişează pe ecran mesajul "Da" în cazul în care există cel puŃin o
literă cu proprietatea menŃionată şi mesajul "Nu", în caz contrar.
Exemplu: dacă fişierul BAC2000.TXT are următorul conŃinut
EXAMEN DE BACALAUREAT LA INFORMATICA
iar de la tastatură se citeşte numărul 8, atunci, deoarece litera A apare de
exact 8 ori, se va afişa pe ecran mesajul "Da".
► 55. (Bacalaureat iulie 2009, varianta 48)
Fişierul text BAC.IN conŃine pe prima linie un număr natural n
(0<n<5000), iar pe a doua linie, separate prin câte un spaŃiu, n numere naturale,
formate din cel mult patru cifre fiecare. ScrieŃi un program care determină şi scrie
în fişierul BAC.OUT toate numerele conŃinute de a doua linie a fişierului care apar

444
o singură dată în această linie. Numerele determinate se vor afişa în ordinea
crescătoare a valorilor lor, separate prin câte un spaŃiu.
Exemplu: dacă pe prima linie a fişierului BAC.IN se află 10, iar pe linia a
doua se găsesc numerele 2 4548 568 4548 57 89 5974 2 89 32 atunci
valorile căutate sunt 32 57 568 5974.
► 56. (Bacalaureat iulie 2009, varianta 33)
În fişierul NUMERE.TXT se află memorate pe prima linie două numere
naturale n şi m (având cel mult patru cifre fiecare, cu m≤n ), iar pe următoarea
linie, în ordine strict crescătoare, n numere naturale.
a) ScrieŃi în limbajul un algoritm eficient din punct de vedere al gestionării
memoriei şi timpului de executare, care citeşte din fişier datele existente şi
afişează cea mai mare sumă a m numere aflate pe a doua linie a fişierului.
b) ExplicaŃi în limbaj natural metoda utilizată, justificând eficienŃa acesteia.
► 57. (Bacalaureat iulie 2009, varianta 64)
Fişierul text DATE.IN conŃine pe prima linie, separate prin câte un spaŃiu,
cel mult 1000 de numere naturale, fiecare dintre ele având maximum 9 cifre.
a) ScrieŃi un program care citeşte numerele din fişierul DATE.IN,
determină şi afişează pe ecran numărul de elemente ale celei mai lungi secvenŃe
ordonate strict descrescător, formate din valori citite consecutiv din fişier. AlegeŃi
o metodă de rezolvare eficientă din punctul de vedere al timpului de executare.
Exemplu: dacă fişierul DATE.IN conŃine: 5 2 9 4 3 6 3 2 1 0 8
pe ecran se afişează valoarea 5, reprezentând lungimea secvenŃei (6 3 2 1 0)
b) DescrieŃi succint, în limbaj natural, metoda de rezolvare folosită,
explicând în ce constă eficienŃa ei (3-4 rânduri).
► 58. (Bacalaureat iulie 2008, varianta 93)
Se citeşte de la tastatură un număr natural n de cel mult 8 cifre. Să se
creeze fişierul text NR.TXT care să conŃină, câte unul pe linie, în orice ordine, toate
numerele naturale distincte care se pot obŃine din valoarea lui n prin eliminarea
uneia sau mai multor cifre de la unul din capetele sale.
Exemplu: pentru n=38604, fişierul NR.TXT va conŃine, câte unul pe linie
şi nu neapărat în această ordine: 8604 604 4 3860 386 38 3
► 59. Se dă fişierul text FR.IN care conŃine pe fiecare linie câte două
numere naturale mai mici decât 35000, reprezentând numărătorul respectiv
numitorul unei fracŃii simple.
a) Să se creeze fişierul FR.OUT care va conŃine pe fiecare rând numărătorii şi
numitorii fracŃiilor ireductibile rezultate prin simplificarea fracŃiilor din fişierul 'fr.in'.
b) Pe ultima linie a fişierului FR.OUT să se scrie numărătorul şi numitorul
fracŃiei rezultate prin adunarea fracŃiilor din fişierul FR.IN. FracŃia sumă se va da
în formă ireductibilă.
Exemplu: 1 3
2 6
pentru 'fr.in' 12 18 fişierul 'fr.out' va conŃine: 2 3
5 2
50 20
7 2
445
►60. Un institut de cercetări militare, care efectuează studii ultrasecrete în
domeniul armelor bilogice, a descoperit existenŃa unei scurgeri de informaŃii către
exterior. Pentru a pune capăt acestei situaŃii, conducerea institutului a decis
introducerea unui nou algoritm de codificare a cartelelor magnetice care permit
accesul în încăperile institutului. Codul PIN al fiecărei cartele va fi generat
pornind de la un fişier PIN.TXT alcătuit din m rânduri de numere naturale, fiecare
rând conŃinând n numere separate prin spaŃii. Pentru construirea acestui cod
trebuie procedat astfel:
− se citesc succesiv numerele din fişier, de pe fiecare rând de la stânga la
dreapta iar rândurile de sus în jos, rezultând astfel un şir de m*n numere naturale;
− se împarte şirul în subşiruri de câte p elemente consecutive;
− pentru fiecare astfel de subşir, se încearcă formarea unui număr natural,
luând câte o cifră din fiecare element al subşirului, astfel încât numărul rezultat să
aibă aspect de deal, adică să aibă cifrele în ordine strict crescătoare; dacă există un
astfel de număr, el va constitui un aşa numit cod intermediar; în cazul în care sunt
posibile mai multe soluŃii, se va reŃine ca şi co intermediar primul număr construit.
− dintre codurile intermediare rezultate prin "cercetarea" tutror subşirurilor
de câte p elemente, se va alege acela care este maxim; el va reprezenta codul PIN
al unei cartele.
Din motive de securitate, fiecare angajat primeşte propriul fişier de m*n
numere PIN.TXT şi trebuie să-şi găseascp singur codul PIN al cartelei care îi va
permite să pătrundă în incinta institutului. RealizaŃi programul care implementează
algoritmul de formare a unui cod PIN.
Exemplu:
Fie fişierul PIN.TXT cu conŃinutul de mai jos, în care m=3 (numărul
liniilor) şi n=4 (numărul elementelor de pe fiecare rând). Fie de asemenea p=3.

235 128 476 593


67 93 365 499
123 1569 435 228

− Citind succesiv numerele din fişier, pe fiecare linie de la stânga la


dreapta iar liniile de sus în jos, obŃinem şirul
(235,128,476,593,67,93,365,499,123,1569,435,228 ).
− ÎmpărŃind şirul în subşiruri de câte p=3 elemente succesive, obŃinem
următoarele subşiruri: (235,128,476), (593,67,93), (365,499,123),
(1569,435,228);
− Pentru subşirul (235,128,476) nu se poate construi nici un număr cu
aspect de deal luând câte o cifră din fiecare element al subşirului (numărul 224,
alcătuit din cifra 2 din primul element, cifra 2 din al doilea element şi cifra 4 din al
treilea element nu este soluŃie, deoarece cifrele extrase trebuie să fie în ordine
strict crescătoare);
446
− Pentru subşirul (593,67,93), soluŃiile posibile sunt: 569, 579, 369,
379; dintre acestea se va reŃine prima, 569, număr care constituie un cod
intermediar;
− Analog, subşirul (365,499,123) nu furnizează nici o soluŃie, iar din
subşirul (1569,435,228) se pot alcătui mai multe soluŃii, din care reŃinem
numărul 138;
− Dintre codurile intermediare construite, 569 şi 138, alegem maximul,
adică 569, acesta reprezentând codul PIN al cartelei.

447
448
449
450

S-ar putea să vă placă și