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.

Člen

Zobrazeno 14 zpráv z 14.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
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.
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é.
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.
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.
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…
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 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]>maximum.velikost){
cout<<"nasel jsem nove maximum"<<endl;
maximum.velikost=vstup[i];
maximum.pozice=i;
}
else{
cout<<"hledame dal"<<endl;
}
}
return maximum;
}
int main()
{
vysledek data;
data=najdi(cisilka);
cout<<"pozice max hodnoty:
"<<data.pozice<<endl<<"hodnota:
"<<data.velikost<<endl;
return 0;
}
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íš.
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.
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š.
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.
Díky všem za ochotnou pomoc. Teď už to chápu a budu s tím dál pracovat
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.
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.
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.
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.
Zobrazeno 14 zpráv z 14.