Diskuze: Kedy sa tie pointre pouzivaju?
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Tvůrce

Zobrazeno 13 zpráv z 13.
//= 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.
Abys pochopil, kde se používají, musíš nejdřív vědět, co to pointer je. Když to víš, nemělo by být těžký představit si, kde a na co se používají.
Pointer je ukazatel někam do paměti. Např. na zásobníku se alokuje paměť pro hlavní funkci (main). Zde se vytvoří proměnné a volají se další funkce. Ty další funkce mají taky nějakou svou paměť. Potřeboval bys třeba seřadit pole, které si vytvořil ve funkci main. Pole se uložilo v zásobníku, ale kdybys ho měl předávat nějaké jiné funkci (např. serad_pole), bylo by nejspíš dost neefektivní, kopírovat celé pole do paměti funkce a pak zase zpět do main. Udělá se to jinak. V main funkci serad_pole předáš pouze odkaz na to, kde je pole umístěno v paměti. Daná funkce pak může pracovat přímo s originálním polem v main.
Dalším příkladem je třeba samotné pole. I to je pointer. pole[1] je v podstatě ekvivalent *(pole+1), jelikož položky pole jsou v paměti uloženy za sebou, takže tímto zápisem se posuneš v paměti o daný datový typ na další index pole. Pak se taky používají pro práci s dynamickou pamětí, kde se v podstatě jen odkazuješ na haldu a ke všem proměnným tam přistupuješ pomocí pointeru.
Úplně nejjednodušší použití je třeba když si vytvoříš ve funkci
main proměnnou a chceš jí používat i v další funkci aniž by proměnná
byla globálního typu. Vytvoříš si na proměnnou pointer, který budes
používat v další funkci například... ale myslím že Drahoš to řekl dost
pochopitelně.
Ještě zajímavější je, když z main zavoláš nějakou funkci, která alokuje v paměti pole a naplní hodnotami. Pointer pak vrátí jako výsledek funkce. Tento pointer pak předáš jako parametr další funkci, která s tím polem má dál pracovat.
Každým program používá takzvaný zásobník, což je část paměti, která je neustále hezky srovnaná, takže je to rychlejší, než zbytek paměti, ale je malá a hlavně co na zásobníku v nějaký funkci vytvoříš, to se zase musí ze zásobníku odstranit, když tu funkci opouštíš.
Když alokuješ nějakou paměť dynamicky, tak ji můžeš mít alokovanou dokud ji neuvolníš, ale nikdy předem nevíš adresu, která zrovna bude volná, proto vždy jen při alokaci dostaneš ukazatel na místo, které alokátor našel a bylo volné.
Typicky se na zásobník ukládají parametry funkcí, takže když třeba zavoláš funkci SeradPole
int length = 100;
int * poleCisel;
poleCisel=(int *) malloc(length*sizeof(int)); // alokováno dynamicky - na haldě (heap)
SeradPole(poleCisel, length);
(která je definovaná takhle)
int SeradPole(int * poleCisel, int length)
{
...
}
tak se na zásobník uloží kopie adresy poleCisel a kopie obsahu proměnné length a provede se zavolání funkce SeradPole, která s nima něco provede a nakonec si je pak zase ze zásobníku odebere (resp. jen posune ukazatel na vrchol zásobníku).
Proto když v běžný funkci změníš nějakou běžnou proměnnou, co ti
přišla jako parametr, tak se to změní jen uvnitř té funkce - na
zásobníku.
Jen pokud ti přišel ukazatel, tak můžeš měnit data na místě, kam
ukazatel ukazuje (jako tady ve funkci SeradPole - muzes menit data na msite, kam
poleCisel ukazuje a srovnat pole), ta změna je pak trvalá, protože nešaháš
na lokální kopii na zásobníku, ale přímo na data na haldě.
V C se návratová hodnota takových funkcí často používá ke zjištění a případný indentifikaci chyby, takže to nemusí vždycky jít. V C se všeobecně výstupy funkce řeší pointerama v parametrech, návratová hodnota se pro výstup používá když je to jenom jedna hodnota a zároveň není potřeba aby funkce dávala informaci o chybě. Alespoň většina Céčkových knihoven co sem kdy používal se tohohle drží. Já v C moc nedělam, ale když jo, tak většinou zvolim to co mi zrovna připadá nejpraktičtejší.
V C nejsou výjimky, tak to ani jinak nejde. Předávání výsledků funkce v parametrech odkazem mi vždycky bylo proti srsti. Moderní jazyky už těmito neduhy netrpí.
Tohle záleží hodně na jazyku. Já třeba v C++ to řešim tak že pokud výstupní data ve funkci vznikají, pak je funkce vrací, pokud ale funkce mění data který už existujou, předávam data referencí (popř. pointerem) a měnim je přímo, funkce pak třeba ani nic nevrací. Informaci o chybě se snažim vždycky předávat návratovou hodnotou, nebo vyřešit chybu uvnitř funkce, většinou jde oboje, pokud ne, tak výjimkou ale všeobecně se výjimkám snažim vyhejbat.
Výjimky považuji za sekundární (chybový) informační kanál a proto je používám vždy, když je to možné. Ze začátku jsem se jim také vyhýbal, ale pak jsem zjistil, že je to vynikající nástroj. Hlavně se ale přes výjimky nesmí řešit standardní situace, jako např. ukončení cyklu apod.
Měnit existující data je vždy nebezpečné. Pro tento účel byly vyvinuty objekty a rozhodně by se neměly obcházet.
Předávání chyby návratovou hodnotou blokuje důležitý informační kanál funkce a v podstatě znemožňuje správné použití dependency injection. A bez dependency injection se nedá správně dělat test-driven development.
Měnit existující data je ale znatelně efektivnější než je 2x kopírovat (jednou do parametru, jednou do návratový hodnoty). Objekty v C++ nejsou v základu referenční, takže stejně nakonec musíš použít referenci explicitně, nebo udělat pointer.
Však také C++ není plně objektový jazyk. V těch plně objektových se jako výsledek funkce předává právě jen pointer na výsledný objekt. To si vynutilo vytvoření výjimek jako sekundárního (chybového) kanálu funkce.
Každý normální program má jeden standardní vstup, jeden standardní výstup a jeden standardní chybový výstup. Výstupní kanály programů jsou tedy dva, tak proč by tuto možnost neměla mít každá funkce v tom programu?
Dakujem za odpovede, cize ak som to spravne pochopil tak je vyhodnejsie pouzivat pointeri pre to lebo pointeri su pamatovo vyhodnejsie kedze to nieje klasicka premenna (je to odkaz na premennu) a netreba pre nu alokovat pamat, chapam to spravne ? Ak som niekde napisal blbost tak ma kludne opravte.
Pointer je dobrý jen k tomu, že ti umožňuje vytvářet datové struktury za běhu programu. Např. klasické pole si ve zdrojáku nastavíš na nějakou velikost a po spuštění ji už nezměníš. Když potřebuješ měnit velikost nějaké kolekce za běhu programu (což potřebuješ velmi často), musíš použít pointery. Jednoduše řečeno přes pointery si uděláš třeba natahovací pole.
Pointery určitě nejsou výhodnější a v mnoha případech se vyplatí kopírovat obsah klasických proměnných než udělat chybu v pointeru. Jinak celá myšlenka lidsky řízených pointerů (stejně jako jazyk C) je zastaralá a dávno ji převzaly stroje, takhle se už neprogramuje.
Zobrazeno 13 zpráv z 13.