Práce s ukazateli – dvourozměrné pole
Procvičování práce s pamětí a vícerozměrnými proměnnými.
Zadání
Napište program, který bude realizovat základní práci s dvourozměrným (2D) dynamickým polem (=oba dva rozměry pole lze v během programu měnit => základem pole je TYP ** (např. double**)).
Implementujte funkce:
Vytvoření - naalokování dvourozměrného pole (matice) daných rozměrů (pole vrací v návratové hodnotě).
Inicializaci – naalokování dvourozměrného pole (pomocí funkce z minulého bodu) s inicializací všech prvků na danou hodnotu (můžete zkusit více způsobů vracení vytvořeného pole - jako parametr, nebo návratová hodnota …).
Zrušení - odalokování dvourozměrného pole (matice), s označením, že dané pole je prázdné.
Výpis - tisk dvourozměrného pole (matice) na konzolu ve
formátu („jako MATLAB“)
Sloupců x Řádků (nebo text
„nealokováno“)
[první řádek (prvky odděleny mezerami)
;
druhý řádek ;
…]
součet – napište funkci pro součet hodnot dvou matic a výsledek uložte do třetí (nové) matice.
Pro pokročilé:
napište funkci pro přidání řádku matici
napište funkci pro přidání sloupce matici
napište funkci pro transpozici matice
napište funkci pro násobení matic a = b * bT
Těla funcí doplňte do vzoru uvedeného na konci tohoto souboru. Řádky ve funkci main pouze upravujte, nemažte. Hlavičkový soubor vytvořte sami.
Korektnost manipulace s pamětí v programu ověřte přidáním modulů knihovny check, který zajistí tisk informací o naalokované paměti a tedy informaci o správné činnosti programu. Popis přidání modulu do programu a funkce pro volání jsou popsány v souboru check.h.
Postup práce:
Vytvořte nový prázdný projekt.
Vytvořte soubor main2D.c, funkce2d.c, funkce2d.h a vložte je do projektu.
Do souborů vložte odpovídající část připraveného kódu z konce této stránky.
Zkuste přeložit a upravte případné chyby (provádějte pouze
opravy chyb, nevytvářejte nový program). V rámci tohoto bodu můžete
zkusit napsat chybnou alokaci/odalokaci a vyzkoušet funkci knihovny
check.
- Překlad začněte tak, že se přepnete do souboru
funkce2D.c a podíváte se, kde jsou hlášeny chyby. Překlad pouze
tohoto modulu je možný pomocí volby BUILD/COMPILE (CTRL+F7).
-
Do souboru funkce2D.c přidáte include souboru funkce2d.h, který je
zatím prázdný.
- Na základě popisu (zdrojový kód níže) co patří
do hlavičkového souboru, v něm vytvořte typ MUJTYP, a enum pro kódy
chyb. Hlavičkový soubor ošetřete proti vícenásobnému načtení.
Zároveň si připravte i formátovací řetězec pro tisk, který bude
příslušný k typu nadefinovanému v MUJTYP. Nyní by měl jít modul
funkce2D.c bez problémů zkompilovat → měl by být správný z
hlediska jazyka C (ne však funkce, protože těla funkcí jsou
prázdná).
- Nyní přeložte celý projekt (nebo zkompilujte
main2d.c). Zjistíme, že opět musíme naincludovat hlavičkový soubor
funkce2D.h, ve kterém jsou používané definice.
- Jelikož máme
přípony souborů .c, překládá se podle jazyka C. Výsledkem tedy je,
že překlad proběhne, i když překladač „nezná“ prototypy
funkcí. Pouze nahlásí warningy. Toto řešení je ovšem špatné a tak
musíme warningy odstranit. To uděláme tím, že hlavičky funkcí ze
souboru funkce2D.c překopírujeme do souboru funkce2d.h a tím
oznámíme prototypy funkcí, které jsou v tomto souboru. Do
hlavičkového souboru nedáváme prototypy funkcí static – ty
jsou lokální pro daný soubor – jsou to funkce pomocné, které
nejsou určené k všeobecnému použití.
Všude, kde se vyskytuje typ uložený v poli, používejte zástupný typ MUJTYP (pomocí #define). Tam kde je stejný typ, ale nemá spojitost s prvky pole používejte standardní název typu.
Postupně začněte vypracovávat těla metod. Motivační obrázek
pro „tvar“ 2D pole v paměti a návaznosti je uveden
níže.
Uvažujte jaké chyby mohou nastat. Každá metoda by měla mít
tři (hlavní) části:
- test zda parametry jsou v pořádku, že
obsahují data, jsou vhodná pro výpočet a že výpočet je s nimi možné
provést
- vlastní výpočet
- test kvality výpočtu/výsledku -
pokud výsledek nelze určit, není správný nebo je "nekvalitní",
nastavte výstup, nebo výstupní proměnnou tak, aby ostatní funkce
věděly, že tato proměnná není vhodná k následujícím výpočtům.
Seznamte se s knihovnou check a připojte ji k projektu. Doplňtě ji (pomocí posledního inlcude v modulu) do všech zdrojových souborů (*.c).
Navrhněte testovací volání funcí (některá volání jsou již uvedena; nezapomeňte okomentovat proč tam jsou, jaký stav mají za úkol testovat).
Motivační nákres situace po naalokování 2D pole
)
============= vzor pro zkopírování - začátek ==================
============= funkce2d.h ==============
Standardní ošetření hlavičky.
Nadefinování typu pole pomocí define nebo typedef:
#define
MUJTYP double
Nadefinování řetězce pro tisk definované proměnné příslušný k
MUJTYP:
#define MUJTYP_PRINTF
“%.2f“
Pro vracené chyby vracejte kódy pomocí typu enum:
enum
TMatrixError
{
EOk = 0, EWrongSize, ENoMemory, ENotAllocated, EAlreadyAllocated};
Prototypy funkcí využitých v c
============= funkce2d.c ==============
static MUJTYP** allocate(unsigned aX, unsigned aY)
{
MUJTYP **mat;
// Alokuje dvourozmerne dynamicke pole s rozměry x a y a prvky typu MUJTYP
// if() return(NULL); // nepodaril se naalokovat vektor ukazatelů
// if() { return(NULL);} // nepodarilo se naalokovat nektery z vektoru hodnot (radek)
return(mat); // naalokovana matice
}
static void deallocate(MUJTYP **aMat, unsigned aY)
{
// vlastni odalokovani 2D pole s nastavenim hodnoty pole tak,
// aby bylo jasne, ze je odalokovano
}
static void fill(MUJTYP **aMat, unsigned aX, unsigned aY, MUJTYP aValue)
{
// naplnění matice hodnotou
}
enum TMatrixError allocate_matrix(MUJTYP ***aMat, unsigned aX, unsigned aY, MUJTYP aValue)
{
// Dyn. alokace dvourozmern. pole velikosti x,y
// s prvky nastavenymi na hodnotu value
// vraci: 1 pokud je jiz naalokovano, jinak 0 (OK),
// pokud pole existuje, pak se nealokuje
// alokace se provede pomocí volání funkce Alokuj
// pokud dojde k chybě při alokaci, vrací se kód 2
// následně se provede naplneni hodnotou pomocí funkce fill_value
// if() return(EAlreadyAllocated); // jiz naalokovano
//if()return(EWrongSize); // nektery ze zadanych rozmeru je spatny (nula)
//if()return(ENoMemory); // funkci Allocate se nepodarilo naalokovat pamet
return(EOk); // Vse je v poradku
}
enum TMatrixError print_matrix(MUJTYP** aMat, unsigned aX, unsigned aY)
{
// Vytisknuti pole mat o velikosti x,y
// if() {return(EOk);} // matice je prazdna pouze tisk oznameni
//if() return(EWrongSize); // nektery ze zadanych rozmeru je spatny (nula)
return(EOk);
}
enum TMatrixError add_matrix(MUJTYP** aMat_a, unsigned aX_a, unsigned aY_a, MUJTYP** aMat_b, unsigned aX_b, unsigned aY_b, MUJTYP ***aMat_c, unsigned *aX_c, unsigned *aY_c)
{
// soucet matic (po prvcich) mat_c=mat_a + mat_b o velikosti x,y
// kontrola zda jsou mat_a, mat_b a mat_c stejnych rozmeru – chyba kód 1
// kontrola „smysluplnosti“ parametrů (mat_a a mat_b musí být naalokovány) – chyba kód 2
// pokud mat_c neexistuje pak ho naalokovat
// pokud mat_c má jiné rozměry, pak ho přealokovat na správný rozměr
// provest součet
// if()return(ENotAllocated); // nektera z matic je prazdna (nenaalokovana)
// if( ) return(EWrongSize); // nektery ze zadanych rozmeru je spatny (nula) – staci u jedne matice + další radky
// if () return(EWrongSize); // matice nemaji stejny rozmer y
// if () return(EWrongSize); // matice nemaji stejny rozmer x
return(EOk);
}
enum TMatrixError deallocate_matrix(MUJTYP*** aMat, unsigned aX, unsigned aY)
{
// Dealokace dvourozmer. pole o velikosti x,y
// nastavit mat tak, aby bylo zrejme, ze je odalokovano
// provede se pomocí volání funkce Odalokuj
return(EOk);
}
// ======================= pro pokročilé ===========================
/* tuto funkci muzete odladit az v ramci implementace struktur
v pripade, ze ji budete odladovat bez structur, je potrebne upravit parametry
funkcí volanych pro transponovane promenne ve funkci main (nevyhoda reseni dat a rozmeru samostatne)
*/
enum TMatrixError transpose_matrix(MUJTYP ***aMat, unsigned *aX, unsigned *aY)
{
// transpozice matice
// naalokovani pomocne transponované matice - Alokuj
// prekopirovani hodnot do nove matice
// odalokovani stare matice - disp_matrix
// presmerovani nove matice do stare (pomoci prirazeni ukazatele)
return(EOk);
}
============== main2d.c =========================
#include <stdio.h>
#include <stdlib.h>
// hodnoty rozmeru pole pro uvodni ladeni
// pro dalsi ladeni zkuste matice ruznych rozmeru
#define X 5
#define Y 6
int main(int argv, char *argc[])
{
MUJTYP **amat = NULL;
MUJTYP **bmat = NULL;
MUJTYP **cmat = NULL;
printf("\nAlokuju.........\n");
if(allocate_matrix(&amat, X, Y, 2) != EOk)
{ fprintf(stderr, "Nedostatek pameti.\n"); return 1; }
// nesmim naalokovat dvakrat
if(allocate_matrix(&amat, X, Y, 2) != EAlreadyAllocated)
{ fprintf(stderr, "Nefunguje test na opakovanou alokaci.\n"); return 1; }
if(allocate_matrix(&bmat, X, Y, 3) != EOk)
{ fprintf(stderr, "Nedostatek pameti.\n"); return 1; }
if(allocate_matrix(&cmat, X, Y, 0) != EOk)
{ fprintf(stderr, "Nedostatek pameti.\n"); return 1; }
amat[0][0] = 4; // Pristup do pole
unsigned int cX = X, cY = Y;
print_matrix(amat, X, Y);
print_matrix(bmat, X, Y);
add_matrix(amat, X, Y, bmat, X, Y, &cmat, &cX, &cY);
print_matrix(cmat, cX, cY);
transpose_matrix(&cmat, &cX, &cY);
// nasobeni_matrix(&amat,&nX,&nY, bmat,X,Y, cmat,Y,X);
print_matrix(cmat, cX, cY);
//memory_stat();
printf("\nDealokuju.........\n");
deallocate_matrix(&amat, X, Y);
deallocate_matrix(&bmat, X, Y);
deallocate_matrix(&cmat, cX, cY);
deallocate_matrix(&cmat, cX, cY); // nesmim odalokovat dvakrat
// nesmim pracovat s prazdnymi (odalokovanymi)
print_matrix(amat, X, Y);
print_matrix(bmat, X, Y);
add_matrix(amat, X, Y, bmat, X, Y, &cmat, &cX, &cY);
print_matrix(cmat, cX, cY);
//transpose_matrix(&cmat, &cX, &cY);
print_matrix(cmat, cX, cY);
// musim byt schopen opetovne pouzit prazdnou promennou
if(allocate_matrix(&amat, X, Y, 2) != EOk) { printf("Nedostatek pameti.\n"); return; }
print_matrix(amat, X, Y);
deallocate_matrix(&amat, X, Y);
printf("\nKonec programu.........\n");
return 0;
}
=========== konec vzoru ===============
Poslední změna 2014-10-09