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“).

  1. 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).

  2. 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).

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. 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?

  8. 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.

  9. 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);


  10. (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