Struktura – komplexní čísla
Komplexní číslo patří ke složitějšímu datovému typu – skládá se ze dvou složek : Imaginární a Reálné (lze použít i dvojici amplituda a úhel, přístup k programování je zde stejný). Pro práci s proměnnými, které se skládají z více proměnných slouží datový typ struktura. Definicí struktury „vznikne“ nový datový typ jeho název je „struct Jmeno“ (to znamená, že stejně jako jsme používali typ int nyní můžeme (na místo int) psát „struct Jmeno“).
Vytvořte projekt se soubory main.c (zde naprogramujte funkci main), komplex.c a komplex.h. Soubor komplex.h ošetřete proti vícenásobnému načtení (podmíněný překlad) a hlavičkový soubor vložte do obou zdrojových souborů (*.c).
V souboru komplex.h bude vše co při kompilaci nevytváří přímý kód (prototyp struktury, funkcí, …) v souboru komplex.c bude to co tvoří kód (funkce s tělem, definice proměnných).
Navrhněte a naprogramujte strukturu TKomplex, která má dvě složky – iRe, iIm. Pro složky zvolte vhodný datový typ. Popis struktury umístěte do hlavičkového souboru komplex.h. Ve funkci main nadefinujte dvě proměnné typu struct TKomplex s názvy aa, bb, a dva ukazatele na typ struct TKomplex s názvy pa, pb.
Proměnnou aa inicializujte přímo v definici na hodnotu {1.1, 2.2}. Hodnoty proměnné bb nastavte/inicializujte pomocí samostatných přiřazovacích příkazů (přiřazení pomocí operátoru = pro jednotlivé složky struktury) na hodnotu {3.3, 4.4}. Ukazatel pb nastavte tak, aby ukazoval na proměnnou bb.
Ve funkci main vytiskněte proměnné aa a bb ve formátu “(1.1+2.2i)“ (shodnotami pro proměnnou aa). Vytiskněte i druhou proměnnou bb, ale tentokrát pomocí ukazatele pb (z předchozího bodu), který na ni ukazuje.
a) Napište funkci Print
pro tisk (struktury) komplexního čísla ve formátu z minulého bodu.
Proměnnou předejte hodnotou jako jediný parametr funkce Print,
tj. struct
TKomplex.
Protože
funkce pro tisk nemění proměnnou (a ani by ji z podstaty chápání
tisku měnit neměla), je vhodné u typu parametru použít modifikátor
const, tedy : const
struct TKomplex aVal. Uvedení modifikátoru const
má význam pro programátora, neboť překladač provede kontrolu, zda se
parametr v těle skutečně nemodifikuje. V případě pokusu o změnu
proměnné zahlásí překladač při překladu chybu.
Funkci rozšiřte o
další parametr typu řetězec, který se vytiskne předtím, než se
vytiskne číslo (v tomto řetězci může být například komentář “Soucet
cisel je:˽“).
Nebude-li text požadován, použijte při volání hodnotu NULL, a ve
funkci tento stav ošetřete.
b) (DU) Napište druhou funkci pro
tisk PrintP tak, aby byl
parametrem ukazatel tj. struct
TKomplex*. Přidáme-li proměnnou pro počet prvků aLen,
můžeme tuto funkci použít nejen pro tisk jedné proměnné, ale i pro
tisk polí (prvky vytištěné podle příkladu 4 oddělené (napříkald)
mezerou).
int PrintP(const
struct TKomplex
*aData, unsigned aLen, char *aTxt)
Podobně jako u předání
hodnotou je možné označit modifikátorem const
i hodnoty předávané pomocí ukazatele:
const
struct TKomplex* const. (blíže viz. bod 6)
c) Srovnejte
výhody a nevýhody předání strukutry pomocí hodnoty a pomocí
ukazatele.
Napište funkci int
SwapParts(const struct TKomplex * const aIn, struct TKomplex * const
aOut).
Struktura
představuje tzv. složený datový typ. Jeho velikost je tedy závislá
na počtu a velikosti všech složek. Při předávání hodnotou dochází ke
kopírování celé struktury do paměťové oblasti zásobníku, což
představuje časově a paměťově náročnou operaci. Abychom se těmto
operacím vyhnuli, je vhodné zvážit, zda nepředat do funkce jako
parametr pouze ukazatel na již existující strukturu. Parametr aIn
představuje neměnný
ukazatel na neměnnou hodnotu vstupního komplexního čísla a parametr
aOut
představuje neměnný
ukazatel na výstupní hodnotu typu struct
TKomplex.
Funkce uloží vstupní komplexní číslo do výstupního
tak, že jeho složky budou vyměněny iIm<=>iRe
(oproti původní proměnné).
Pozn.: Zkuste volání se stejnou
proměnnou pro oba parametry tj. SwapParts(&a,
&a) – v čem může být problém?
Využití ukazatelů v parametruch ovšem vyžaduje kontrolu hodnot ukazatelů na NULL. Doplňte tyto kontroly do těla funkce a zajistěte navrácení chybové hodnoty.
Napište funkci struct TKomplex Add(const struct TKomplex aVal1, const struct TKomplex aVal2), která sečte dvě komplexní proměnné a výsledek vrátí jako návratovou hodnotu. Jelikož je výsledkem proměnná jejíž prvky jsou různé od existujících proměnných, musí pro ni vzniknout nová proměnná.
Ve funkci main
nadefinujte pole komplexních čísel struct
TKomplex (délka pole bude zadána pomocí makra #define
N 10. Prvky pole naplňte v cyklu hodnotami iRe
= (i-5)*(i-5); Imag = i;, kde i se mění od 0 do N.
Napište funkci Sort,
která seřadí pole komplexních čísel aValues
o délce aLen
na základě jejich velikosti (velikost komplexního čísla je
definovaná jako odmocnina ze součtu kvadrátů složek).
int
Sort(struct TKomplex aValues[], const unsigned aLen).
Pozn.
K řazení je možné využít knihovní funkce qsort
(vyžaduje hlavičkový soubor stdlib.h).
Ošetřete
chyby vzniklé zadáním špatných hodnot u obou parametrů funkce
Sort.
Původní
a seřazené pole vytiskněte pomocí funkce Print
(PrintP).
DU:
Promyslete situaci, kdy by pro výsledné setříděné pole měla být
použita nová proměnná. Bylo by tedy nutné pro výsledné pole
naalokovat místo a předat ho zpět do volající funkce. Zhodnoťte
vhodnost následujících hlaviček funkce k tomuto účelu? Promyslete i
volání těchto funkcí včetně definice proměnných (a nutnost
odalokovat naalokovanou paměť).
struct
TKomplex* Sort(const struct TKomplex *aData, int aLen);
struct
TKomplex* Sort(const struct TKomplex aData[], int aLen);
struct
TKomplex Sort(const struct TKomplex *aData, int aLen);
struct
TKomplex Sort(const struct TKomplex aData[], int aLen);
int
Sort(const struct TKomplex *aData, int aLen,
struct TKomplex *aOut);
int Sort(const struct TKomplex aData[],
int aLen,
struct TKomplex aOut[]);
int Sort(const struct TKomplex aData[],
int aLen,
struct TKomplex *aOut);
int Sort(const struct TKomplex aData[],
int aLen,
struct TKomplex **aOut);
(DU) Pro funkci Add je možné volit různá řešení parametrů.
Promyslete jednotlivé následující typy volání, z nichž pomocí všech
je možné požadovanou funkci splnit. Srovnejte jednotlivá řešení z
ohledem na velikost použité paměti při předávání parametrů a způsobu
naprogramování. Nezapomeňte uvažovat i volání funkcí včetně definice
použitých proměnných. Diskutujte ne/výhodnost řešení používajících
dynamickou alokaci paměti.
(Těla funkcí jsou pouze náznakem).
struct TKomplex Add(struct TKomplex s1,struct TKomplex
s2)
{
struct TKomplex pom;
return pom;
}
struct TKomplex Add(struct TKomplex *s1,struct TKomplex
*s2)
{
struct TKomplex pom;
return pom;
}
struct TKomplex* Add(struct TKomplex s1,struct TKomplex
s2)
{
struct TKomplex *pom = malloc();
return pom;
}
struct TKomplex* Add(struct TKomplex *s1,struct TKomplex *s2)
{
struct TKomplex *pom = malloc();
return pom;
}
int Add(struct TKomplex *s1,struct TKomplex *s2,struct TKomplex
*s3)
{
return 0;
}
int Ukazatele3(struct TKomplex *s1,struct TKomplex *s2,struct
TKomplex **s3)
{
*s3 = malloc();
return 0;
}
Poslední změna 2015-04-30