Práce s ukazateli – dvourozměrné pole – úpravy 1
Procvičování práce s pamětí a vícerozměrnými proměnnými. Úpravy na C++ mechanizmy.
Zadání
Upravte program pro práci s dvourozměrným polem z minulého cvičení pomocí C++ mechanizmů:
namespace - „uložte“ své funkce ze souboru funkce2d do namespace s vaším jménem
tisk na konzolu pomocí streamů - cout
new, delete – zaměňte alokaci pomocí C-funkcí (alloc, free) za C++ mechanizmy new, delete
výjimky – ošetřete výjimky, které mohou být generovány operátory new/delete. Nahraďte chyby oznamované pomocí return, mechanizmy výjimek. Zkuste nasimulovat danou chybu a její řešení (chycení).
struct – přepište pole pomocí sjednocení parametrů dat a rozměrů za pomoci vytvoření stuktury pro 2D pole, která bude obsahovat rozměry matice iRadku, iSloupcu a data iData (+další vhodné proměnné, budou-li potřeba).
Postup práce:
Vytvořte nový prázdný projekt.
Do adresáře projektu vložte kopie souborů z minulého cvičení main2D.c, funkce2d.c, funkce2d.h a vložte je do projektu. U zdrojových souborů přejmenujte koncovku na .cpp, u hlavičkového na .hpp. Zkuste přeložit a opravte případné chyby plynoucí z rozdílu mezi jazyky C a C++.
Do projektu vložte i knihovnu check.
Pro tisk používá C++ koncepci streamů, která nahrazuje tisk
pomocí funkcí typu printf.
Místo
tisku pomocí printf
použijte v tomto projektu tisk pomocí streamu cout.
Vyměňte všechny printf
(pouze v souboru funkce2d.cpp)
za cout a zkuste
přeložit. Ke správné funkci musíte naincludovat knihovnu iostream.
Dále je nutné si uvědomit, že proměnné cout,
cerr (standardní výstup a standardní chybový výstup) a
manipulátor endl
(odřádkuje a vytiskne výstupní text na konzolu) jsou v prostoru std.
Proto je nutné je „zpřístupnit“ pomocí direktivy using.
Zpřístupněte je jednotlivě (using
pro každou z proměnných cout,
cerr, endl). Přeložte a zkontrolujte zda je tisk v pořádku.
Vyměňte obsah souboru main2d.cpp
za přiložený zdrojový text. V následujících
krocích se postupně snažte upravit své soubory (funkce2d.h
a funkce2d.cpp) tak, aby
fungovaly s přiloženým zdrojovým textem pro main2d.cpp.
Odlaďujte postupně, tím že budete odstraňovat komentáře.
Jelikož
chyby jsou signalizovány pomocí typu enum, vložte do souborů
funkce2D (rozhodněte co
do hlavičkového a co do zdrojového) projektu následující kód:
extern
const
char
*MatrixErrorStr[];
#define
TOSTR(a)
(#a)
const
char *MatrixErrorStr[]
= { TOSTR(EOk),
TOSTR(EWrongSize),
TOSTR(ENoMemory),
TOSTR(ENotAllocated),
TOSTR(EAlreadyAllocated)
};
Pomocí klíčového slova typedef
můžeme vytvořit nový datový typ z již stávajícího.
Vyměňte
definici MUJTYP z
minulého cvičení za příkaz typedef
double TType;. Všechny výskyty MUJTYP
přejmenujte na TType.
Při práci v týmu, nebo na větších projektech je výhodné
oddělit funkce (na základě autorů nebo společné činnosti) pomocí
jmenných prostorů.
Vytvořte jmenný prostor pro funkce ze souboru
funkce2D se jménem
Matrix. Nejprve vložte
do jmenného prostoru deklarace nacházející se v hlavičkovém souboru
a přeložte (= nadefinujte v hlavičkovém souboru jmenný prostor
daného jména a do jeho těla vložte obsah původního hlavičkového
souboru (mimo ošetření vícenásobného načtení)).
Následně
přiřaďte do jmenného prostoru Matrix
i zdrojové funkce v souboru funkce2D.cpp.
Funkci transpose_matrix
přiřaďte do jmenného prostoru Matrix
pomocí operátoru příslušnosti a jména prostoru, ostatní funkce
vložte pomocí namespace {}
(stejně jako v hlavičkovém souboru).
Přístup k proměnným v
modulu main je plným názvem Prostor::jmeno.
Zapněte část
programu, vyřazenou pomocí podmíněného překladu tak, že vyměníte #if
0 za #if 1.
Jazyk C++ používá k práci s pamětí klíčová slova new
a delete, které
nahrazují původní funkce typu malloc
a free.
Nahraďte
alokaci a odalokaci novými mechanizmy – new
a delete. Pro pole je
nutné použít „polní“ operátory new
[] a delete [].
Pro ošetření chyb se v jazyce C++ kromě návratových hodnot
funkcí používá mechanizmus výjimek.
Přepracujte předávání chyb
na mechanizmus výjimek.
Všechny funkce z modulu funkce2D
(mimo „lokálních“ static funkcí) budou vracet chyby
pomocí výjimek. Jelikož výjimky „jdou mimo“ parametrů
funkcí, budou nyní funkce vracet typ void – přepište prototypy
funkcí tak, aby vracely void.
Tímto krokem „přestanou
fungovat“ returny (nepůjdou přeložit). Místo returnů nyní
musíme vygenerovat chybu typu výjimka. Pro výjimku využijeme
stávající návratové hodnoty (a jejich typ). Výjimku vygenerujeme
pomocí klíčového slova throw (kterým nahradíme stávající return).
Výjimky jsou generovány i při použití operátoru new při
alokaci.
Kód pro alokaci s ošetřením chyb pomocí výjimek může
vypadat například tak jak je uvedeno níže.
Pokud generujeme
výjimku, je nutné označit blok, ve kterém se má ošetřit –
tento blok začíná klíčovým slovem try
a za blokem následuje sekce bloků uvozených příkazem catch.
Operátor new generuje
standardní výjimku bad_alloc
(knihovna <new>).
Pro výjimky vašeho programu budou použit typ enum.
Všimněte si,
že kód pro výjimky byl v modulu main2d
již přítomen, aniž bychom výjimky generovali.
V modulu main
zkuste zda mechanizmus výjimek funguje.
try
{
mat = new TType*[aY];
for(y = 0; y < aY; ++y)
mat[y] = new TType[aX];
}
catch(std::bad _alloc)
{
if(mat)
deallocate(mat, y - 1);
throw(ENoMemory);
}
„Přesuňte“ matici do struktury – vytvořte
(v hlavičkovém souboru) definici struktury TMatrix.
Struktura TMatrix bude
mít dvě proměnné typu unsigned:
iRadku a iSloupcu
a proměnnou typu TType** iData
pro uložení dat (+další proměnné, které budete potřebovat pro
správný chod programu).
Přepište program tak, aby všechny
matice, které se skládaly ze tří proměnných (data, rozměry), byly
nahrazeny daty v této struktuře. Funkce allocate_matrix
a deallocate_matrix
neměňte (slouží obecně pro práci s 2D polem bez návaznosti na
strukturu, která je „vyšší“ proměnnou).
Program
odlaďte – zakomentujte funkci main a postupně odkomentovávejte
jednotlivé řádky a za současné změny příslušných funkcí na parametr
typu struktura TMatrix.
Strukturu je vhodné předávat pomocí ukazatele.
Poslední změna 2014-10-13