Rodné číslo
V textovom súbore sa nachádza niekoľko rodných čísiel, pričom prvý riadok súboru obsahuje číslo udávajúce počet údajov v súbore. Zistite, koľko mužov a žien je v súbore.
Ukážkový súbor:
1201021234 9912319999 8962011111
Riešenie cez scanf()
Jedno riešenie sa spoľahne na funkciu scanf()
, do ktorej narveme vhodný formátovací reťazec. Ako vyzerá jedno rodné číslo?
[cifra][cifra][INDIKÁTOR][cifra][cifra][cifra][cifra][cifra][cifra][cifra][cifra]
Inak povedané:
dve_cifry[INDIKÁTOR]osem_cifier
Pozor na dátové typy: osem cifier môže na niektorých platformách vypadnúť z rozsahu int
u: na 8-bitových a 16-bitových strojoch má int
hornú hranicu 32767. Skúsme nachvíľu uvažovať v long
och:
int predpona;
char indikator;
long pripona;
scanf("%2d%c%8ld", &predpona, &indikator, &pripona))
- Pre dve cifry stačí načítať
int
dĺžky 2: teda%2d
. - Pre indikátor stačí jeden
char
: teda%c
. - Pre osemznakovú príponu ostane
long
: teda%8ld
(ld
, napriek podivnému označeniu, zodpovedá long integeru).
Funkcia scanf()
vráti ako návratovú hodnotu počet načítaných položiek: v našom prípade by mali byť vždy tri. Výnimkou je situácia, keď parsovanie skončí na konci súboru: neprekvapivo sa nám vráti EOF
.
Dajme si celý program (zatiaľ bez počítania). Je to predbežná verzia, ktorá má priestor na šetrenie pamäťou!
Celý zdroják (verzia 1)
#include <stdio.h>
int main(void) {
int predpona;
char indikator;
long pripona;
int najdenych = 0;
while((najdenych = scanf("%2d%c%8ld", &predpona, &indikator, &pripona)) != EOF) {
printf("%c\n", indikator);
printf("Najdenych poloziek: %d\n", najdenych);
}
}
Zdroják možno spustiť napríklad:
./rodnecisla < rodnecisla.txt
Premenná predpona
a pripona
môžeme úplne odignorovať, lebo vo výsledku nás nezaujímajú. Našťastie, vzor pre načítavanie môže pre každú položku nastaviť príkaz “ignoruj ma!”, a to pomocou hviezdičky, ktorá bude indikovať, že položka sa síce naparsuje, ale nebude potrebovať premennú, do ktorej sa uloží. Aha:
scanf("%*2c%c%*8c", &indikator)
- načítame dvojznakový reťazec, ktorý odignorujeme hviezdičkou
- potom načítame jeden znak s indikátorom
- potom načítame ďalších osem znakov do reťazca, ktorý opäť odignorujeme.
Návratová hodnota bude momentálne stále buď jedna (ignorované položky sa nezarátavajú) alebo EOF
.
Celý zdroják (verzia 2)
#include <stdio.h>
int main(void) {
unsigned int zien = 0;
unsigned int muzov = 0;
char indikator;
while(scanf("%*2c%c%*8c", &indikator) != EOF) {
if(indikator == '5' || indikator == '6') {
zien++;
} else if(indikator == '0' || indikator == '1') {
muzov++;
}
}
printf("Muzov: %d\nZien: %d\n", muzov, zien);
}
Funkcia scanf()
však nie je veľmi robustná: je síce pravda, že načíta aj takýto vstup:
8952129987 8902129987 9911011234
ale ak narazí na nenaparsovateľné sekvencie, jednoducho zdochne:
xxxx 8952129987 8902129987 9911011234
Alebo umrie aj na tomto:
Rodne cisla:
============
8952129987
8902129987
9911011234
Ak je vstup flexibilný, alebo má nábeh na nepravidelnosti, je omnoho lepšie načítavať ho po jednotlivých riadkoch cez fgets()
a každý z riadkov samostatne skontrolovať a následne z neho vytiahnuť tretí znak.