přejít na obsah přejít na navigaci

Linux E X P R E S, Programovanie v jazyku C++: Cyklus while (1)

Programovanie v jazyku C++: Cyklus while (1)

cplusplus.png

V tomto článku sa zameriame na cyklus while. Popritom si ukážeme, ako vytvoriť nekonečný cyklus.


Cyklus while

Cyklus while má rovnakú úlohu ako cyklus for. Cyklus for už ako tak poznáte. Narozdiel od cyklu for má ale iný zápis. Ukážme si najprv základnú deklaráciu cyklu while.

Základná deklarácia:

while(podmienka)
telo

Najprv, než prebehne cyklus, otestuje sa podmienka. Ak test podmienky vráti true, tak sa cyklus vykoná. Ak vráti false, tak sa nevykoná. Ešte poznámka, ak sa skončí vykonanie tela cyklu, tak opäť sa testuje podmienka cyklu. Ukážeme si názorný príklad.

1. príklad: Vyskúšanie si cyklus while

#include <iostream>
 using namespace std;

 int main()
 {
     string name;

     cout << "Napis svoje obcianske meno!\n";
     cin >> name;

     if (name.empty())
     {
         cout << "Ale daco musis napisat no, nestvi ma!";
         return 0;
     }

     size_t i = 0;
     while (i < name.size())
     {
         cout << name[i] << ": " << static_cast<int>(name[i]) << "\n";
    // tu pretypujeme a vypíšeme na obrazovku
         i++;
     }

     return 0;
 }

Priebeh programu:

Napis svoje obcianske meno!
 Eduard
 E: 69
 d: 100
 u: 117
 a: 97
 r: 114
 d: 100

Rozbor programu: Program má za úlohu, zistiť ASCII kód písmen z vášho mena. Program začína hláškou a vstupom od užívateľa. Následne začne prvý test cyklu. Podmienka i < name.size() znamená, že test bude úspešný, pokým premenná i je menšia ako dĺžka reťazca. V tele cyklu pomocou static_cast<int> pretypujeme premennú typu char (znak) na typ int (celé číslo). O pretypovaní premenných v C++ bude ešte niekedy v budúcností článok. Vo výsledku dostaneme pre každé jednotlivé písmeno zadaného reťazca jeho ASCII číselnú podobu.



Cyklus while verzus for

Aký je rozdiel medzi cyklom for a while? V podstate žiadny, len zápis je iný. Pozrime si deklarácie oboch cyklov.

Cyklus for:

for (inicializačný výraz; testovací výraz; zvýšenie/zníženie hodnoty inicializačného výrazu)
 {
             príkazy
 }

A cyklus while:

inicializačný výraz;
 while (testovací výraz)
 {
             príkazy
             zvýšenie/zníženie hodnoty inicilizačného výrazu;
 }

Ak si odmyslíme inicializáciu a zmeny hodnoty inicializácie, tak máme:

for (;testovací výraz;)
 telo 
 while (testovací výraz)
 telo

Vidíte, sú si ekvivalentné tieto cykly.

Otázkou však je, aká je základná kostra oboch cyklov? Je vôbec nutné mať testovací výraz, aby mi prešla kompilácia?

Skúsime na príkladoch.

2. príklad: Kostra cyklu for

#include <iostream>
 using namespace std;
 
 int main()
 {
     for(;;)
     {
         cout << "Som paaaan programator!\n";
     }
 
     return 0;
 }

Priebeh programu: Nechcite vidieť ten veľký report. Dalo by povedať, že by bol nekonečný, ak násilne neukončíme program. Otázka na zamyslenie, zastaví sa vôbec niekedy program bez pričinenia? Naštudujte si problém zastavenia (halting problem) a zistíte, že tento nekonečný cyklus nikdy neskončí.

Rozbor programu: Takže už vieme, že sme stvorili nekonečný cyklus. Zároveň je deklarácia for(;;) najzákladnejšia.

Fajn, predpokladajme, že i cyklu while nedáme testovací výraz. Prejde kompilácia?

3. príklad: Kostra cyklu while

#include <iostream>
 using namespace std;
 
 int main()
 {
     while()
     {
         cout << "Som paaaan programator!\n";
     }
 
     return 0;
 }

Priebeh programu:

…/momo.cpp||In function 'int main()':|
 …/momo.cpp|5|error: expected primary-expression before ')' token|
 ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Rozbor programu:

Ajajaj, ani nám to neskompilovalo. Ako to? V cykle while je povinný testovací výraz. Na vytvorenie nekonečného cyklu postačí, keď dáme napríklad 1. Keďže hodnotu 1 nebudeme meniť, stále bude hodnota 1 a cyklus sa tak nikdy neskončí.

4. príklad:

#include <iostream>
 using namespace std;
 
 int main()
 {
     while(1)
     {
         cout << "Som paaaan programator!\n";
     }
 
     return 0;
 }

Priebeh makra: Náš nekonečný cyklus funguje.

Nahoru

Příspěvky

Programovanie v jazyku C++: Cyklus while (1)
Jardík 11. 01. 2017, 12:29:53
Odpovědět  Odkaz 
>> while (name[i] != '\0')
Tady pozor. C++ sice od C++11 garantuje, že std::string opravdu na konci řetězce nulový byte má (předtím byl takový požadavek jen na fci string::c_str()), ale nikde není zakázáno, že uprostřed stringu nemůže být taky. std::string může obsahovat nulové znaky kdekoliv! Dokonce i čtením ze std::cin použitím operátoru >> takový řetězec můžete dostat. V konzoli ho třeba nedokážete zadat, ale při přesměrování ze souboru to takový řetězec vrátí. Znak '\0' není považován za bílý znak a bude součástí vstupu. Zkuste si

#include
#include

int main()
{
std::string str;

if (std::cin >> str)
{
std::cout
Re: Programovanie v jazyku C++: Cyklus while (1)
Jardík 11. 01. 2017, 12:34:09
Odpovědět  Odkaz 
Omlouvám se, zase mi to snědlo půlku příspěvku:

Tady pozor. C++ sice od C++11 garantuje, že std::string opravdu na konci řetězce nulový byte má (předtím byl takový požadavek jen na fci string::c_str()), ale nikde není zakázáno, že uprostřed stringu nemůže být taky. std::string může obsahovat nulové znaky kdekoliv! Dokonce i čtením ze std::cin použitím operátoru >> takový řetězec můžete dostat. V konzoli ho třeba nedokážete zadat, ale při přesměrování ze souboru to takový řetězec vrátí. Znak '\0' není považován za bílý znak a bude součástí vstupu. Zkuste si:

(kód na http://pastebin.com/qU0h0auJ)

A vytvořte soubor (např. a.dat), s obsahem (hex) 61686F6A_00_6A6172646F (ahoj(NULL)jardo). Spusťte program s přesměrováním souboru na standardní vstup (./test < a.dat). Program vypíše celou sekvenci. Příklad by bylo lepší modifikovat na

while (i != name.size()) {}

A typ proměnné i samozřejmě změnit na "správný typ", kterým int není. Což je, si myslím, mnohem názornější. Popř. opravit tvrzení "Podmienka name[i] != '\0' znamená, že test bude úspešný, pokým nenarazí na ukončovací znak reťazca." a napsat tam "dokud nenarazí na první nulový byte", nebo tak něco.
Eduard Boldižár Re: Re: Programovanie v jazyku C++: Cyklus while (1)
Eduard Boldižár 11. 01. 2017, 13:41:53
Odpovědět  Odkaz 
Vďaka, zmením na:
int i = 0;
while (name[i] != NULL)
{
cout
Eduard Boldižár Re: Re: Programovanie v jazyku C++: Cyklus while (1)
Eduard Boldižár 11. 01. 2017, 13:45:25
Odpovědět  Odkaz 
Tiež mi to zle posiela odpovede. Tak ešte raz:

int i = 0;
while (name[i] != NULL)
{
cout
Eduard Boldižár Programovanie v jazyku C++: Cyklus while (1)
Eduard Boldižár 11. 01. 2017, 13:46:55
Odpovědět  Odkaz 
Ok v skratkostí, lebo niečo tu nefunguje. Lepšie while (name[i] != NULL)? Mohlo by to byť ok. i je preto integer, lebo má zaujíma index poľa.
Re: Programovanie v jazyku C++: Cyklus while (1)
Jardík 11. 01. 2017, 16:42:31
Odpovědět  Odkaz 
Né, while (name[i] != NULL) nepomůže. Poblém je, že std::string může obsahovat nulový byte, na začátku, uprostřed, nakonci, prostě kdekoliv. Ta podmínka říká "vem znak na pozici i a zkontroluj, jestli není nulový". To není stejné, jako se zeptat "je i platný index řetězce". Pokud v cyklu nehledáte první nulový byte v řetězci, ale účelem je iterovat přes všechny znaky řetězce, tak správné řešení s použitím cyklu while je porovnat index i s velikostí řetězce - např. while (i != name.size()), nebo while (i < name.size()).

Co se týče typu proměnné i, funkce std::string::size() vrací hodnotu typu std::string::size_type, což je typedef na std::size_t. To je neznaménkový číselný typ shopný pojmout, v tomto případě, hodnotu maximální délky řetězce. To s typem int zaručené nemáte a může přetéci. A přetečení znaménkového typu pak vede k nedefinovanému chování (popř. definovaného implementací při přetečení při konverzi neznaménkového typu na znaménkový). Proto správně je např.

std::size_t i = 0;
while (i < name.size())
{
// dělej něco se znakem name[i]
++i;
}

Samozřejmě použitý for-range cyklu by bylo hezčí, ale článek je o cyklu while:

for (char c : name)
{
// dělej něco se znakem c
}
Eduard Boldižár Re: Re: Programovanie v jazyku C++: Cyklus while (1)
Eduard Boldižár 11. 01. 2017, 17:37:35
Odpovědět  Odkaz 
Áno, je mi to jasne. Vďaka, zmením to.

Odpovědět

Nejsou podporovány žádné značky, komentáře jsou jen čistě textové. Více o diskuzích a pravidlech najdete v nápovědě.
Diskuzi můžete sledovat pomocí RSS kanálu rss



 
 

Top články z OpenOffice.cz