Programovací jazyk C (UINF/JAC) – 2011

2011/11/25

Inštalácia

Nainštalujte Cygwin s balíčkami:

Nový projekt v NetBeans

Vytvorenie nového projektu v NetBeans

Nechajte si spustiť prázdny projekt. Pozorujte zhody so syntaxou Javy - funkcia main(), direktívy #include ako analógia importov kučeravé zátvorky, dátové typy podobné Jave. Spustite prázdny projekt, aby ste overili, že prostredie funguje korektne. Okomentujeme, že funkcia main() musí vracať celé číslo – nula znamená, že program dobehol správne. Konštanta EXIT_SUCCESS má hodnotu 0.

Cvičenia

Cvičenie 1 (20. 9. 2011)

Ahoj svet

Vypíšte na konzolu “Ahoj svet”.

Použite funkciu puts().

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {  
    puts("Hello World!");
    return (EXIT_SUCCESS);
}

Alternatívne použite funkciu printf().

Urobte zámernú chybu – napr. vynechajte bodkočiarku – a pozorujte varovanie kompilátora.

Vypíšte čísla od 1 po 30

Použijeme for cyklus. Vysvetlime si, že na rozdiel od Javy nemôžeme deklarovať premenné rovno v rámci cyklu – to je totiž až vymoženosť C++. Premenné deklarujeme na začiatku funkciu – podobne ako v Pascale.

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

int main(int argc, char** argv) {
    int i = 0;
    for(i; i < 10; i++) {
        printf("%d", i);
    }
    return (EXIT_SUCCESS);
}

Zdôraznime, že lokálne premenné treba vždy inicializovať, pretože štandardne je ich hodnota nedefinovaná a môžu obsahovať náhodné dáta.

Stručne vysvetlíme princíp formátovacích reťazcov - %d formátuje číslo.

Všimneme si, že výstupom je štrúdlik čísiel v jednom riadku - funkcia printf() totiž neudáva koniec riadku. Ten musíme špeciálne uviesť vo formátovacom reťazci. Korektnejšia verzia je teda

printf("%d\n", i);

Špeciálne si dajme pozor na to, že nesmieme zabudnúť formátovací reťazec. V opačnom prípade volanie printf(i) je síce syntakticky správne, ale logicky nekorektné.

Naučme sa zapnúť ladiace hlášky a varovania kompilátora, viď http://ics.upjs.sk/~novotnyr/wiki/CLanguage/NastavenieNetBeans.

Takáto chyba súvisí so smerníkmi, ale na tie si nechajme dostatok času.

Malá násobilka do 10

Vypíšte malú násobilku od 1 po 10.

Využime na to vnorené cykly. Podotknime, že obe premenné musia byť deklarované na začiatku funkcie a dohodnime konvenciu, že každá premenná je deklarovaná na samostatnom riadku.

Využime formátovací reťazec:

printf("%d x %d = %d, i, j, i * j);

Hľadanie väčšieho čísla z dvojice

Majme dané dve čísla v dvoch premenných, vypíšte väčšie z nich. (Zatiaľ neriešme vstup z klávesnice.)

Použime podmienku if. Pripomeňme, že test rovnosti sa používa pomocou == a nie pomocou (=). Poznamenajme, že v C neexistuje dátový typ boolean a podmienka if testuje, či výraz nadobúda nenulovú hodnotu. “Nenulové” hodnoty sú pravdivé.

Note

V céčku je podmienka if(i = 0) syntakticky korektná konštrukcia. Priraďovací príkaz vracia hodnotu a teda tento príkaz je ekvivalentný príkazu if(0). V kombinácii s predošlou zásadou to znamená, že takáto podmienka sa vždy vyhodnotí na “nepravdu”, ale môže to mať vedľajšie efekty (nechcenú zmenu obsahu premennej.)

Hľadanie maxima v poli

Z poľa čísiel zadaných v kóde vypíšte najväčšiu hodnotu (maximum). Zatiaľ sa venujme poliam celých čísiel. Syntax je o niečo odlišná od konvencie v Jave.

int pole[] = {2, 3, 5, -2};

Ak nepoznáme hodnoty pri inicializácii, použime syntax

int[4] pole;

Note

Java podporuje aj túto syntax, ale konvenciou je deklarovať pole nasledovne (všimnime si zátvorky)

  int[] pole = {2, 3, 5, -2}

Deklarácia poľa bez inicializácie sa v Jave realizuje konštruktorom, ale v C samozrejme operátor new neexistuje.

Pri hľadaní maxima v poli musíme inicializovať pomocnú premennú pre dosiaľ nájdené maximum. Pre jednoduchosť ju môžeme inicializovať hodnotou napr. -127.

Note

Letmo treba poznamenať niečo o portabilite programov a o rozsahu integeru. Pre korektnosť môžeme include-núť limits.h a využiť preddefinované konštanty.

Poznamenajme, že na rozdiel od Javy nemajú polia definovanú dĺžku (v porovnaní s vlastnosťou .length). V uvedenom prípade musíme už v čase kompilácie poznať dĺžku poľa (pre jednoduchosť pracujme s fixným počtom 5 čísiel v poli).

Note

Nekomplikujme výklad poznámkou o sizeof, ani výkladom o dynamicky alokovaných poliach - na to je ešte čas.

Vysvetlime, že Céčko zásadne nekontroluje medze polí. Ak máme päťprvkové pole, nič nám nezabráni iterovať cez prvých 100 prvkov, akurát od istého prvku budeme pristupovať do cudzej pamäte, čo môže mať nepredvídateľné následky – od čítania nezmyselných či náhodných dát, po pád programu na chybe SEGFAULT.

Vypíšte parametre zadané z príkazového riadku

Funkcia main() sprístupňuje dva parametre: argv a argc. Nebudeme komentovať dátové typy, vysvetlíme zatiaľ, že argv je pole reťazcov (reťazce nepitveme, nepúšťame sa do debát, že je to pointer na char a pod.)

Ak chceme uviesť do NetBeansu parametre príkazového riadka pre program, použijeme nastavenia projektu:Nastavenie príkazového riadka - dáta pre argv

Pole argv preiterujeme for cyklom a vypíšeme pomocou printf(). Vo formátovacom reťazci použijeme %s, zodpovedajúce reťazcom.

Note

V prípade, že vypisujeme čisté reťazce, môžeme použiť printf() tak, že reťazec bude sám sebe formátovacím reťazcom. Kvôli bezpečnosti a konzistentnosti sa odporúča vždy použiť formátovací reťazec s parametrom.

Cvičenie 2 (27. 9. 2011)

Nekonalo sa (konferencia ITAT)

Cvičenie 3 (4. 10. 2011)

Cvičenie 4 (11. 10. 2011)

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ždém riadku sú štyri hodnoty oddelené dvojbodkami:

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

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

Cvičenie 5 (18. 10. 2011)

Upravte predošlú úlohu tak, aby bola databáza alokovaná dynamicky podľa počtu záznamov v súbore. Pre jednoduchosť predpokladajte upravený súbor passwd tak, že počet záznamov je uvedený na prvom riadku.

2
root:x:0:0
novotnyr:x:127:127

Dopracujte vyhľadávanie používateľa podľa loginu. Vytvorte funkciu pre túto funkcionalitu; nájdeného používateľa nevracajte, ale vypíšte na konzolu.

Ďalšie čítanie: Dynamická alokácia pamäte a pointery

Zadania

Poznámky k zadaniam: zadania realizujte použitím ANSI C podľa normy ANSI C89/90. Kompilácia nech prebehne s parametrami -ansi -pedantic. Odporúčaný kompilátor je gcc.

Termín na odovzdanie je 6. 2. 2011 do 23:59

Zadanie 1

Vytvorte modul a používateľské rozhranie pre spracovanie INI súborov podľa konvencie súboru win.ini.

Inicializačný súbor predstavuje textový súbor nasledovného typu:

; for 16-bit app support
[Mail]
MAPI=1
[MCI Extensions.BAK]
3g2=MPEGVideo
3gp=MPEGVideo
3gp2=MPEGVideo
3gpp=MPEGVideo
[Internet]
UUID=2030258618

Riadok predstavuje:

Príklad:

1.  vybraný operačný systém
OS=Windows
1.  vybraný operačný systém
1.  jedna z možností: Windows / Linux / MacOS
OS=Windows
1.  Nastavenia Windowsu
[Windows]
BootDrive=C
InstallFolder=Windows

Znak = je tesne spojený na jednej strane s kľúčom a na druhej strane s hodnotou (okolo znaku = nie je žiadne biele miesto).

Názov kľúča nesmie obsahovať medzery, ale hodnota medzery obsahovať môže.

Každá položka začína prvým znakom nového riadku (nie sú pred ňou medzery ani iné znaky bieleho miesta).

Modul nech obsahuje funkcionalitu:

Dáta z INI súboru musia byť uložené v pamäti (nepripúšťa sa zmena dát načítaním, prebehnutím a úpravou súboru).

Modul nech je dodaný v podobe samostatného C súboru vrátane hlavičkového súboru obsahujúceho požadované funkcie.

Používateľské rozhranie nech predstavuje jednoduché menu s voľbou položiek menu z klávesnice, kde je možné otestovať nasledovnú funkcionalitu:

Všetky vyššie popísané funkcie musia byť v zadaní implementované – nepripúšťa sa odovzdanie čiastočne implementovaného zadania.

Zadanie 2

Vytvorte program spracovávajúci matematické výrazy v infixnej notácii za použitia reverznej poľskej notácie. Použité operátory sú:

Matematický výraz obsahuje prirodzené čísla, zátvorky a operátory.

Príklady výrazov:

Príklady nekorektných výrazov?

Prevod z infixnej notácie do reverznej poľskej notácie realizujte napr. pomocou shunting yard algoritmu, ktorý využíva zásobník a rad. (Zásobník a rad realizujte ako samostatnú knižnicu v separátnom súbore s hlavičkovým súborom includnutým do hlavného súboru v rovnakom duchu ako sa to realizovalo na cvičeniach. Implementáciu radu a zásobníka zvoľte podľa uváženia.)

Výstupom programu nech je výsledok vyhodnotenia výrazu a zároveň jeho prepis do reverznej poľskej notácie.

Ukážka:

/home/novotnyr> ./rpn "1 + 1"
1 1 + = 2

Ak výraz obsahuje nekorektné zátvorkovanie, vypíšte chybu “Nekorektné zátvorkovanie” (na overenie použite zásobník a kód z cvičenia, resp. znalosti z PAZ1b).

Ak výraz obsahuje nekorektné znaky, či operátory, vypíšte chybu “Nekorektný znak na pozícii X”, kde X je poradie znaku indexované od 1ky.

>> Home