Programovací jazyk C: cvičenie 4

Teploty

V textovom súbore máme uvedených n údajov o teplote, ktorá bola nameraná na poludnie. Nájdite maximálnu teplotu v nameraných dátach. Pozor však: v rámci prípravy na budúce úlohy nerobte výpočet jednorazovým prechodom, ale uložte si dáta do vhodnej dátovej štruktúry.

Uľahčenie môžeme získať uvedením počtu údajov na prvé miesto v súbore. Ukážkový súbor:

5
35.1
32.0
37.0
25.0
26.7

Riešenie

V tomto prípade potrebujeme alokovať pole s toľkými prvkami, koľko udáva prvé číslo v súbore. S výhodou využijeme malloc()

Na výpočet maxima definujme funkciu najdi_maximum, pričom nezabudneme uviesť dva parametre: samotné pole + jeho dĺžku (C totiž v prípade polí nikde neeviduje ich dĺžku.) Vieme s výhodou využiť fakt, že pole typu X a pointer na typ X sú ekvivalentné.

#include <stdio.h>
#include <stdlib.h>

int najdi_maximum(int pole[], int dlzka) {
    int max = -10000;
    int i = 0;
    for(; i < dlzka; i++) {
        if(pole[i] > max) {
            max = pole[i];
        }
    }
    return max;
}

int main(void)
{    
    FILE * subor;
    int pocet_prvkov;
    int i;

    int * prvky;

    subor = fopen("C:\\temp\\data.txt", "r");
    if(subor == NULL) {
        perror("Subor sa nepodarilo otvorit");
        return 1;
    }

    fscanf(subor, "%d", &pocet_prvkov);

    prvky = malloc(pocet_prvkov * sizeof(int));
    if(prvky == NULL) {
        perror("Malloc zlyhal");
        return 1;
    }

    for(i = 0; i < pocet_prvkov; i++) {
        fscanf(subor, "%d", &prvky[i]);
    }

    printf("%d", najdi_maximum(prvky, pocet_prvkov));

    fclose(subor);
    free(prvky);

    return 0;
}

Pseudo /etc/passwd

Majme daný zjednodušený súbor typu /etc/passwd z Linuxu, v ktorom sú uvádzané údaje o používateľoch systému. Súbor nech vyzerá nasledovne:

root:x:0:0
novotnyr:x:127:127
www-data:x:5:5

Na každom riadku sú štyri hodnoty oddelené dvojbodkami:

  • login používateľa (maximálne 32 znakov)
  • indikátor uloženia hesla v externom súbore /etc/shadow. Vždy má hodnotu x.
  • ID používateľa (UID), jednoznačné vzhľadom na celý súbor. Prirodzené číslo.
  • ID skupiny používateľa (GID). Prirodzené číslo.

Vytvorte program, ktorý načíta súbor do pamäte a zaveďte nasledovné funkcie:

  • vyhľadanie používateľa podľa UID
  • výpis používateľa
  • výpis celej databázy.

Databáza nech je (zatiaľ) realizovaná pomocou structov a alokovaná staticky v poli 255 položiek.

Riešenie

Údaj o používateľovi možno elegantne reprezentovať structmi (alias degenerovanými triedami ;-)). Údaje pre UID a GID uložíme do intov, indikátor uloženia hesla môžeme rovno vynechať a pre login používateľa rezervuje pole 32 + 1 znakov (dodatkový znak pre ukončovací \0).

struct zaznam {
    char login[32 + 1];
    int uid;
    int gid;
};

Načítavanie môžeme realizovať:

  • cez cyklus a fscanf(). Žiaľ, fscanf() je veľmi málo robustná funkcia (stačí preletieť stackoverflow.com).
  • cez cyklus a kombináciu fgets() a sscanf(). Pomocou fgets() načítame celý riadok do buffera, ktorý následne naparsujeme cez sscanf().

V prípade druhej možnosti nezabudnime špecifikovať dostatočne veľký buffer: 64 znakov však rozhodne postačí. Ďalší významný bod spočíva v špecifikácii formátovacieho výrazu:

%32[^:]:%*c:%d:%d

Prvý komponent načíta maximálne tridsaťdva znakov (%32) odlišných od dvojbodky (skupina [^:] reprezentuje množinu znakov „nie dvojbodka”). Druhý komponent (%*c) načíta jeden znak, ktorý bude ignorovaný (indikátor *). Ďalšie dva komponenty zodpovedajú dvom decimálnym číslam, teda GID a UID.

Pri sscanf() nezabudneme na nutnosť uviesť adresy premenných. K adresám premenných UID a GID pristúpime cez ampersand, ale pozor! Login ho nepotrebuje — samotné pole znakov je totiž ekvivalentné s pointerom na char.

#include <stdio.h>
#include <stdlib.h>

struct zaznam {
    char login[32 + 1];
    int uid; /* id pouzivatela */
    int gid; /* id skupiny */
};

int main(void)
{    
    char riadok[64];

    FILE * subor;

    struct zaznam jeden_zaznam;

    subor = fopen("C:\\temp\\passwd.txt", "r");
    if(subor == NULL) {
        perror("Subor sa nepodarilo otvorit");
        return 1;
    }

    while(1) {
        if(fgets(riadok, 64, subor) == NULL) {
            break;
        }

        sscanf(riadok, "%32[^:]:%*c:%d:%d",
               jeden_zaznam.login,
               &jeden_zaznam.uid,
               &jeden_zaznam.gid);

        printf("%s\n", jeden_zaznam.login);

    }

    fclose(subor);

    return 0;
}

Tento kód samozrejme nepoužíva databázu, doplníme to nabudúce.

Pridaj komentár

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