IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: C++ výstupní parametr funkce = struktura

V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Dominik Baričák:15.3.2018 17:32

Zdravím,
Nedávno jsme ve škole začali brát novou věc, a já netuším, jak ji přesně chápat. Proto píši sem. Chtěl bych poradit s tím, kde bych mohl pochopit problematiku funkce s výstupním parametrem strukury. Zatím co mám učebnici a tak celkově jsem na internetu viděl i na různých tutorial pro začátečníky jen výstupní parametr int nebo void, ale tohle ne. Prosím o doporučení na nějakou stránku nebo lépe, jak se ta věc jmenuje. Například for cyklus, atd, aby mi to google byl schopný najít. Příkládám kod:

#include <sstream>
#include <iostream>
using namespace std;

struct vysledek{
int pozice;
int velikost;
};

const int VEL=10;
typedef int pole[VEL];

pole cisilka={2,4,8,1,­12,5,3,66,7,10};

vysledek najdi(pole vstup){
vysledek maximum={0,-32000};

for(int i=0;i<VEL;i++){
if(vstup[i]>m­aximum.velikos­t){
cout<<"nasel jsem nove maximum"<<endl;
maximum.velikos­t=vstup[i];
maximum.pozice=i;
}
else{
cout<<"hledame dal"<<endl;
}
}

return maximum;

}

int main()
{

vysledek data;
data=najdi(ci­silka);
cout<<"pozice max hodnoty: "<<data.pozice<<en­dl<<"hodnota: "<<data.velikos­t<<endl;

return 0;
}

Učitel nám dal také za úkol dopsat do té funkce "najdi" také výpočet pro minimum. To bych zvádl. Napsat druhou funkci, ale v jedné to nedokážu napsat, jelikož se v tom ještě neorientuju.

 
Odpovědět
15.3.2018 17:32
Avatar
Jindřich Máca
Tvůrce
Avatar
Odpovídá na Dominik Baričák
Jindřich Máca:15.3.2018 19:53

Ahoj a co na tom konkrétně nechápeš? V první řádě "problematiku funkce s výstupním parametrem strukury"; tohle není žádná problematika. Prostě máš pojem funkce a pojem struktura a používáš je dohromady. :)

  1. Musíš obecně vědět, co je funkce. S touto znalostí pak i víš, že ony můžou vracet vlastně úplně cokoliv. Např. číslo, pole, ale klidně i jinou funkci. :-` Ten princip je pořád stejný. Takže pokud umíš napsat funkci, tak pouze změníš, co vrací a hotovo.
  2. Musíš vědět, co je struktura. Mám pocit, že tady tak trochu leží ten kámen úrazu. Budu prostě citovat zdejší článek:

Jedná se o nový datový typ, který můžeme uložit do jedné proměnné, ale který uvnitř zároveň obsahuje několik prvků (někdy se mu říká záznamový typ). Vzdáleně se může podobat poli, jeho prvky ovšem nemusejí být stejného typu a místo číselně jsou pojmenované slovy.

S těmito znalostmi by neměl být problém tomu kódu výše porozumět. Takže ze všeho nejdříve se ujisti, že tyto znalosti máš, můžeš si případně projít zdejší sekci základů programování v C, a potom se třeba doptej na konkrétní věci, které Ti nebudou jasné. ;)

 
Nahoru Odpovědět
15.3.2018 19:53
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Dominik Baričák
DarkCoder:15.3.2018 20:30

To co potřebuješ vědět je znalost ukazatelů. Aby funkce mohla změnit obsah proměnné nebo objektu, je třeba předat funkci ukazatel na tento objekt. Tedy použít volání odkazem a to je pro všechny typy stejné. To použiješ i tehdy, budeš chtít, aby funkce dokázala vrátit více než jednu hodnotu. Nežli Ti doporučovat nějakou stránku, ukáži Ti to na příkladu, ze kterého bys měl vše pochopit.

Následující program naplní prvky strukturu minmax v závislosti na výsledku funkce getminmax() porovnávající dvě celá čísla. Funkce geminmax() přebírá ukazatel na strukturu a dva celočíselné argumenty.

#include <stdio.h>

void getminmax(struct sMinmax *s, int num1, int num2);

struct sMinmax {
        int min;
        int max;
};

int main(void) {
        struct sMinmax minmax;
        int x = 5, y = 10;

        getminmax(&minmax, x, y);
        printf("min = %d, max = %d\n", minmax.min, minmax.max);
        return 0;
}

void getminmax(struct sMinmax *s, int num1, int num2) {
        (num1 > num2) ? (s->max = num1, s->min = num2) : (s->max = num2, s->min = num1);
}

Za povšimnutí stojí:
Přistupuji-li k prvkům struktury pomocí ukazatele, používá se šipkový operátor.
Přistupuji-li k prvkům struktury přímo, používá se tečkový operátor.
K postupnému naplnění prvků struktury je použit čárkový operátor.

Nahoru Odpovědět
15.3.2018 20:30
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Dominik Baričák:15.3.2018 21:32

Díky moc za všechny rady, DarkCoder: Tak daleko jsem se ještě nedostal. Dám tedy ještě jednu otázku. K čemu se tedy u funkce přidává výstupní parametr typu struktura ? Pořád nemůžu pochopit, proč je to tam nacpané, když to jde udělat s ukazatelama.

 
Nahoru Odpovědět
15.3.2018 21:32
Avatar
Martin Petrovaj
Tvůrce
Avatar
Odpovídá na Dominik Baričák
Martin Petrovaj:15.3.2018 21:53

Pokiaľ správne chápem, že sa pýtaš na výhody vášho prístupu v škole oproti ukážke od DarkCodera, tak mne osobne pripadá značne čitateľnejšie

data = getminmax(4, 10);

než

getminmax(&data, 4, 10);

aj keď to je asi aj otázka osobnej preferencie.

V každom prípade, na použitie iných typov (štruktúr či objektov) než primitives ako návratových hodnôt by som si zvykal, nie vždy musíš mať "luxus" či dokonca vôľu modifikovať existujúcu premennú - môže byť immutable (príp. budeš sám chcieť, aby sa jej hodnota nemenila), v tom prípade sa ako riešenie núka vrátiť novú inštanciu ako návratovú hodnotu.
No a fajnšmekri to ešte vedia použiť aj v iných situáciách a na ďalšie srandy (aj bez nutnosti zvažovania immutability), ako je napr. fluent interface, ale to už asi ideme mimo rozsah tvojej otázky :-) V každom prípade to nie je nič zložité, funkciu vrátane hlavičky píšeš úplne rovnako, ako keby pracovala s / vracala bežný primitive typ a lá int, float, string…

Nahoru Odpovědět
15.3.2018 21:53
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
Dominik Baričák:15.3.2018 22:20

Teď už poslední otázka a přestanu klást moje nesmyslné otázky. Nebudu lhát. Většině věcem co sem píšete nerozumím :D Takže se zeptám jednoduše.

Nechápu, proč když: vysledek najdi(pole vstup){

přepíšu na:

int najdi(pole vstup){

Tak to nefunguje. Jde mi jen o tohle.

#include <sstream>
#include <iostream>
using namespace std;

struct vysledek{
int pozice;
int velikost;
};

const int VEL=10;
typedef int pole[VEL];

pole cisilka={2,4,8,1,­12,5,3,66,7,10};

vysledek maximum={0,-32000};//toto je inicializace struktury

vysledek najdi(pole vstup){

for(int i=0;i<VEL;i++){
if(vstup[i]>m­aximum.velikos­t){
cout<<"nasel jsem nove maximum"<<endl;
maximum.velikos­t=vstup[i];
maximum.pozice=i;
}
else{
cout<<"hledame dal"<<endl;
}
}

return maximum;

}

int main()
{

vysledek data;
data=najdi(ci­silka);
cout<<"pozice max hodnoty: "<<data.pozice<<en­dl<<"hodnota: "<<data.velikos­t<<endl;

return 0;
}

 
Nahoru Odpovědět
15.3.2018 22:20
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Dominik Baričák
DarkCoder:15.3.2018 22:20

Struktura je sdružený datový typ jehož použití může být velmi výhodné v mnoha případech. Struktura se používá tam, kde její prvky jsou různého typu a navzájem spolu souvisí. Představ si třeba knihu. Ta se nějak jmenuje, má nějakého autora, má číslo vydání. Všechny tyto informace spolu souvisí a vytváří tak informace o objektu. Struktura by mohla vypadat třeba následovně:

struct sKniha {
   char nazevknihy[40];
   char jmenoautora[40];
   unsigned char edice;
}

A vytvoření celého seznamu knih:

struct sKniha kniha[100];

Mít tyto data oddělené ve třech samostatných polích by nebylo příliž elegantní.

Struktura vůbec nemusí být součástí funkce. Její použítí zavisí na situaci. Je to datový typ. Kdežto použití ukazatele, což je proměnná, která v sobě nese adresu jiného objektu, je bezpodmínečné, pokud chci měnit hodnotu objektu použitého jako argument funkce.

Ukazatel na výše uvedenou strukturu jako parametr bych mohl využít např. ve funkci vytvářející nový záznam nebo editaci záznamu. Použití ukazatele na strukturu je i tak samo o sobě vhodnější než předávat strukturu funkci jako celek. Reálné struktury bývají obvykle velké a použití ukazatele je mnohem efektivnější.

Jinak slovní pojetí výstupní parametr není zrovna šťastné a nepoužívej ho. Lepší je že jako argument funkce je použit ukazatel na typ. Navíc nikde není dáno, že proměnnou, na kterou se ukazuje prostřednictvím ukazatele použitého jako argument funkce, je nutno měnit. Pouze to umožňuje.

Ještě jedna věc, neboj se učitele zeptat, pokud Ti něco není jasné. Obvykle Ti to může podat jinak, ze kterého to lépe pochopíš.

Nahoru Odpovědět
15.3.2018 22:20
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Dominik Baričák
DarkCoder:15.3.2018 22:53

To co uvedl Martin Petrovaj je další způsob jak vracet strukturu a to pomocí ukazatele na strukturu jako návratový typ. V tomto případě by prototyp funkce vypadal následovně:

struct sMinmax *getminmax(int num1, int num2);

Každopádně pokud chceš používat struktury a funkce společně a efektivně, pak ukazatele musí být tvůj nejvíc největší kamarád. :-)

Nahoru Odpovědět
15.3.2018 22:53
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Martin Petrovaj
Tvůrce
Avatar
Odpovídá na Dominik Baričák
Martin Petrovaj:16.3.2018 6:49

Ak necháme tvoju funkciu najdi tak, ako je:

vysledek najdi(pole vstup){

    for(int i=0;i<VEL;i++){
        if(vstup[i]>maximum.velikost){
            cout<<"nasel jsem nove maximum"<<endl;
            maximum.velikost=vstup[i];
            maximum.pozice=i;
        }
        else{
            cout<<"hledame dal"<<endl;
        }
    }

    return maximum;
}

A ty len zmeníš v hlavičke návratový typ na int:

int najdi (pole vstup) {
    //…

    return maximum // maximum je premenna typu vysledek (struktura)
}

tak ti program neskompiluje kvôli tomu, že tvoja funkcia vracia štruktúru, ale v hlavičke má ako návratový typ uvedené, že vracia int. Ak by si to upravil nejako takto:

int najdi(pole vstup){
    int max = -32000;

    for(int i=0;i<VEL;i++){
        if(vstup[i]>max){
            cout<<"nasel jsem nove maximum"<<endl;
            max=vstup[i];
        }
        else{
            cout<<"hledame dal"<<endl;
        }
    }

    return max;
}

tak by to už malo fungovať. Nezabudni ale, že potom ti už ďalej v programe neprejde priradenie vysledek data = najdi(cisilka), pretože tvoja funkcia najdi teraz vracia int, a ty do premennej typu vysledek len tak priradiť int nemôžeš. :-D

Tiež si všimni, že prichádzaš o možnosť získať dve návratové hodnoty - nie len najväčší prvok, ale aj jeho index (pozíciu) vo vstupnom poli. Práve kvôli tomu vám asi učiteľ tento príklad na štruktúry ukazoval, alternatívou by bolo ešte vrátiť pole intov (v tvojom prípade 2-prvkové), alebo ešte spraviť osobitnú funkciu na nájdenie indexu max. hodnoty. Potom ale asi tento príklad tak nejako stráca svoju pointu. :-)

A učiteľa sa za mňa ešte spýtaj, prečo vo funkcii najdi pracuje s premennou maximum, ktorá je definovaná mimo scope tej funkcie. Nemal by vás učiť zvykať si na používanie takýchto "globálnych" premenných.

Nahoru Odpovědět
16.3.2018 6:49
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
Dominik Baričák:16.3.2018 11:27

Díky všem za ochotnou pomoc. Teď už to chápu a budu s tím dál pracovat :)

 
Nahoru Odpovědět
16.3.2018 11:27
Avatar
Dominik Baričák:16.3.2018 12:23

Ta globál ní proměnná byla moje chyba. Dal jsem si ji nahoru pro větší přehlednost. Vím, že by se to nemělo dělat.

 
Nahoru Odpovědět
16.3.2018 12:23
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Dominik Baričák
DarkCoder:16.3.2018 17:39

Vracej ukazatel na strukturu nikoli strukturu jako celek. Předávej funkci najdi() parametr pro velikost pole. Ale hlavně uprav tu inicializaci struktury maximum, to je mnohem závažnější chyba než bezdůvodné použití globální proměnné v rámci funkce.

Nahoru Odpovědět
16.3.2018 17:39
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
B42P6
Člen
Avatar
Odpovídá na DarkCoder
B42P6:17.3.2018 11:43

Len pre zaujímavosť:

Ak nejaká funkcia vracia štruktúru, väčšina kompiler-ov to skompiluje tak, že pridá tejto funkcii "skrytý parameter" čo je ukazateľ na prázdnu štruktúru alokovanú na zásobniku volajúcej funkcie, volaná funkcia potom vráti výslednú štruktúru do tejto pamäte.
Ale, ak štruktúra nezaberá veľa pamäti, kompiler sa môže rozhodnúť vrátiť túto štruktúru cez registre v procesore, čo je rýchlejšie.

Preto si myslím, že je lepšie vrátiť štruktúru z funkcie ako celok a nechať na kompiler-i rozhodnúť sa ako ju čo najlepšie vrátiť.

Inak, súhlasím ;-) , že pre efektívne využívanie je potrebné byť veľký kamarát z ukazateľmi, napríklad pri používaní štruktúry ako argument, je omnoho, omnoho lepšie a rýchlejšie ak sa predáva len ukazateľ a nemusí sa kopírovať celá štruktúra. :)

Nahoru Odpovědět
17.3.2018 11:43
'long long long' is too long for GCC
Avatar
DarkCoder
Člen
Avatar
Odpovídá na B42P6
DarkCoder:17.3.2018 12:35

Ano, kvalitní překladače se snaží najít v kódu určitý smysl a provádí s kódem různé optimalizace. Deklarovat proměnnou jako registr umožňuje přistupovat k této proměnné nejrychleji. Z důvodu omezení registrů je ale třeba zvážit, jakou proměnnou jim přiřadím. Navíc proměnná deklarovaná jako registr nemá adresu a není tedy k ní možno přistupovat přes ukazatel. Spoléhat se na to, že za mě někdo něco udělá co mohu udělat sám, to rozhodně ne.

Nahoru Odpovědět
17.3.2018 12:35
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 14 zpráv z 14.