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 základní funkce pro práci s dvourozměrnými maticemi realizující následující činnosti (kapitola 5.2.24). Pole realizujte jako dynamické (má možnost měnit svoji velikost => je realizováno pomocí ukazatelů a následně alokací paměti až za chodu programu (na rozdíl od statického pole, které má dán pevný rozměr při překladu)).
Naalokování dvourozměrného pole (matice) s inicializací všech prvků na danou hodnotu (můžete zkusit více způsobů vracení - jako parametr, nebo návratová hodnota ...)
výpis (tisk) dvourozměrného pole (matice) na konzolu
rozdíl odpovídajících si prvků matic (cij = aij - bij)
transpozici matice
odalokování dvourozměrného pole (matice)
násobení matic a = b * bT
Funkce ověřte pomocí (doplnění) vzoru uvedeného na konci tohoto souboru. Řádky ve funkci main pouze upravujte, nemažte. Hlavičkový soubor vytvořte sami.
Správnost programu ověřte přidáním modulů check, kterým dosáhnete kontroly naalokované paměti a tedy i správné činnosti programu. Popis přidání do programu a funkce pro volání jsou popsány v check.h.
Krok 0: vytvoření projektu
v rámci řešení (solution) z
minulého cvičení si vytvořte nový (prázdný konzolový) projekt.
Vytvořte soubor pro funkci main. Dále soubory pro zdroje funkcí a pro
hlavičky funkcí.
V solution/properties nastavte jak startup
project tento projekt.
Krok 1: základ programu
Zkopírujte si vzor programu z
konce této stránky.
Zdrojový kód rozdělte do souboru
demonstračního (s main), zdrojového a hlavičkového souboru pro
funkce. Hlavičkový soubor ošetřete proti vícenásobnému načtení.
Přítomný zdrojový kód pro začátek zakomentujte a funkce tvořte
postupně za neustálého odlaďování. (Tento bod je vhodné spojit s
bodem následujícím).
Krok2: knihovna pro kontrolu práce s pamětí
seznamte se
s knihovnou pro kontrolu alokování paměti „check“.
Doplňte ho do projektu a zkontrolujte správnost projektu. Zkuste
nasimulovat chybový stav (například zakomentovat odalokování) a
zjistěte zda toto knihovna „check“ odhalí. Popis přidání
do programu a funkce pro volání jsou popsány v check.h, dostupné v
sekci literatura.
Krok3: práce se strukturami
přepište program tak, aby
základem práce byl typ struct
SMat. Struktura bude obsahovat rozměry matice a ukazatel na
dynamické pole. Do funkcí se tedy nebude předávat pole jako ukazatel
a rozměry, ale pouze jako struktura (která tato data obsahuje).
Ve
funkci main též demonstrujte, že v případě rozdílných rozměrů matic
se neprovedou funkce, které vyžadují aby matice měly stejný tvar
(chybu řešte tiskem hlášení na konzolu).
(související kapitoly skript:
kapitola 5.2.24 – dvourozměrná pole – základní práce
kapitola 5.2.18 – ukazatel a pole – použití ukazatele pro práci s polem
kapitola 5.2.17 – ukazatel a funkce – jak předávat paměťové odkazy z a do funkce
kapitola 5.2.16 – dynamická paměť – jak získat a vrátit paměťový blok
kapitola 5.2.15 – základní vlastnosti a práce s ukazateli)
Pozn.:
Dvourozměrné pole PPP je typu double **. To znamená, že se jedná o ukazatel na (pole) ukazatel(ů). Každý z ukazatelů v tomto poli dále ukazuje na prvky 1D pole. Pole ukazatelů je možné brát například jako pole ukazatelů na řádky (přístupné pomocí prvního indexu) a druhé indexy jako prvky v poli doublů jako pozice sloupců. Samozřejmě lze představit i „obrácenou“ variantu – zaměnit v předešlém sloupce<=>řádky.
Alokace pole tedy vypadá tak, že naalokujeme pole ukazatelů na double, které má velikost shodnou s počtem řádků/sloupců. Pro každý z prvků tohoto pole je dále naalokováno pole prvků double o délce rovné počtu sloupců/řádků.
Přístup k řádkům je PPP[i], přístup k prvkům pole (sloupci v daném řádku) je PPP[i][j] – jedná se tedy o postupnou indexaci ukazatelů.
(pozn. Zakomentované příkazy příkladu měly smysl v DOS. V příkladu mohou být drobné „testovací“ chyby, které bude nutno ve vzoru upravit.
Pro procvičení můžete nejprve zkusit překládat soubory s názvy matice.c a hlavni.c a potom v novém projektu s příponami cpp. Prostředí podle přípony volí typ překladače C/C++. Ozřejmili byste si tedy některé rozdíly mezi C a C++
V případě nejasností zkuste dotazy.
Motivační nákres situace po naalokování 2D pole
)
============= vzor pr zkopírování začátek ==================
============= pole2d.h ==============
standardní ošetření hlavičky
nadefinování typu pole #define MUJTYP double
prototypy funkcí využitých v cpp
============= pole2d.cpp ==============
MUJTYP ** Alokuj(int x,int y) { // Alokuje dvourozmerne dynamicke pole s rozměry x a y a prvky typu MUJTYP } int init_matrix (MUJTYP ***mat,int x, int y,int value) { // Dyn. alokace dvourozmern. pole velikosti x,y // s prvky nastavenymi na hodnotu value // vraci: 1 kdyz ok, 2 pokud je jiz naalokovano, jinak 0, // pokud pole existuje, pak se nealokuje a vrací se chyba // alokace pomocí volání funkce Alokuj // naplneni hodnotou return (1); // Vse je vporadku } void print_matrix (MUJTYP** mat,int x,int y) { // Vytisknuti pole mat o velikosti x,y } void rozdil_matrix (MUJTYP** mat_a,MUJTTYP** mat_b,MUJTYP *** mat_c,int x,int y) { // rozdil 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 // pokud mat_c neexistuje pak ho naalokovat // pokud mat_c má jiné rozměry, pak ho přealokovat na správný rozměr // provest rozdil } void disp_matrix (MUJTYP*** mat,int x, int y) { // Dealokace dvourozmer. pole o velikosti x,y // nastavit mat tak, aby bylo zrejme, ze je odalokovano } /* 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) void transp(MUJTYP ***mat, int x, int y) { // 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) } */ ============== hlavni.cpp ========================= #include <stdio.h> #include <stdlib.h> #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 (init_matrix (&amat,X,Y,2)==0) { printf("Nedostatek pameti.\n");return 1; } // nesmim naalokovat dvakrat if (init_matrix (&amat,X,Y,2)==0) { printf("Nedostatek pameti.\n");return 1; } if (init_matrix (&bmat,X,Y,3)==0) { printf("Nedostatek pameti.\n");return 1 ; } if (init_matrix (&cmat,X,Y,0)==0) { printf("Nedostatek pameti.\n");return 1; } amat[0][0]=4; // Pristup do pole print_matrix (amat,X,Y); print_matrix (bmat,X,Y); rozdil_matrix(amat,bmat,&cmat,X,Y); print_matrix (cmat,X,Y); // transp(&cmat); nasobeni_matrix(&amat, bmat, cmat); print_matrix (cmat,X,Y); //memory_stat(); printf("\nDealokuju.........\n"); disp_matrix(&amat,X,Y); disp_matrix(&bmat,X,Y); disp_matrix(&cmat,X,Y); disp_matrix(&cmat,X,Y); // nesmim odalokovat dvakrat // nesmim pracovat s prazdnymi (odalokovanymi) print_matrix (amat,X,Y); print_matrix (bmat,X,Y); rozdil_matrix(amat,bmat,&cmat,X,Y); print_matrix (cmat,X,Y); // transp(&cmat); print_matrix (cmat,X,Y); // musim byt schopen opetovne pouzit prazdnou promennou if (init_matrix (&amat,X,Y,2)==0) { printf("Nedostatek pameti.\n");return; } print_matrix (amat,X,Y); disp_matrix(&amat,X,Y); printf("\nKonec programu.........\n"); return 0; }
=========== konec vzoru ===============
Poslední změna 2013-10-14