[so] Demo curs 2 inchidere stdin

Darius Mihai dariusmihaim at gmail.com
Sun Mar 3 13:25:11 EET 2019


On Sun, Mar 3, 2019 at 1:19 PM Adrian Șendroiu via so
<so at cursuri.cs.pub.ro> wrote:
>
> On Sun, 3 Mar 2019 at 13:05, Andra Danciu via so <so at cursuri.cs.pub.ro> wrote:
> >
> > Hello!
> >
> > La cursul 2, la unul dintre demo-uri, Razvan Deaconescu a dat close pe stdin, a deschis un fisier si a citit un string cu scanf, presupunand ca scanf-ul va citi din fisier. La curs acest demo nu a mers, nu imi explic de ce. La mine a functionat. Am dat insa de un comportament ciudat.
> >
> > Acestui cod i-am dat ca argumente 3 fisiere random cu text in ele:
> > https://pastebin.com/xhy4gt6d
> >
> > La stdout se afiseaza primele 3 cuvinte din primul fisier, in loc sa afiseze primul cuvant din fiecare fisier. Fisierele sunt, cumva, serializate desi le inchid inainte sa citesc tot continutul (nu imi va citi nimic din fisierul 2 pana nu ajunge la finalul primului fisier). Care e explicatia?
>
> Salut,
>
> Explicația este că funcțiile din stdio fac buffering. Primul scanf
> citește cu read într-un buffer mai mare, iar următoarele vor întoarce
> date direct din buffer, fără să mai citească din fișier. scanf n-are
> de unde să știe că între timp ai închis și redeschis file descriptorul
> asociat lui stdin.

Bună, Andra,

Așa cum a spus și Adrian, problema este combinarea funcțiilor de
sistem (open) cu funcții de bibliotecă (scanf). Cu toate că
într-adevăr stdio folosește implicit file descriptor-ul 0 pentru a
citi, iar close + open îl vor suprascrie, primul scanf va umple
buffer-ul implicit al stdin cu date din primul fișier. Tu chiar dacă
faci close pe stdin, funcțiile open și close sunt transmise direct
sistemului de operare, iar funcțiile de bibliotecă nu vor goli
buffer-ul.

Abordarea coretă este:
  - folosești freopen pentru a redeschide stdin pentru a citi din alt fișier
  - folosești read pentru a citi datele din fișiere

Dacă vrei să folosești neapărat close + open + scanf, trebuie să
declari buffer-ul stdin ca NULL folosind setbuf(stdin, NULL);

Darius


More information about the so mailing list