Programovanie (1) v C/C++
1-INF-127, ZS 2024/25

Úvod · Pravidlá · Prednášky · Softvér · Testovač
· Kontaktujte nás pomocou e-mailovej adresy E-prg.png (bude odpovedať ten z nás, kto má príslušnú otázku na starosti alebo kto má práve čas).
· Prosíme študentov, aby si pravidelne čítali e-maily na @uniba.sk adrese alebo aby si tieto emaily preposielali na adresu, ktorú pravidelne čítajú.


Prednáška 15: Rozdiel medzi revíziami

Z Programovanie
Skočit na navigaci Skočit na vyhledávání
Riadok 4: Riadok 4:
 
* Budúci týždeň budú kvôli štátnemu sviatku iba piatkové cvičenia. V ''pondelok 16. novembra'' bude zverejnených niekoľko úloh na cvičenia č. 9 (menej, než obvykle).
 
* Budúci týždeň budú kvôli štátnemu sviatku iba piatkové cvičenia. V ''pondelok 16. novembra'' bude zverejnených niekoľko úloh na cvičenia č. 9 (menej, než obvykle).
 
* V ''piatok 20. novembra'' bude na začiatku doplnkových cvičení krátky test, body za ktorý budú riadnou súčasťou hodnotenia z cvičení č. 9. Pokyny ohľadom technickej realizácie testu budú upresnené neskôr.
 
* V ''piatok 20. novembra'' bude na začiatku doplnkových cvičení krátky test, body za ktorý budú riadnou súčasťou hodnotenia z cvičení č. 9. Pokyny ohľadom technickej realizácie testu budú upresnené neskôr.
 +
 +
== Smerníková aritmetika ==
 +
 +
Na smerníkoch možno vykonávať určité operácie, ktoré sa zvyknú nazývať smerníková aritmetika. Uvažujme číslo <tt>n</tt> typu <tt>int</tt> a smerníky <tt>p</tt> a <tt>q</tt> na nejaký typ <tt>T</tt>
 +
<syntaxhighlight lang="C++">
 +
int n;
 +
T *p, *q;
 +
</syntaxhighlight>
 +
* <tt>p + n</tt> je smerník na <tt>n</tt>-té políčko za adresou <tt>p</tt>, pričom veľkosť políčka je daná typom <tt>T</tt>
 +
** <tt>p + n</tt> je teda to isté ako <tt>&(p[n])</tt> a <tt>*(p+n)</tt> je to isté ako <tt>p[n]</tt>.
 +
** <tt>p++</tt> je skratkou pre <tt>p = p + 1</tt>, posunie nám teda smerník <tt>p</tt> o políčko doprava.
 +
** Výraz <tt>p[n]</tt> je len skratkou pre <tt>*(p+n)</tt>.
 +
** <tt>p[n]</tt> aj <tt>p + n</tt> teda chceme používať iba ak <tt>p</tt> ukazuje na prvok poľa, za ktorým v poli ide ešte aspoň <tt>n</tt> ďalších políčok
 +
* Podobne <tt>p - n</tt> je smerník na <tt>n</tt>-té políčko pred adresou <tt>p</tt>.
 +
** <tt>p - n</tt> teda chceme používať iba ak <tt>p</tt> ukazuje na prvok poľa, pred ktorým v poli ide ešte aspoň <tt>n</tt> ďalších políčok
 +
* Ak <tt>p</tt> a <tt>q</tt> sú adresami prvkov v tom istom poli, <tt>p - q</tt> je celé číslo <tt>k</tt> také, že <tt>p == q + k</tt>, t.j. o koľko políčok je <tt>p</tt> ďalej vpravo od <tt>q</tt>.
 +
* Ak <tt>p</tt> a <tt>q</tt> sú adresami prvkov v tom istom poli, môžeme ich tiež porovnávať pomocou <tt><, >, <=, >=</tt>
 +
* Ľubovoľné dva smerníky toho istého typu vieme porovnávať pomocou <tt>==, !=</tt>.
 +
 +
Tu je napr. zvláštny spôsob ako vypísať pole <tt>a</tt>:
 +
<syntaxhighlight lang="C++">
 +
int a[4] = {4, 3, 2, 1};
 +
for (int *smernik = a; smernik < a + 4; smernik++) {
 +
    cout << "Prvok " << smernik - a << " je " << *smernik << endl;
 +
}
 +
</syntaxhighlight>
 +
 +
Podobný kód sa ale občas používa na prechádzanie reťazcov. Napríklad nasledujúca funkcia spočíta počet medzier v reťazci:
 +
 +
<syntaxhighlight lang="C++">
 +
int zratajMedzery(char str[]) { // mohli by sme dat aj char *str
 +
  int pocet = 0;
 +
  while(*str != 0) {  // kym nenajdeme ukoncovaciu nulu v retazci
 +
    if(*str == ' ') { // skontroluj znak, na ktory ukazuje smernik
 +
        pocet++;
 +
    }
 +
    str++;          // posun smernik na dalsi znak
 +
  }
 +
  return pocet;
 +
}
 +
</syntaxhighlight>
 +
 +
=== Funkcie z knižnice cstring so smerníkovou aritmetikou===
 +
 +
* <tt>strstr(text, vzorka)</tt> vracia smerník na <tt>char</tt>
 +
** <tt>NULL</tt> ak sa vzorka nenachádza v texte, smerník na začiatok prvého výskytu inak
 +
** pozíciu výskytu zistíme smerníkovou aritmetikou:
 +
<pre>
 +
char *text = "Hello world!";
 +
char *vzorka = "or";
 +
char *where = strstr(text, vzorka);
 +
if(where != NULL) {
 +
  int position = where - text;
 +
}
 +
</pre>
 +
* Ako by ste spočítali počet výskytov vzorky v texte?
 +
* Podobne <tt>strchr</tt> hľadá prvý výskyt znaku v texte
 +
 +
=== Sizeof() ===
 +
Operátor <tt>sizeof()</tt> zistí "veľkosť" dátového typu v bajtoch
 +
* presnejšie ide o vzdialenosť medzi nasledujúcimi prvkami poľa, teda o koľko sa posunieme pri posune +1 v smerníkovej aritmetike
 +
* napr. pri <tt>struct</tt> nemusí byť rovné súčtu veľkostí premenných
 +
 +
<pre>
 +
int i, *pi;
 +
sizeof(*pi);  // počet bajtov potrebných na uloženie typu int
 +
sizeof(i);    // da sa napísať aj takto
 +
sizeof(int);  // alebo takto
 +
 +
sizeof(pi);    // pocet bajtov na ulozenie smernika na int
 +
sizeof(int *); // to iste
 +
</pre>
  
 
== Práca s konzolou na spôsob jazyka C: <tt>printf</tt> a <tt>scanf</tt> ==
 
== Práca s konzolou na spôsob jazyka C: <tt>printf</tt> a <tt>scanf</tt> ==

Verzia zo dňa a času 20:20, 9. november 2021

Oznamy

  • Na piatkových doplnkových cvičeniach bude bonusová rozcvička (za 1 bonusový bod). Zvyšné úlohy z tohto týždňa treba odovzdať do stredy 18. novembra, 22:00.
  • Druhú domácu úlohu treba odovzdať do piatku 13. novembra, 22:00.
  • Budúci týždeň budú kvôli štátnemu sviatku iba piatkové cvičenia. V pondelok 16. novembra bude zverejnených niekoľko úloh na cvičenia č. 9 (menej, než obvykle).
  • V piatok 20. novembra bude na začiatku doplnkových cvičení krátky test, body za ktorý budú riadnou súčasťou hodnotenia z cvičení č. 9. Pokyny ohľadom technickej realizácie testu budú upresnené neskôr.

Smerníková aritmetika

Na smerníkoch možno vykonávať určité operácie, ktoré sa zvyknú nazývať smerníková aritmetika. Uvažujme číslo n typu int a smerníky p a q na nejaký typ T

int n;
T *p, *q;
  • p + n je smerník na n-té políčko za adresou p, pričom veľkosť políčka je daná typom T
    • p + n je teda to isté ako &(p[n]) a *(p+n) je to isté ako p[n].
    • p++ je skratkou pre p = p + 1, posunie nám teda smerník p o políčko doprava.
    • Výraz p[n] je len skratkou pre *(p+n).
    • p[n] aj p + n teda chceme používať iba ak p ukazuje na prvok poľa, za ktorým v poli ide ešte aspoň n ďalších políčok
  • Podobne p - n je smerník na n-té políčko pred adresou p.
    • p - n teda chceme používať iba ak p ukazuje na prvok poľa, pred ktorým v poli ide ešte aspoň n ďalších políčok
  • Ak p a q sú adresami prvkov v tom istom poli, p - q je celé číslo k také, že p == q + k, t.j. o koľko políčok je p ďalej vpravo od q.
  • Ak p a q sú adresami prvkov v tom istom poli, môžeme ich tiež porovnávať pomocou <, >, <=, >=
  • Ľubovoľné dva smerníky toho istého typu vieme porovnávať pomocou ==, !=.

Tu je napr. zvláštny spôsob ako vypísať pole a:

int a[4] = {4, 3, 2, 1};
for (int *smernik = a; smernik < a + 4; smernik++) {
     cout << "Prvok " << smernik - a << " je " << *smernik << endl;
}

Podobný kód sa ale občas používa na prechádzanie reťazcov. Napríklad nasledujúca funkcia spočíta počet medzier v reťazci:

int zratajMedzery(char str[]) { // mohli by sme dat aj char *str
  int pocet = 0;
  while(*str != 0) {   // kym nenajdeme ukoncovaciu nulu v retazci
     if(*str == ' ') { // skontroluj znak, na ktory ukazuje smernik
         pocet++; 
     }
     str++;           // posun smernik na dalsi znak 
  }
  return pocet;
}

Funkcie z knižnice cstring so smerníkovou aritmetikou

  • strstr(text, vzorka) vracia smerník na char
    • NULL ak sa vzorka nenachádza v texte, smerník na začiatok prvého výskytu inak
    • pozíciu výskytu zistíme smerníkovou aritmetikou:
char *text = "Hello world!";
char *vzorka = "or";
char *where = strstr(text, vzorka);
if(where != NULL) {
  int position = where - text;
}
  • Ako by ste spočítali počet výskytov vzorky v texte?
  • Podobne strchr hľadá prvý výskyt znaku v texte

Sizeof()

Operátor sizeof() zistí "veľkosť" dátového typu v bajtoch

  • presnejšie ide o vzdialenosť medzi nasledujúcimi prvkami poľa, teda o koľko sa posunieme pri posune +1 v smerníkovej aritmetike
  • napr. pri struct nemusí byť rovné súčtu veľkostí premenných
int i, *pi;
sizeof(*pi);   // počet bajtov potrebných na uloženie typu int 
sizeof(i);     // da sa napísať aj takto
sizeof(int);   // alebo takto

sizeof(pi);    // pocet bajtov na ulozenie smernika na int
sizeof(int *); // to iste

Práca s konzolou na spôsob jazyka C: printf a scanf

Doposiaľ sme s konzolou pracovali prostredníctvom knižnice iostream, ktorá patrí medzi štandardné knižnice jazyka C++ a v ktorej sú definované štandardné vstupno-výstupné prúdy cin a cout. V nasledujúcom si ukážeme alternatívny prístup k práci s konzolou založený na knižnici cstdio, ktorá je štandardnou knižnicou jazyka C. Podobne ako nižšie sa tak so vstupom a výstupom dá pracovať aj v jazyku C.

Výpis formátovaných dát na konzolu: printf

S použitím knižnice cstdio možno na konzolu písať pomocou funkcie printf. Jej základné použitie môže vyzerať napríklad takto:

#include <cstdio>
using namespace std;

int main(void) {
    printf("Ahoj svet, este raz!\n");
    return 0;
}

Funkciu printf možno volať aj s viac ako jedným argumentom. Vo všeobecnosti vyzerá jej volanie nasledovne:

printf(format, hodnota1, hodnota2, ...)

Prvým argumentom je takzvaný formátovací reťazec, za ním nasleduje niekoľko ďalších argumentov (prípadne aj žiaden). Formátovací reťazec pozostáva z dvoch druhov znakov: bežné znaky, ktoré sa priamo vypíšu na výstup a takzvané špecifikácie konverzií začínajúce symbolom % a končiace tzv. znakom konverzie, ktoré majú za následok vypísanie niektorého z ďalších argumentov funkcie printf (presnejšie prvého ešte nevypísaného argumentu). V rámci špecifikácie konverzie možno zadať formát, v ktorom sa má ten-ktorý argument vypísať.

Napríklad

#include <cstdio>
using namespace std;

int main(void) {
    int n = 7;
    printf("Prve cislo je %d a druhe cislo je %d.\n",1+1,n);
    return 0;
}

vypíše

Prve cislo je 2 a druhe cislo je 7.

Špecifikácia %d tu pozostáva iba zo znaku konverzie d, ktorý zodpovedá výpisu celého čísla v desiatkovej sústave.

Ďalšie príklady znakov konverzie:

  • %f: reálne číslo.
  • %e: reálne čislo vo vedeckej notácii, napr. 5.4e7.
  • %x: celé číslo v šestnástkovej sústave.
  • %c: znak (char).
  • %s: reťazec (char *).
  • %%: vypíše samotný znak %.

Pozor: typy jednotlivých argumentov musia byť v súlade s formátovacím reťazcom (pričom vo všeobecnosti nedôjde k automatickému pretypovaniu).

Pred samotný znak konverzie možno pridávať aj modifikátory l, ll, resp. h zodpovedajúce modifikátorom typov long, long long, resp. short. Napríklad

  • %lld: vypíše „veľmi dlhé” celé číslo.
  • %lf: pri printf by sa nemalo používať, zato však veľmi podstatné pri načítavaní.

Formátovanie výstupu

Formát vypísania daného argumentu možno zadať niekoľkými nepovinnými parametrami medzi symbolom % a znakom konverzie. Napríklad:

  • %.2f: vypíše reálne číslo na 2 desatinné miesta.
  • %4d: ak má celé číslo menej ako 4 cifry, doplní vľavo medzery.
  • %04d: podobne, ale dopĺňa nuly.

Nasledujúci program vo vhodnom formáte vypíše hodnoty faktoriálu prirodzených čísel od 1 po 20:

#include <cstdio>
using namespace std;

long long int factorial(int n) {                      
    if (n == 0) {
        return 1;
    } else {
        return n * factorial(n-1);
    }
}

int main(void) {
    for (int i = 1; i <= 20; i++) {                   
        printf("%2d! = %22lld\n",i,factorial(i));
    }
    return 0;
}

Nasledujúci program vypíše vo vhodnom formáte zadaný dátum:

#include <cstdio>
using namespace std;

void vypisDatum(int d, int m, int r) {
    printf("%02d.%02d.%04d\n",d,m,r);
}

int main(void) {
    vypisDatum(2,1,2019);
    return 0;
}

Celá špecifikácia konverzie pozostáva z nasledujúcich častí:

  • Z povinného úvodného znaku %.
  • Z jedného alebo niekoľkých nepovinných príznakov, ako napríklad -, ktorého použitie vyústi v zarovnanie vypisovaného textu vľavo (bez jeho použitia sa text zarovná vpravo). Ďalšími príznakmi sú napríklad 0 (dopĺňanie núl naľavo), + (vypíše znamienko + pri kladných číslach), atď.
  • Z nepovinného celého čísla udávajúceho minimálnu šírku výpisu (minimálny počet „políčok”, do ktorých sa text vypíše).
  • Z nepovinnej bodky nasledovanej celým číslom udávajúcim presnosť výpisu (pri reálnych číslach napríklad počet desatinných miest; presnosť má však svoju interpretáciu aj pri iných typoch dát).
  • Z nepovinného modifikátora l, ll, alebo h pre long, long long, resp. short.
  • Z povinného symbolu konverzie (napr. d, f, s, ...).

Načítanie formátovaných dát z konzoly: scanf

Funkciu scanf s typickým volaním

scanf(format, adresa1, adresa2, ...)

možno využiť na načítanie dát z konzoly.

  • Napríklad scanf("%d", &x) načíta celočíselnú hodnotu do premennej x.
  • Zatiaľ čo argumentmi printf sú priamo hodnoty, scanf potrebuje adresy premenných, pretože ich modifikuje.

Jednoduchý príklad použitia:

#include <cstdio>
using namespace std;

void vypisDatum(int d, int m, int r) {
    printf("%02d.%02d.%04d\n",d,m,r);
}

int main(void) {
    int r;

    printf("Zadaj rok: ");  
    scanf("%d", &r);        
    vypisDatum(1,1,r);                   
    return 0;
}

Pomocou scanf možno načítať aj viacero premenných naraz:

#include <cstdio>
using namespace std;

void vypisDatum(int d, int m, int r) {
    printf("%02d.%02d.%04d\n",d,m,r);
}

int main(void) {
    int d,m,r;

    printf("Zadaj den, mesiac a rok: ");  
    scanf("%d %d %d", &d, &m, &r);        
    vypisDatum(d,m,r);                    
    return 0;
}

Formátovací reťazec sa teraz interpretuje nasledovne:

  • Špecifikácie formátov načítavaných premenných (začínajúce znakom %) možno zadávať podobne ako pri funkcii printf.
    • Pozor: na načítanie reálneho čísla typu double je potrebné namiesto %f použiť %lf. Použitie %f zodpovedá načítavaniu hodnoty „kratšieho” typu float. Pri funkcii printf je však žiadúce pre double aj float používať %f (hoci na mnohých systémoch bude fungovať aj %lf).
  • Biele znaky (angl. whitespace; t.j. medzery, konce riadkov, tabulátory) vo formátovacom reťazci spôsobia, že funkcia scanf číta a ignoruje všetky biele znaky pred ďalším nebielym znakom. Jeden biely znak vo formátovacom reťazci tak umožní ľubovoľný počet bielych znakov na vstupe.
  • Ostatné znaky formátovacieho reťazca musia presne zodpovedať vstupu.

Nasledujúci príkaz tak napríklad načíta dátum vo formáte deň.mesiac.rok:

scanf("%d.%d.%d", &d, &m, &r);

Kontrola správnosti vstupu

Funkcia scanf vracia na výstupe počet úspešne načítaných hodnôt zo vstupu. V prípade chyby hneď na začiatku vstupu tak napríklad vráti 0. V prípade, že hneď na začiatku narazí na koniec súboru (ktorý na konzole možno zadať pod Linuxom ako Ctrl+D resp. pod Windowsom ako Ctrl+Z a Enter), vráti hodnotu EOF (typicky -1).

Príklad: zadávanie dátumu vo formáte deň.mesiac.rok s kontrolou vstupu:

#include <cstdio>
using namespace std;

void vypisDatum(int d, int m, int r) {
    printf("%02d.%02d.%04d\n",d,m,r);
}

int main(void) {
    int d,m,r;
    printf("Zadaj datum: ");  
    if (scanf("%d.%d.%d", &d, &m, &r) == 3) {
        printf("Datum je ");
        vypisDatum(d,m,r);
    } else {
        printf("Nebol zadany korektny datum.\n");
    }
    return 0;
}

Ďalším príkladom môže byť program, ktorý počíta súčet postupne zadávaných čísel, až kým je zadané nekorektné číslo alebo koniec súboru:

#include <cstdio>
using namespace std;

int main(void) {
    double sum = 0;
    double x;
    while (scanf("%lf", &x) == 1) {
         sum += x;
    }
    printf("Sucet je %.2f\n", sum);
    return 0;
}

Textové súbory

Na načítavanie a vypisovanie dát sme doposiaľ používali výhradne konzolu. V praxi však často vzniká potreba spracovávať dáta uložené v súboroch. Zameriame sa teraz na súbory v textovom formáte, s ktorými sa pracuje podobne ako s konzolou.

Základy: typ FILE * a funkcie fopen, fclose, fprintf, fscanf

So súbormi sa pri použití knižnice cstdio pracuje pomocou typu FILE *. Ide tu o smerník na štruktúru typu FILE, ktorá obsahuje nejaké (pre programátora zväčša nepodstatné) informácie o súbore, s ktorým sa práve pracuje. Premenné pre prácu so súbormi tak možno definovať napríklad takto:

FILE *f;
FILE *fr, *fw;

Pozor: v názve typu FILE treba dodržať veľké písmená (čiže treba písať FILE *, nie file *).

Otvorenie súboru pre čítanie

  • fr = fopen("vstup.txt", "r");
  • Otvorí súbor s názvom vstup.txt (prípadne možno zadať kompletnú cestu k súboru).
  • Ak taký súbor neexistuje alebo sa nedá otvoriť, do fr priradí NULL.
  • Z takto otvoreného súboru môžeme čítať napríklad pomocou fscanf, ktorá je analógiou k scanf.
  • Napríklad fscanf(fr, "%d", &x);

Otvorenie súboru pre zápis

  • fw = fopen("vystup.txt", "w");
  • Vytvorí súbor s názvom vystup.txt. Ak už existoval, zmaže jeho obsah (keby sme vo volaní fopen namiesto "w" použili "a", pridávalo by sa na koniec existujúceho súboru).
  • Ak sa nepodarí súbor otvoriť, do fw priradí NULL.
  • Do takto otvoreného súboru môžeme zapisovať napr. pomocou funkcie fprintf, ktorá je analógiou k printf.
  • Napr. fprintf(fw, "%d", x);

Zatvorenie súboru

  • Po ukončení práce so súborom je ho potrebné zavrieť pomocou fclose(f);
  • Počet súčasne otvorených súborov je obmedzený.

Príklad

Nasledujúci program načíta číslo n a následne n celých čísel zo súboru vstup.txt. Do súboru vystup.txt vypíše vstupné čísla v opačnom poradí.

#include <cstdio>
#include <cassert>
using namespace std;

int main(void) {
    FILE *fr = fopen("vstup.txt", "r");  
    FILE *fw = fopen("vystup.txt", "w");
    assert(fr != NULL && fw != NULL);
    
    int n,r;
    r = fscanf(fr, "%d", &n);
    assert(r == 1 && n >= 0);
    int *a = new int[n];
    
    for (int i = 0; i <= n-1; i++) {
        r = fscanf(fr, "%d", &a[i]);
        assert(r == 1);
    }
    fclose(fr);
    for (int i = n-1; i >= 0; i--) {
        fprintf(fw, "%d ", a[i]);
    }
    fclose(fw);
    delete[] a;    
    return 0;
}

Štandardný vstup a výstup ako súbor

So štandardným vstupom a výstupom sa pracuje rovnako ako so súborom. V cstdio sú definované dva konštantné smerníky

FILE *stdin, *stdout;

pre štandardný vstupný a výstupný prúd. Tie tak môžu byť použité v ľubovoľnom kontexte, v ktorom sa očakáva súbor. Napríklad volanie fscanf(stdin,"%d",&x) je ekvivalentné volaniu scanf("%d",&x).

Ten istý kód sa tak dá použiť na prácu so súbormi aj so štandardným vstupom resp. výstupom – stačí len podľa potreby nastaviť premennú typu FILE *. Typické použitie je napríklad nasledovné:

    FILE *fr, *fw;
    ...
    fscanf(fr, "%s", str);
    if (strcmp(str,"-") == 0) {
        fw = stdout;
    } else {
        fw = fopen(str, "w");
    }
    fprintf(fw, "Hello world!\n");
    ...

Testovanie konca súboru

Existujú dve možnosti testovania „nárazu” na koniec súboru:

  • V knižnici cstdio je definovaná symbolická konštanta EOF, ktorá má väčšinou hodnotu -1. Ak sa funkcii fscanf nepodarí načítať žiadnu hodnotu, pretože načítavanie dospelo ku koncu súboru, vráti konštantu EOF ako svoj výstup.
  • Funkcia feof(subor) vráti true práve vtedy, keď sa funkcia fscanf (alebo nejaká iná funkcia) už niekedy pokúšala čítať za koncom súboru subor.

Spracovanie vstupu pozostávajúceho z postupnosti čísel

Často na vstupe očakávame postupnosť číselných hodnôt oddelených bielymi znakmi. Pozrime sa na tri obvyklé možnosti, ako môže byť takýto vstup zadaný a spracovaný pomocou funkcie fscanf.

Formát 1: N (počet čísel) a následne N ďalších čísel.

#include <cstdio>
#include <cassert>
using namespace std;

int main(void) {
    FILE *f;
    const int MAXN = 100;
    int a[MAXN], N, kod;

    f = fopen("vstup.txt", "r");
    assert(f != NULL);

    kod = fscanf(f, "%d ", &N);
    assert(kod == 1 && N >= 0 && N < MAXN);

    for (int i = 0; i < N; i++) {
        kod = fscanf(f, "%d ", &a[i]);
        assert(kod == 1);
    }
    fclose(f);

    // tu pride spracovanie dat v poli a
}

Formát 2: postupnosť čísel ukončená číslom -1 alebo inou špeciálnou hodnotu.

    // otvorime subor f ako vyssie
    N = 0;
    int x;
    kod = fscanf(f, "%d ", &x);
    assert(kod == 1);
    while (x != -1) {
        assert(N < MAXN);
        a[N] = x;
        N++;
        kod = fscanf(f, "%d ", &x);
        assert(kod == 1);
    }
    // zatvorime subor a spracujeme data

Formát 3: čísla, až kým neskončí súbor (najtypickejší prípad v praxi).

Priamočiary prístup nefunguje vždy správne:

    // otvorime subor f ako vyssie
    N = 0;
    while (!feof(f)) {
        assert(N < MAXN);
        kod = fscanf(f, "%d", &a[N]);
        assert(kod == 1);
        N++;
    }
    // zatvorime subor a spracujeme data

Po poslednom čísle v súbore často nasleduje ešte koniec riadku, v dôsledku čoho môže posledné volanie funkcie fscanf vyústiť v návratovú hodnotu -1 (predchádzajúce volanie fscanf totiž ešte „nenarazilo” na koniec súboru, v dôsledku čoho je pred čítaním posledného riadku hodnota feof(f) stále rovná false). Tým pádom program zlyhá na riadku assert(kod == 1). Tento nedostatok môžeme napraviť napríklad tak, že vo volaní funkcie fscanf dáme vo formátovacom reťazci za %d medzeru. Tá sa bude pokúšať preskočiť všetky biele znaky až po najbližší nebiely; pritom natrafí na koniec súboru a feof(f) už bude vracať true.

#include <cstdio>
#include <cassert>
using namespace std;

int main(void) {
    FILE *f;
    const int MAXN = 100;
    int a[MAXN], N, kod;

    f = fopen("vstup.txt", "r");
    assert(f != NULL);

    N = 0;
    while (!feof(f)) {
        assert(N < MAXN);
        kod = fscanf(f, "%d ", &a[N]);
        assert(kod == 1);
        N++;
    }
    fclose(f);

    // tu pride spracovanie dat v poli a
}