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ť struct
mi (alias degenerovanými triedami ;-)). Údaje pre UID a GID uložíme do int
ov, 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()
asscanf()
. Pomocoufgets()
načítame celý riadok do buffera, ktorý následne naparsujeme cezsscanf()
.
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.