$$ \newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} \newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} \newcommand{\mod}{\,\mathrm{mod}\,} \renewcommand{\div}{\,\mathrm{div}\,} \newcommand{\metar}{\,\mathrm{m}} \newcommand{\cm}{\,\mathrm{cm}} \newcommand{\dm}{\,\mathrm{dm}} \newcommand{\litar}{\,\mathrm{l}} \newcommand{\km}{\,\mathrm{km}} \newcommand{\s}{\,\mathrm{s}} \newcommand{\h}{\,\mathrm{h}} \newcommand{\minut}{\,\mathrm{min}} \newcommand{\kmh}{\,\mathrm{\frac{km}{h}}} \newcommand{\ms}{\,\mathrm{\frac{m}{s}}} \newcommand{\mmin}{\,\mathrm{\frac{m}{min}}} \newcommand{\smin}{\,\mathrm{\frac{s}{min}}} $$
Priručnik za početnike (C++) / Automatsko čitanje ulaznih podataka - Saveti i trikovi

Automatsko čitanje ulaznih podataka - Saveti i trikovi

  • Dozvoljeno polaganje
  • Lekcije
  • Nema
  • Vugdelija
  • 7/24/2015

Kada program ne radi onako kako očekuješ, ponekad je potrebno da ga pokreneš nekoliko puta, dok ne otkriješ u čemu je problem. Kada ulaznih podataka nema mnogo, onda ponovno izvršavanje (restartovanje) programa i nije tako strašno. Međutim, ako treba uneti čitav niz brojeva, ovo postaje vrlo zamorno, a podložno je i greškama.

Na sreću, postoji način da ulazne podatke otkucamo samo jednom, proverimo i sačuvamo u posebnom tekstualnom fajlu, a da ih kasnije program pri svakom pokretanju čita automatski.

 

Program i dalje pišemo na isti način, to jest tako da učitava podatke sa tastature, a u radnom okruženju zadajemo da se kao standardni ulazni tok za naš program umesto tastature koristi fajl.

Ovo podešavanje možemo da izvedemo ovako: u pod-prozoru "Solution Explorer" (ako nije već otvoren, može da se otvori iz "View" menija) desni klik mišem na ime projekta i izaberemo "Properties", kao na ovoj slici:


 

Pojaviće se prozor prikazan na sledećoj slici (ili vrlo sličan). U levom delu prozora izaberemo "Debugging", a u desnom delu, pod "Command arguments" upišemo znak"<", i zatim putanju do fajla koji sadrži ulazne podatke.

 

Ovo podešavanje se naziva preusmeravanje standardnog ulaza.

 

 

Kao primer koji pokazuje da je automatsko čitanje ulaznih podataka veoma isplativo, može da posluži skoro bilo koji zadatak.

Mi ovde u tu svrhu navodimo samo jedan zadatak, u kome ćemo usput vežbati i nalaženje grešaka.

 

Savet: Nemoj se nadati da će tvoj program da proradi iz prve, umesto toga pripremi se na provere i ispravljanje. Čak i kada bi program odmah bio ispravan, moraš da ga isprobaš i da se u to uveriš. To znači da ulazne podatke svakako moraš da otkucaš bar jednom. Kad je već tako, otkucaj ih u fajl i obezbedi da ne moraš da ih kucaš drugi put. Čuvanje ulaznih podataka u falju izgleda kao više posla (nego direktno kucanje u prozoru programa), ali ispostavlja se da je u stvari manje.

 

Primer:

Gradski autobus je opremljen GPS uređajem, koji može da pošalje svoje koordinate (X i Y) u metrima, u koordinatnom sistemu grada u kojem autobus saobraća. Radno vreme (jedna smena) vozača traje ukupno n minuta, i tokom tog vremena na početku svakog minuta GPS uređaj šalje svoje koordinate (to jest koordinate autobusa).

Ako se za jedan minut pozicija autobusa i po x i po y koordinati promeni za manje od 10 metara, smatramo da autobus stoji. Ako autobus stoji p ili više minuta, smatramo da je vozač napravio pauzu.

Napisati program koji učitava brojeve n (trajanje vožnje) i p (trajanje najkraće pauze), a zatim i n parova realnih brojeva (x, y), a ispisuje koliko su ukupno trajale sve pauze vozača.

 

Rešenje:

 

Nakon učitavanja trajanja vožnje n, trajanja pauze minPauza, i početnog položaja (položaj na početku vožnje), u naredbi ponavljanja još n-1 puta učitamo novu poziciju (dakle završavamo sa položajem na početku n-tog minuta), i svaki put proverimo da li rastojanje od prethodne pozicije znači da autobus stoji. Ako autobus stoji dovoljno dugo (minPauza minuta ili duže), znači da je to pauza, pa njeno trajanje dodajemo na trajanje svih pauza. Na kraju petlje trenutni položaj zapamtimo u promenljivama za prethodni položaj (u sledećem prolazu to će biti prethodni položaj), a nakon izvršavanja petlje ispisujemo ukupno trajanje svih pauza.

 

Prvi pokušaj programa koji rešava zadatak (nakon uklanjanja sintaksnih grešaka) bi mogao da izgleda ovako:

 

Hajde da testiramo program. Ovaj put, umesto da prosto pokreneš program i uneseš podatke, predlažemo ti da uradiš sledeće:

  • u svom programerskom okruženju (ili bilo kojem editoru teksta) kreiraj fajl sa sledećim sadržajem:

 

 

  • sačuvaj fajl, a zatim preusmeri standardni ulaz na sačuvani fajl, kao što je gore objašnjeno. Imaj na umu da je putanja

"c:\MojiProgrami\ulaz11.txt" data samo kao primer - ako sačuvaš fajl sa podacima u drugom direktorijumu (folderu), ili pod drugim imenom, navedi stvarnu putanju do sačuvanog fajla.

 

Savet:

Nemoj da ti preusmeravanje ulaza bude teško, ako ti ovakav unos (većeg broja) podataka iz fajla postane navika, videćeš da će ti se ona brzo isplatiti.

 

  • Pre pokretanja programa proveri još da je tvoja konfiguracija "debug" (vidi lekciju Postepeno izvršavanje programa).

 

Kada nakon ove pripreme pokreneš program, neće biti potrebno da (ponovo) unosiš podatke. Videćeš da program ispisuje broj 116. Ovo očigledno nije dobar rezultat, jer se autobus ukupno kretao 20 minuta, pa nije moguće da su pauze trajale 116 minuta. Koliki rezultat je trebalo da dobijemo?

 

Iz ulaznih podataka vidimo da je autobus stajao pet minuta na poziciji (300, 100) jer se na toj poziciji prvi put pojavio na početku drugog minuta (što odgovara četvrtom redu ulaza), a poslednji put na početku sedmog minuta (7 - 2 = 5). Sledeće stajanje na poziciji (300, 300) je trajalo šest minuta, a poslednje tri minuta na poziciji (400, 300). Prva dva stajanja treba da se računaju kao pauze (u ovom primeru je zadato da je pauza sve što traje 5 minuta ili duže), a poslednje ne, jer traje samo tri minuta. Dakle, program treba da ispiše da su pauze trajale 11 minuta (5 + 6 = 11).

 

U čemu naš program greši? Da bismo otkrili grešku, potrebno je:

  • da znamo šta bi program trebalo da uradi na svakom pojedinom koraku;
  • da poredimo ono što je program uradio sa onim što smo očekivali, dok ne naiđemo na razliku.

 

Izvršavajmo program korak po korak (F10) i pratimo vrednosti promenljivih. Promenljive koje želimo da pratimo prosto mišem označimo u programu i dovučemo u "watch" prozor. Biće nam potrebno da pratimo poslednjeStajanjesvePauze, xy i brojač petlje i.

 

Vidimo da se naredba u liniji 18

 

Prvi put izvršava pri ovim vrednostima promenljivih:

 

 

Nakon njenog izvršenja

 

 

Promenljiva svePauze je prvi put povećana na 5, kao što smo i želeli:

 

 

Međutim, u sledećem izvršavanju petlje, vrednosti promenljivih su:

 

Što znači da se autobus pomerio (y je sada 200), ali vrednost poslednjeStajanje je i dalje 5, pa se zato i dalje povećava vrednost svePauze. Ovde bi trebalo da je poslednjeStajanje jednako 0, jer se autobus kreće!

Izmenićemo program, tako da kada uslov u naredbi 12 nije ispunjen (autobus više ne stoji), vrednost poslednjeStajanje vraćamo na 0, ali pre nego što tu vrednost izgubimo, treba da vidimo da li je dovoljno velika da se stajanje broji kao pauza. Program sada izgleda ovako:

 

 

Izmenjeni deo je označen na slici. Izvršimo program ispočetka (Shift-F5, F5). Vidimo da je sada rezultat 11.

Da li ovo znači da je program sada ispravan? Ne znači. U stvari, mi nikada ne možemo da budemo potpuno sigurni da je program ispravan. Sve što možemo je da detaljno testiramo program ne više različitih primera, da bismo smanjili mogućnost da nam se potkrade greška. Greške prave svi, pa i najbolji. Jedini efikasan način da se borimo protiv grešaka je što više testiranja.

 

Proverimo na primer, šta bi bilo da poslednja pauza nije trajala prekratko. Izmenimo trajanje najkraće pauze na 3

 

 

i ponovo sačuvajmo ulazne podatke. Sada bi trebalo da dobijemo rezultat 14 (5 + 6 + 3 = 14). Međutim, ako izvršimo program, vidimo da je rezultat i dalje 11. Zašto?

 

Ako ispratimo izvršavanje programa do kraja, vidimo da se u else granu (linije 18-22, koje su naknadno dodate) poslednji put ulazi za i=16, kada dodajemo pauzu od 6 minuta. Treća pauza se izbroji u promenljivoj poslednjeStajanje, ali se ne dodaje na svePauze. Tako su vrednosti promenljivih na kraju izvršavanja ove:

 

 

Proveru da li je poslednje stajanje dovoljno dugo da se broji kao pauza možemo da vršimo tek kad se to stajanje završi (inače bismo za stajanje od 6 minuta dodali 3+4+5+6 minuta). To znači da kada poslednje stajanje traje do kraja petlje, za njega proveru moramo da izvršimo nakon petlje. Evo još jedne izmene programa:

 

 

(ponovo je novi deo označen). Kada ovaj program pokrenemo, dobijamo očekivani rezultat, to jest 14.

Testiraj program i sa drugim podacima i proveravaj da li se dobija ispravan rezultat. Trudi se da se testovi po nečemu razlikuju, na primer tako da:

  • postoji prekratko stajanje (nedovoljno za pauzu), koje nije ni na početku ni na kraju skupa podataka;
  • podaci počinju stajanjem autobusa;

Itd.

 

Savet: Uvek detaljno testiraj svoj program. Shvati to kao sastavni deo programiranja, i to veoma važan deo. Uz vežbu, pravićeš sve manje grešaka, ali ćeš pisati i veće i komplikovanije programe, tako da će neke greške uvek moći da se potkradu. Kompanije koje prave programe, takođe stalno i intenzivno testiraju svoje programe, jer u velikim programima je praktično nemoguće pronaći greške na drugačiji način.

 

Savet: kada imaš vremena (nije kontrolni ili takmičenje iz programiranja), dobro je da o testovima dobro razmisliš i da ih napišeš i pre nego što počneš da pišeš program. To će ti pomoći da prva verzija programa bude bolja nego što bi inače bila.

 

Možda ćeš u ovom ili nekom drugom programu naći grešku koju mi nismo našli. Ako se to dogodi, molimo te da nam javiš.

Hvala unapred!