Ciele
- Porozumieť reprezentácii čísiel v pamäti počítača.
- Osvojiť si prácu s dvojrozmerným poľom.
- Vytvoriť vlastné funkcie podľa špecifikácie.
- Naučiť sa ukončovať funkcie pomocou rozličných návratových hodnôt pri rozličných vstupných parametroch.
QR Code
Pravdepodobne ste sa už stretli s QR kódom. Je to 2D pole určené na vizuálnu reprezentáciu údajov. QR (Quick Response) kód bol vytvorený v Japonsku v roku 1994 pre automobilový premysel. Neskôr sa rozšíril aj do iných oblastí, vrátane každodenného života.
K získaniu údajov z QR kódu je potrebné použiť skener alebo mať naištalovanú aplikáciu v telefóne, ktorá túto funkcionalitu zabezpečuje.
V tomto zadaní naštastie nebudeme programovať celú funcionalitu aplikácie, ktorá skenuje QR kód, ale na tomto kóde si ukážeme základné princípy pre prácu s 2D poľom.
QR kód pozostáva z čiernych štvorcov umiestnených v mriežke, ktoré sú na bielom pozadí. To umožnuje čitateľnosť kódu pre zariadenia ako kamera alebo nejaké špeciálne skenovacie zariadenie. My sa budeme zaujímať najmä o dátovú časť tohto kódu.
Pre uchovanie dát v QR kóde sa používajú štandardné módy, ktoré umožnujú uchovať čísla, alfanumerické znaky, binárne dáta (bajty), kanji, ale aj iné, ak sú použité rozšírenia. My budeme pracovať s binárnymi údajmi.
Vašou úlohou je naprogramovať zadanie tak, aby dokázalo konvertovať krátky text do bajtov a tie následne zoskupiť do blokov a naopak.
Pre kódovanie znakov z reťazca do binárnej sústavy používajte základnú ASCII tabuľku.
Pre uchovávanie bajtov sa budú používať polia typu bool
, kde 1 == true
a 0 == false
.
Bloky sa skladajú z vertikálne uložených bajtov. Bajty sa ukladajú postupne zľava doprava, pokiaľ to šírka bloku dovolí. Až potom sa ukladajú do nového "riadku". Index nového "riadku" pre blok má offset o veľkosti zodpovedajúcej výške bajtu (8 bitov).
Príklad
Zakódujme si reťazec "Ahoj!"
. Kódovať je potrebné týchto 6 znakov: 'A'
, 'h'
, 'o'
, 'j'
, '!'
, '\0'
. Znaky kódujeme do dvojkovej (binárnej) sústavy na základe ich hodnôt v ASCII tabuľke. Kódujeme aj terminátor, pretože tento znak má tiež svoju hodnotu v ASCII tabuľke. Hodnoty týchto znakov v ASCII tabuľke sú nasledovné:
ZNAK | Hodnota - desiatková sústava | Hodnota - dvojková sústava (8 bitov) |
---|---|---|
'A' |
65 |
01000001 |
'h' |
104 |
01101000 |
'o' |
111 |
01101111 |
'j' |
106 |
01101010 |
'!' |
33 |
00100001 |
'\0' |
0 |
00000000 |
Poznámka
Pod číslom 0
rozumieme hodnotu false
a pod číslom 1
rozumieme hodnotu true
.
A práve to bude Vašou úlohou: Na základe ASCII hodnoty znaku vypočítať, akú hodnotu má tento znak v dvojkovej sústave. Takto vznikne byte. Takže ak kódujete skupinu znakov (reťazec), generujete dvojrozmerné pole, v ktorom sa na každom riadku nachádza jeden byte.
Keď získame skupinu bajtov (viď. tabuľka), môžeme vytvoriť "bloky". Bloky majú definovaný počet stĺpcov aj "riadkov" (offset*8), a je stanovený tak, aby sa do blokov zmestili všetky znaky. Kódy znakov (bajty) sú do blokov ukladané vertikálne, najskôr zľava doprava, potom sa podľa offset-u presunieme nižšie a opäť ukladáme bajty vertikálne, zľava doprava. Ak sú k dispozícii bloky navyše, ukladáme do nich false
(kódy znaku '\0'
).
Keďže počet "riadkov" aj stĺpcov v blokoch je dopredu definovaný, povedzme, že budeme mať 2
"riadky" a 3
stĺpce. Usporiadajme si znaky nášho reťazca "Ahoj!"
v takom poradí, v akom budú ukladané do blokov:
'A' 'h' 'o'
'j' '!' '\0'
Byte každého znaku je uložený vertikálne. Takže pre 2
"riadky" (2*8) a 3
stĺpce bude reťazec "Ahoj!"
uložený do blokov nasledovne:
0 0 0
1 1 1
0 1 1
0 0 0
0 1 1
0 0 1
0 0 1
1 0 1
0 0 0
1 0 0
1 1 0
0 0 0
1 0 0
0 0 0
1 0 0
0 1 0
Pre 2
"riadky" a 4
stĺpce bude poradie znakov nasledovné:
'A' 'h' 'o' 'j'
'!' '\0' '\0' '\0'
A v blokoch budú uložené nasledovne:
0 0 0 0
1 1 1 1
0 1 1 1
0 0 0 0
0 1 1 1
0 0 1 0
0 0 1 1
1 0 1 0
0 0 0 0
0 0 0 0
1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
1 0 0 0
Úloha 1: (De)Kódovanie znaku
Vytvorte funkciu void encode_char(const char character, bool bits[8])
s dvoma parametrami:
const char character
- Znak, ktorého ASCII hodnota sa zakóduje z desiatkovej do dvojkovej (binárnej) sústavybool bits[8]
- Pole hodnôttrue
alebofalse
. Jeho veľkosť je8
, lebo každý znak je možné zakódovať na8
bitov.
Funkcia nevráti žiadnu hodnotu, ale naplní pole bits
hodnotami true
alebo false
. Pole bude obsahovať zápis ASCII hodnoty znaku character
v dvojkovej sústave. Platí, že 1 == true
a 0 == false
.
Vytvorte funkciu char decode_byte(const bool bits[8])
s parametrom:
const bool bits[8]
- Pole hodnôttrue
alebofalse
. Jeho veľkosť je8
, lebo každý znak je možné zakódovať na8
bitov.
Funkcia vráti znak, ktorý je v ASCII tabuľke zapísaný pod rovnakou hodnotou (v desiatkovej sústave), aká je zapísaná v poli bits
v dvojkovej sústave.
Príklad použitia funkcií
bool bits1[8];
encode_char('A', bits1);
for(int i = 0; i < 8; i++){
printf("%d", bits1[i]);
}
printf("\n");
// prints: 01000001
bool bits2[8] = {0,1,0,0,0,0,0,1};
printf("%c\n", decode_byte(bits2));
// prints: A
Hodnotenie
Táto úloha je za max. 3 body (každá funkcia je za max. 1.5 bodov).
Úloha 2: (De)Kódovanie reťazca
Vytvorte funkciu void encode_string(const char string[], bool bytes[strlen(string)+1][8])
s dvoma parametrami:
const char string[]
- Reťazec, ktorý je potrebné zakódovať na bajtybool bytes[strlen(string)+1][8]
- Dvojrozmerné pole, ktoré na každom riadku obsahuje 1 bajt (8 bitov)
Funkcia nevráti žiadnu hodnotu, ale naplní pole bytes
hodnotami true
alebo false
. Pole bude obsahovať zápis ASCII hodnôt znakov z reťazca string
v dvojkovej sústave vrátane terminátora. Platí, že 1 == true
a 0 == false
.
Vytvorte funkciu void decode_bytes(const int rows, bool bytes[rows][8], char string[rows])
s troma parametrami:
const int rows
- Počet riadkov poľabytes
a počet znakov reťazcastring
vrátane terminátorabool bytes[rows][8]
- Dvojrozmerné pole, ktoré na každom riadku obsahuje 1 bajt (8 bitov)char string[rows]
- Reťazec, ktorý je potrebné vytvoriť dekódovaním údajov poľabytes
Funkcia nevráti žiadnu hodnotu, ale naplní reťazec string
znakmi dekódovaním údajov v poli bytes
. Pole bytes
obsahuje na každom riadku 1 bajt (8 bitov) s hodnotami true
alebo false
, čo vyjadruje ASCII hodnotu znakov v dvojkovej sústave vrátane terminátora. Platí, že 1 == true
a 0 == false
.
Príklad použitia funkcií
char* text = "Hello, how are you?";
const int len = strlen(text);
bool bytes1[len+1][8];
encode_string(text, bytes1);
for(int j = 0; j <= len; j++){
printf("%c: ", text[j]);
for(int i = 0; i < 8; i++){
printf("%d", bytes1[j][i]);
}
printf("\n");
}
// prints:
// H: 01001000
// e: 01100101
// l: 01101100
// l: 01101100
// o: 01101111
// ,: 00101100
// : 00100000
// h: 01101000
// o: 01101111
// w: 01110111
// : 00100000
// a: 01100001
// r: 01110010
// e: 01100101
// : 00100000
// y: 01111001
// o: 01101111
// u: 01110101
// ?: 00111111
// : 00000000
bool bytes2[7][8] = {
{0,1,0,0,1,0,0,0},
{0,1,1,0,0,1,0,1},
{0,1,1,0,1,1,0,0},
{0,1,1,0,1,1,0,0},
{0,1,1,0,1,1,1,1},
{0,0,1,0,0,0,0,1},
{0,0,0,0,0,0,0,0}
};
char string[7];
decode_bytes(7, bytes2, string);
printf("%s\n", string);
// prints: Hello!
Hodnotenie
Táto úloha je za max. 3 body (každá funkcia je za max. 1.5 bodov).
Úloha 3: (De)Kódovanie blokov
Vytvorte funkciu void bytes_to_blocks(const int cols, const int offset, bool blocks[offset*8][cols], const int rows, bool bytes[rows][8])
s parametrami:
const int cols
- Počet stĺpcov pre blokyconst int offset
- Počet skupín riadkov pre bloky (upravuje počet riadkov pre bloky)bool blocks[offset*8][cols]
- Dvojrozmerné pole pre bloky s presne definovaným počtom stĺpcov a riadkovconst int rows
- Počet riadkov (dĺžka reťazca vrátane terminátora)bool bytes[rows][8]
- Dvojrozmerné pole s bajtami kódov pre znaky reťazca
Funkcia nevráti žiadnu hodnotu, ale naplní pole blocks
blokmi bajtov, ktoré obsahujú kódy jednotlivých znakov reťazca. Platí, že 1 == true
a 0 == false
.
Vytvorte funkciu void blocks_to_bytes(const int cols, const int offset, bool blocks[offset*8][cols], const int rows, bool bytes[rows][8])
s parametrami:
const int cols
- Počet stĺpcov pre blokyconst int offset
- Počet skupín riadkov pre bloky (upravuje počet riadkov pre bloky)bool blocks[offset*8][cols]
- Dvojrozmerné pole pre bloky s presne definovaným počtom stĺpcov a riadkovconst int rows
- Počet riadkov (dĺžka reťazca vrátane terminátora)bool bytes[rows][8]
- Dvojrozmerné pole s bajtami kódov pre znaky reťazca
Funkcia nevráti žiadnu hodnotu, ale naplní pole bytes
kódmi jednotlivých znakov reťazca. Platí, že 1 == true
a 0 == false
.
Príklad použitia funkcií
int length = 4+1, cols = 3, offset = 2;
bool bytes1[4+1][8] = {
{0,1,0,0,0,0,0,1},
{0,1,1,0,1,0,0,0},
{0,1,1,0,1,1,1,1},
{0,1,1,0,1,0,1,0},
{0,0,0,0,0,0,0,0}
};
bool blocks1[offset*8][cols];
bytes_to_blocks(cols, offset, blocks1, length, bytes1);
for(int j = 0; j < offset*8; j++){
for(int i = 0; i < cols; i++){
printf("%d ", (blocks1[j][i] == true) ? 1 : 0);
}
printf("\n");
if(j % 8 == 7){
printf("\n");
}
}
// prints:
// 0 0 0
// 1 1 1
// 0 1 1
// 0 0 0
// 0 1 1
// 0 0 1
// 0 0 1
// 1 0 1
//
// 0 0 0
// 1 0 0
// 1 0 0
// 0 0 0
// 1 0 0
// 0 0 0
// 1 0 0
// 0 0 0
bool blocks2[2*8][3] = {
{0,0,0},
{1,1,1},
{0,1,1},
{0,0,0},
{0,1,1},
{0,0,1},
{0,0,1},
{1,0,1},
{0,0,0},
{1,0,0},
{1,0,0},
{0,0,0},
{1,0,0},
{0,0,0},
{1,0,0},
{0,0,0}
};
bool bytes2[length][8];
blocks_to_bytes(3, 2, blocks2, length, bytes2);
for(int j = 0; j < length; j++){
for(int i = 0; i < 8; i++){
printf("%d", bytes2[j][i]);
}
printf("\n");
}
// prints:
// 01000001
// 01101000
// 01101111
// 01101010
// 00000000
Hodnotenie
Táto úloha je za max. 5 bodov (každá funkcia je za max. 2.5 bodov).
Požiadavky pre úspešné odovzdanie zadania
- Projekt musí byť odovzdaný včas v git repozitári na adrese git.kpi.fei.tuke.sk (viď nižšie).
- Počas prekladu nemôže dôjsť ku žiadnej chybe! Projekt sa bude prekladať prekladačom
gcc
pomocou nasledovných prepínačov:
gcc -std=c11 -Werror -Wall -lm
- Vo výslednej implementácii sa nemôže nachádzať žiadna globálna premenná.
Odovzdávanie projektu
Zadanie odovzdajte do 12.12.2024 (piatok). Posledné testovanie prebehne v tento deň o polnoci.
Zadanie sa odovzdáva prostredníctvom systému na správu verzií Git na serveri git.kpi.fei.tuke.sk.
Názov Vášho projektu musí byť v tvare: zap-2024-id.
Projekt musí mať nasledujúcu štruktúru priečinkov a súborov:
.
├── ps5
│ └── qr.c
└── README
Význam jednotlivých súborov je nasledovný:
README
- Súbor, v ktorom bude uvedená Vaša skupina, ktorú navštevujete na cvičeniach:
GROUP : C1
/ps5/qr.c
- Zdrojový kód pre riešenia úloh 1-3
Upozornenie
Je dôležité, aby Vaše súbory zachovali uvedenú štruktúru. Ak sa niektorý zo súborov síce v repozitári nachádza, ale v inom priečinku, bude to považované za chybu a takýto projekt nebude považovaný za správny.
Upozornenie
Pri názvoch priečinkov, súborov a obsahu súboru README
záleží na veľkosti písmen!
Poznámka
Ak sa vo Vašom projekte budú nachádzať ďalšie súbory okrem požadovaných, ich existencia nebude považovaná za chybu.
Hodnotenie a testovanie
Za zadanie môžete získať max. 11 bodov, z toho max. 3 body za úlohy č. 1 a 2, a max. 5 bodov za úlohu č. 3. Ľubovoľné 3 body sa započítajú do zápočtu, ostatné body sa započítajú do skúšky. Počet získaných bodov sa bude odrážať od výsledku testov, ktorými Vaše zadanie úspešne prejde. Overovať sa bude:
- Štruktúra Vášho projektu (či sa v ňom nachádzajú všetky potrebné súbory).
- Funkčnosť Vašej implementácie.
Váš kód sa bude prekladať prekladačom gcc
s nasledovnými prepínačmi:
gcc -std=c11 -Werror -Wall -lm
Za chybu sa bude považovať:
- Ak vo Vašej implementácii použijete globálnu premennú.
- Ak počas prekladu dôjde ku chybe (upozornenia sú priamo konvertované na chyby).
- Ak Vaša implementácia neprejde niektorým z testov.
Testovanie Vašich riešení sa bude vykonávať automaticky každé 2 hodiny a to konkrétne o 0000, 0200, 0400, 0600, 0800, 1000, 1200, 1400, 1600, 1800, 2000 a 2200.
Vaše riešenia prejdú kontrolou originality. Preto sa pri práci na Vašom zadaní správajte podľa pravidiel etického kódexu! V prípade, že odovzdáte zadanie, ktoré nie je Vaše, môžete byť vylúčení z predmetu!