Cvičebnica z C: Počet mužov/žien v rodných číslach

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 intu: na 8-bitových a 16-bitových strojoch má int hornú hranicu 32767. Skúsme nachvíľu uvažovať v longoch:

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.

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *