O čom je lab
Na tomto cvičení sa zoznámite so základnými nástrojmi, ktoré budete pri práci používať. Budete pracovať s prekladačom gcc a nástrojom make. Popri tom vytvoríte svoju prvú hernú pecku s názvom: Uhádni číslo, ktoré si myslím.
Ciele
- Learn to work with the gcc compiler and understand some of its switches.
- To learn how to work with the make tool and how to set it up using environment variables.
- Familiarize yourself with the basic data types of the C language.
- Learn to work with variables.
- Create simple arithmetic expressions.
- Master the functions for working with standard I/O.
- Master working with custom functions and functions that have a return value.
Postup
Krok 1: Warm up
V tomto kroku vytvoríte (svoj prvý) program v jazyku C, preložíte ho a nastavíte svoje prostredie.
Úloha 1.1
Vytvorte adresár ~/labs/lab05
, do ktorého budete ukladať svoje kódy programov v jazyku C.
Môžete použiť nasledujúce príkazy:
ls
listuje obsah adresáramkdir nazov
vytvorí nový adresárcd nazov
zmení aktuálny adresár na iný (podadresár)cd ..
zmení aktuálny adresár na nadradený adresárrmdir nazov
zmaže adresár (pre prázdny adresár)rm -r nazov
zmaže adresár (pre neprázdny adresár)
Úloha 1.2
Vo svojom obľúbenom textovom editore si vytvorte nový súbor s názvom guess.c
.
Úloha 1.3
Vytvorte program, pomocou ktorého vypíšete na obrazovku populárnu vetu: Hello world!
Riešením môže byť nasledujúci kód:
#include <stdio.h>
int main(){
printf("Hello world!\n");
return 0;
}
Úloha 1.4
Upravte program tak, aby obsahoval úvodný dialóg hry Uhádni číslo, ktoré si myslím medzi používateľom a počítačom. V tomto dialógu program vyzve používateľa, aby zadal svoj tip, ktorý od neho následne načítate v samostatnej funkcii get_guess()
. Tip vráťte ako návratovú hodnotu funkcie get_guess()
.
Tento dialóg môže vyzerať nasledovne, pričom vstup od používateľa je zvýraznený tučne a riadok začínajúci znakom $ predstavuje príkazový riadok:
$ ./guess Pick a number between 1 and 100. Your guess: 50 You have entered: 50
Riešením tohto problému môže byť nasledujúci fragment kódu:
#include <stdio.h>
int get_guess(); // function declaration
int main(){
printf("Pick a number between 1 and 100.\n");
int guess = get_guess(); // stores returned value in variable
printf("You have entered: %d\n", guess);
return 0;
}
// function definition
int get_guess(){
printf("Your guess: ");
int guess;
scanf("%d", &guess);
// returns value
return guess;
}
Úloha 1.5
Preložte svoj program a overte jeho funkcionalitu.
Pre preklad ste doteraz používali nástroj make
s pomocou súboru Makefile
. Odteraz budete používať prekladač GNU C Compiler - gcc
s nasledovnými parametrami:
gcc -std=c11 -Wall -Werror guess.c -lm -o guess
Význam jednotlivých parametrov je nasledovný:
-std=c11
Budeme používať verziu jazyka C z roku 2011-Wall
Zaujímať nás budú všetky upozornenia (warning), pretože nechceme, aby ste písali "len" kód, ktorý funugje, ale aby ste písali "dobrý kód" a prekladač vás na nič špeciálne nemusel upozorňovať (program vie fungovať aj napriek tomu, že vás prekladač niekoľkokrát upozornil)-Werror
Aby ste tieto upozornenia neignorovali, táto voľba ich všetky zmení na chyby, čím nedôjde ku vytvoreniu výsledného spustiteľného programuguess.c
Názov súboru, ktorý má byť preložený-lm
Pri preklade bude prilinkovaná aj matematická knižnica-o guess
Názov spustiteľného výsledného súboru, ktorý vznikne prekladom
Program môžete preložiť aj použitím nástroja make
, ako tomu bolo doteraz, avšak bez použitia súboru Makefile
. Všeobecná syntax použitia je nasledovná:
make guess
Poznámka
Nami poskytnutý server aj VM už majú prednastavené premenné prostredia tak, aby preklad prebehol s takými prepínačmi, aké sú popísané vyššie. Avšak v prípade, že používate vlasnú distribúciu linuxu, predvolené správanie Vám zabezpečí preklad nasledovne:
cc guess.c -o guess
Aby bolo možné dosiahnuť rovnaké správanie ako použitím prekladača gcc
, je potrebné nastaviť premenné prostredia CFLAGS
, LDLIBS
a CC
v súbore ~/.bashrc
:
export CFLAGS="-std=c11 -Wall -Werror"
export LDLIBS="-lm"
export CC=gcc
Aby sa Vaše nastavenia prejavili, bude potrebné sa najskôr odhlásiť a potom opäť prihlásiť. Prípadne skúste zadať príkaz exec bash
.
Ak sa zmeny neprejavili, premenujte súbor ~/.bashrc
na ~/.profile
a opäť sa odhláste a prihláste.
Preložený program následne spustíte z adresára, v ktorom sa nachádza:
./guess
Krok 2: The Game Continues
V tomto kroku už zostáva iba vytvoriť samotnú hru.
Pravidlá hry sú veľmi jednoduché: Počítač vygeneruje náhodné číslo z určitého rozsahu, ktoré má hráč uhádnuť. Hráč sa potom pokúša tipovať, aké číslo si počítač myslí a ten mu zakaždým povie, či je jeho číslo väčšie, menšie alebo rovné s hráčovým tipom.
Cieľom nasledujúcich úloh je precvičiť si prácu s funkciami, ktoré vedia vrátiť hodnotu, prácu so štandardným vstupom a výstupom, ako aj s jednoduchými výrazmi.
Úloha 2.1
Upravte program tak, aby vygeneroval náhodné číslo vo funkcii get_secret()
, načítal od hráča jeho tip a následne ho vyhodnotil správou na obrazovke.
Pre vygenerovanie náhodného čísla z intervalu <1, 100> v jazyku C je možné použiť nasledujúci fragment kódu:
srand(time(NULL));
int secret = (rand() % 100) + 1;
Avšak v prípade, že náhodné číslo chceme generovať v samostatnej funkcii get_secret()
(a vrátiť ho ako návratovú hodnotu), zápis bude odlišný:
int main(){
srand(time(NULL));
int secret = get_secret();
// ......
}
int get_secret(){
return (rand() % 100) + 1;
}
Navyše, jazyk C nepozná funkcie srand()
, rand()
ani time()
. Aby prekladač vedel, o aké funkcie sa jedná, importujte ich z hlavičkových súborov stdlib.h
a time.h
.
Príklad výstupu z programu je nasledovný, pričom vstup od používateľa je zvýraznený tučne a riadky začínajúce znakom $ predstavujú príkazový riadok:
$ ./guess Pick a number between 1 and 100. Your guess: 50 Hmm... My number is bigger than yours. $ ./guess Pick a number between 1 and 100. Your guess: 50 Hmm... My number is smaller than yours. $ ./guess Pick a number between 1 and 100. Your guess: 50 Congratulations! You found it!
Úloha 2.2
Upravte svoje riešenie tak, aby hráč mohol číslo hádať dovtedy, pokiaľ ho neuhádne.
Príklad výstupu z programu je nasledovný, pričom vstup od používateľa je zvýraznený tučne a riadok začínajúci znakom $ predstavuje príkazový riadok:
$ ./guess Pick a number between 1 and 100. Your guess: 50 Hmm... My number is bigger than yours. Your guess: 75 Hmm... My number is bigger than yours. Your guess: 87 Hmm... My number is smaller than yours. Your guess: 81 Congratulations! You found it!
Úloha 2.3
Obmedzte počet pokusov, ktoré môže hráč pri hádaní použiť, na 5. Ak ich vyčerpá, hráč číslo neuhádol.
V tomto momente budú existovať dva konce - úspešný a neúspešný. Úspešné ukončenie hry je rovnaké ako uvádza príklad výstupu v predchádzajúcej úlohe. Ukážka neúspešného hádania je zobrazená nižšie, pričom vstup od používateľa je zvýraznený tučne a riadok začínajúci znakom $ predstavuje príkazový riadok:
$ ./guess Pick a number between 1 and 100. You have max. 5 attempts. Your guess: 50 Hmm... My number is bigger than yours. Your guess: 75 Hmm... My number is bigger than yours. Your guess: 87 Hmm... My number is smaller than yours. Your guess: 81 Hmm... My number is bigger than yours. Your guess: 84 Hmm... My number is smaller than yours. Game over. My number was 82.
Úloha 2.4
Svoje riešenie rozšírte o zobrazenie informácie o aktuálnom čísle pokusu. Dialóg pre načítanie číselného tipu sa nachádza v samostatnej funkcii, preto je číslo pokusu potrebné odovzdať funkcii get_guess()
ako vstupný parameter.
Príklad výstupu z programu je nasledovný, pričom vstup od používateľa je zvýraznený tučne a riadok začínajúci znakom $ predstavuje príkazový riadok:
$ ./guess Pick a number between 1 and 100. You have max. 5 attempts. Your 1. guess: 50 Hmm... My number is bigger than yours. Your 2. guess: 75 Hmm... My number is bigger than yours. Your 3. guess: 87 Hmm... My number is smaller than yours. Your 4. guess: 81 Hmm... My number is bigger than yours. Your 5. guess: 84 Hmm... My number is smaller than yours. Game over. My number was 82.
Úloha 2.5
Rozšírte svoje riešenie tak, aby sa po skončení hádania hra opýtala, či si hráč chce zahrať znova. Ak áno, spustí hru znova. Ak nie, program sa ukončí.
Príklad výstupu z programu je nasledovný, pričom vstup od používateľa je zvýraznený tučne a riadok začínajúci znakom $ predstavuje príkazový riadok:
$ ./guess Pick a number between 1 and 100. You have max. 5 attempts. Your 1. guess: 50 Hmm... My number is bigger than yours. Your 2. guess: 75 Congratulations! You found it! Play again? (y/n) n See you later!
Upozornenie
Pri načítavaní znaku nezabudnite vyčistiť vstupný buffer pred aj po načítavaní vstupu od používateľa. Pred načítaním z neho odstránite znak nového riadku a po načítaní z neho odstránite znaky, ktoré sú tam navyše spolu s novým riadkom (miesto jedného znaku používateľ môže zadať aj postupnosť znakov yes). Vyčistiť buffer môžete napr. takto:
while( getchar() != '\n' )
;
Tento kód môžete oddeliť do samostatnej funkcie clear_buffer()
.
Upozornenie
Nepoužívajte nekonečný cyklus!
Úloha 2.6
Rozšírte funkciu get_secret()
o dva parametra a upravte výpočet pre generovanie náhodného čísla tak, aby bolo z intervalu daného parametrami funkcie: int get_secret(const int start, const int end)
.
Poznámka
Kľúčové slovo const
znamená, že parameter je konštanta, t.j. jeho hodnota sa v priebehu vykonávania funkcie nemení.
Krok 3: Macros
V tomto kroku upravíte Váš program tak, aby používal makrá.
Úloha 3.1
Doplňte do Vášho programu 3 makrá: START, END a ATTEMPTS.
- START Predstavuje začiatok intervalu, v rámci ktorého sa majú generovať náhodné hodnoty
- END Predstavuje koniec intervalu, v rámci ktorého sa majú generovať náhodné hodnoty
- ATTEMPTS Predstavuje celkový počet pokusov na hádanie v rámci jednej hry
Úloha 3.2
Upravte Váš program tak, aby používal vytvorené makrá.
Doplňujúce úlohy
Úloha A.1
Vytvorte program, pomocou ktorého načítate zo vstupu postupnosť čísel, pričom načítavanie ukončíte zadaním hodnoty 0. Na obrazovku vypíšte najväčšie zadané číslo, najmenšie zadané číslo, súčet všetkých zadaných čísiel a ich aritmetický priemer.
Úloha A.2
Vytvorte program, ktorý zo vstupu načíta hodnotu N
(celé kladné číslo) a na jeho základe vypíše na obrazovku Pascalov trojuholník.
Úloha A.3
Upravte program guess
tak, aby pri výzve na zadanie tipu vedel hráč zadať len čísla z uvedeného rozsahu. Ak zadá nesprávny vstup, hra ho vyzve o opätovné zadanie.
Úloha A.4
Vytvorte nový program guess_my_number
tak, aby počítač hádal číslo, ktoré si myslíte Vy ako hráč a Vy mu pomocou odpovedí (moje je väčšie/menšie/rovné) budete pomáhať. Pre realizovanie programu použite metódu Bisekcie (Bisection search, metóda delenia intervalov).
Príklad výstupu komunikácie z programu je nasledovný, pričom vstup od používateľa je zvýraznený tučne:
$ ./guess_my_number Please think of a number between 0 and 100! Is your secret number 50? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. l Is your secret number 75? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. l Is your secret number 87? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. h Is your secret number 81? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. l Is your secret number 84? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. h Is your secret number 82? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. l Is your secret number 83? Enter 'h' to indicate the guess is too high. Enter 'l' to indicate the guess is too low. Enter 'c' to indicate I guessed correctly. c Game over. Your secret number was: 83
Úloha A.5
Modifikujte program guess_my_number
nasledovne: Nech A si myslí číslo a B háda myslené číslo. Používateľ nech zadá interval, na ktorom je číslo hádané. Výstupom nech je konverzácia medzi A a B. Počítač teda bude komunikovať sám so sebou.
Úloha A.6
Zopakujte si prácu s generátorom náhodných čísel (Úloha 2.1) a naprogramujte počítadlo pre "Produkt si práve pozerá" podľa vzoru skúsených programátorov z internetu (viď obrázok). Kreativite sa medze nekladú.
Doplňujúce zdroje
- Pavel Herout: Učebnice jazyka C (1. díl) - kapitola 5.1, 5.4 a 5.5, 9.2
- Funkcia
printf()
: c-reference, cplusplus.com - Loads the data from the given locations, converts them to character string equivalents and writes the results tostdout
. - Funkcia
scanf()
: c-reference, cplusplus.com - Reads data from stdin, interprets it according to format and stores the results into given locations. - Funkcia
getchar()
: c-reference, cplusplus.com - Reads the next character fromstdin
. - Funkcia
srand()
: c-reference, cplusplus.com - Seeds the pseudo-random number generator used byrand()
with the value seed. - Funkcia
rand()
: c-reference, cplusplus.com - Returns a pseudo-random integral value between 0 and RAND_MAX (0 and RAND_MAX included). - Funkcia
time()
: c-reference, cplusplus.com - Returns the current calendar time encoded as atime_t
object. - Clearing the input buffer in C