[itk] Számítástechnika kezdőknek

C++ programozás kezdőknek - while ciklus, fájlkezelés

[2021. szeptember 30.] [ christo161 ]

Ebben a tananyagrészben arról lesz szó, hogy hogyan tudunk utasításokat ismételten végrehajtani abban az esetben, ha az ismétlések száma nem ismert a program számára. Továbbá szó lesz még az alapvető fájlkezelésről.

Előző tananyagrész: tömb, std::array, std::vector, for ciklus
Következő tananyagrész: do-while ciklus, input ellenőrzés

while ciklus

A while ciklus azoknak az eseteknek a kezelésére lett kitalálva, amikor nem ismert a program számára, hogy hányszor kell megismételni bizonyos utasítások végrehajtását.

A while ciklus tulajdonképpen olyan mint egy if (else ág nélkül), azzal a különbséggel, hogy nem csak egyszer fut le, hanem egészen addig, amíg az általunk megadott feltétel érvényben van (tehát true az értéke). Amikor a feltétel már nem teljesül, a ciklusmag nem fut le (a ciklus leáll).

A while ciklus szintaxisát szemléltető kód (ez csak szemléltető kód, nem használható, fordítási hibát okoz):

while ( /*condition*/ ) {
  //statements executed while the condition is true
}

Az elöltesztelős ciklusok (for, foreach és while) struktogramja:

struktogram_ciklus_eloltesztelos.pngSokan használnak while ciklust for ciklus helyett, ugyanúgy számlálós ciklusként. Szerintem ennek kerülendőnek kéne lennie.

//use for loop instead of this
int i = 0;
while (i < n) {
  //statements
  ++i;
}

Amikor egy ciklusváltozót növelgetünk egy, a programunk számára ismert számig, akkor arra inkább for ciklust használjunk.

1. while ciklus példa: egy egész szám számjegyeinek száma

Egy int típusú szám tízzel való (egész)osztása valójában az adott szám legkisebb helyiértékű számjegyének elhagyását jelenti. Pl. ha int típusú 128-at osztunk szintén int típusú tízzel, annak eredménye 12 lesz.
Ha egy int típusú szám minden egyes tízzel osztását követően növelünk egy számlálót, akkor megkapjuk az adott szám számjegyeinek számát.
A számlálónak adjunk kezdőértéket, különben az eredmény nem lesz megfelelő.

//integer digits count example
#include <iostream>

int main () {
  long int input_number;
  std::cout << "Please enter an integer number:\n";
  std::cin >> input_number;
  std::cout << "The input number: " << input_number << '\n';
  int digits_count = 1;

  while ( input_number /= 10 ) {
    digits_count++;
  }

  std::cout << "The number of digits: " << digits_count << '\n';
}

Kapcsolódó tananyagrész:

Persze akár azt is meg lehetne tenni, hogy egy std::string típusú változóba kérjük be a felhasználótól a számot, és a size() tagfüggvénnyel lekérdezzük, hogy hány karaktert tartalmaz, bár ez nem tartalmaz while ciklust.

//integer digits count example
#include <iostream>
#include <string>

int main () {
  std::string input_number;
  std::cout << "Please enter an integer number:\n";
  std::cin >> input_number;
  std::cout << "The input number: " << input_number << '\n';

  std::cout << "The number of digits: " << input_number.size() << '\n';
}

2. while ciklus példa: soronkénti beolvasás fájlból

Elsőként hozzunk létre egy fájlt ugyanabban a könyvtárban, amiben a programunkat fogjuk elhelyezni. A fájl tartalma legyen mondjuk számértékek felsorolása:

1 0 3 6 8 3 4 6
4 6 0 4 7 9 1 5
5 9 1 3 2 0 3 4

Egy ilyen utasítást követően a file_example nevű fájl objektumon keresztül elérhetjük a programunkban azt a fájlt, ami a programunk futtatható fájljának könyvtárában található filename.txt néven:

ifstream file_example("filename.txt");

Az ifstream típusú file_example nevű fájl objektum követi nyomon, hogy hol tart a fájl feldolgozása.

Ezt követően ha létrehozunk egy std::string változót (pl. std::string row; utasítással), akkor a getline(file_example,row); utasítással beolvashatjuk a row nevű, std::string típusú fájlba a fájl egy sorát.

Két ellenőrzést azonban el kell végeznünk.
Egyrészt, hogy sikerült-e megnyitni a fájlt (pl. hibalehetőség ha nem létezik a fájl, vagy nem a megfelelő könyvtárban van), amit a fájl objektum is_open() tagfüggvényével tehetünk meg.
Másrészt pedig, hogy a fájl végére értünk-e, amit a fájl objektum eof() tagfüggvényével kérdezhetünk le. Az eof() tagfüggvény akkor ad vissza igazat, ha a fájl végére értünk, ezért a ciklusnak addig kell futnia, amíg az eof() tagfüggvény hamis értéket ad visszal, amit így fejezhetünk ki: !file_example.eof()

Ebben a példában kiíratjuk a standard outputra (alapesetben a parancssorba) a fájl sorait. Miután ezzel végeztünk, a fájl feldolgozását lezárjuk a fájl objektum close() tagfüggvényével.

if ( file_example.is_open() ) {
  while ( !file_example.eof() ) {
    getline(file_example, row);
    std::cout << sor << '\n';
  }
  file_example.close();
} else {
  std::cout << "Error opening file" << '\n';
}

A teljes példaprogram:

//print the rows of a file to stdout
#include <iostream>
#include <string>
#include <fstream>

int main() {
  std::fstream file_example( "example_1.txt" );
  std::string row;

  if ( file_example.is_open() ) {
    while ( !file_example.eof() ) {
      getline(file_example, row);
      std::cout << row << '\n';
    }
    file_example.close();
  } else {
    std::cout << "Error opening file" << '\n';
  }
}

Előfordulhat, hogy könyvekben, internetes példákban ennek a kódrészletnek egy kicsit módosított változatával találkozunk:

while ( getline(file_example, row) ) {
  std::cout << row << '\n';
}

3. while ciklus példa: szavankénti beolvasás fájlból

Hozzunk létre egy fájlt abban a könyvtárban, amiben majd a programunk indítófájlja lesz, például ezzel a tartalommal:

Budapest Prague Vienna Bucharest
New York Washington Toronto
Moscow Sanghai Pongyang

Az előző feladathoz hasonlóan szintén létre kell hoznunk egy fájl obkejtumot, aminek a paramétereként meg kell adnunk, hogy milyen nevű fájllal kívánunk dolgozni:

fstream file_example("filename.txt");

Ezt követően létre kell hoznunk egy (jellemzően std::string típusú) változót amibe egyenként beolvassuk a fájl egyes szavait, ezt nevezzük mondjuk word-nek.

Ha szavanként végezzük el a fájlból beolvasást, akkor a getline függvény helyett az std::cin-hez hasonlóan végezzük el a bekérést:

file_example >> word;

Ezelőtt persze az előző feladathoz hasonlóan el kell végeznünk a két ellenőrzést, hogy a fájlt sikerült-e megnyitni, illetve hogy nem ért-e a fájl végére a feldolgozás.

A while ciklust követően bezárjuk a fájlt.

//print the word of a file to stdout
#include <iostream>
#include <string>
#include <fstream>

int main() {
  std::fstream file_example("example_2.txt");
  std::string word;

  if ( file_example.is_open() ) {
    while ( !file_example.eof() ) {
      file_example >> word;
      std::cout << word << ' ';
    }
    file_example.close();
  } else {
    std::cout << "Error opening file" << '\n';
  }
}

Hozzáfűzés fájlhoz

Bár ez nem while ciklusos példa, hiszen ismerjük azon dolgok számát, amiket egy fájlba ki akarunk írni, a fájlkezeléshez viszont fontos ismeret lehet.

Ebben a példában egy std::vectorban tárolt értékeket írunk ki egy fájlba.

Szintén szükségünk lesz egy fájl objektumra. Ha a fájlhoz hozzáfűzni szeretnénk, fontos, hogy a második paraméter std::ios::app legyen (alapesetben nem ez van kiválasztva).

std::fstream file_example( "filename.txt", std::ofstream::app );

A for cikluson belül szinte ugyanúgy írjuk ki az elemeket a fájlba, mintha csak a standard outputra írnánk. Ebben a példában össze is lehet hasonlítani a kettőt, mivel a standard outputra is kiírjuk, amit a fájlba kiírtunk.

//print the rows of a file to stdout
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

int main() {
  std::vector<std::string> strings_example = {"Budapest", "Prague", "Warsaw", "Vienna", "Bratislava"};

  std::fstream file_example( "filename.txt", std::ofstream::out | std::ofstream::app );

  if ( file_example.is_open() ) {
    for (const std::string& element : strings_example) {
      file_example << element << ' ';
      std::cout << element << ' ';
    }
    file_example << '\n';
    std::cout << '\n';
    file_example.close();
  } else {
    std::cout << "Error opening file" << '\n';
  }
}

Fájl tartalmának felülírása

Az előző példához hasonló, csak a fájl objektum második paramétere std::ofstream::trunc lesz, nem pedig std::ofstream::app.

//print the rows of a file to stdout
#include <iostream>
#include <string>
#include <vector>
#include <fstream>

int main() {
  std::vector<std::string> strings_example = {"Budapest", "Prague", "Warsaw", "Vienna", "Bratislava"};

  std::fstream file_example( "filename.txt", std::ofstream::trunc | std::ofstream::out);

  if ( file_example.is_open() ) {
    for (const std::string& element : strings_example) {
      file_example << element << ' ';
      std::cout << element << ' ';
    }
    file_example << '\n';
    std::cout << '\n';
    file_example.close();
  } else {
    std::cout << "Error opening file" << '\n';
  }
}

Egyéb tananyagok:

Előző tananyagrész: tömb, std::array, std::vector, for ciklus
Következő tananyagrész: do-while ciklus, input ellenőrzés

A bejegyzés trackback címe:

https://itkezdoknek.blog.hu/api/trackback/id/tr116688662

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása