NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
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 – Lekce 4 - Dynamické textové řetězce a struktury v jazyce C

Zpět

Upozorňujeme, že diskuze pod našimi online kurzy jsou nemoderované a primárně slouží k získávání zpětné vazby pro budoucí vylepšení kurzů. Pro studenty našich rekvalifikačních kurzů nabízíme možnost přímého kontaktu s lektory a studijním referentem pro osobní konzultace a podporu v rámci jejich studia. Toto je exkluzivní služba, která zajišťuje kvalitní a cílenou pomoc v případě jakýchkoli dotazů nebo projektů.

Komentáře
Avatar
Odpovídá na Martin Russin
Patrik Valkovič:12.7.2021 17:31

Přesně tak. Obdobně by to fungovalo například pokud by se jednalo o ukazatel na celé číslo.

int *p_int = (int*)malloc(sizeof(int));
*p_int = 10; // přiřazení hodnoty na místo kam míří ukazatel
int *p_int2 = p_int; // přiřazení ukazatele do ukazatele, adresa na kterou odkazuje p_int2 je stejná jako ta na kterou odkazuje p_int
int hodnota = *p_int2; // přiřazení hodnoty do hodnoty, dereference získá hodnoty z místa kam ukazatel odkazuje
Odpovědět
12.7.2021 17:31
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Martin Russin
DarkCoder:12.7.2021 18:19

Pozor na to správné vyjadřování, ukazatel není inicializován adresou ukazatele na typ, ale ukazatelem na typ. Adresa ukazatele je něco jiného, jedná se již o vícenásobnou referenci, kterou nelze přiřadit ukazatelové proměnné.

UZIVATEL *p_uzivatel2 = p_Karol;

Výše uvedený kód značí že je definována ukazatelová proměnná p_uzivatel2, která může ukazovat na typ UZIVATEL a tato proměnná je inicializována ukazatelovou proměnnou p_Karol.

Levá strana je adresa, pravá strana musí být adresa. Proto není na pravé straně uveden u názvu proměnné znak *.

Pokud bychom měli toto:

int i = 0;
int *pa = &i;

Pak mohu psát

int *pb = pa;
// Nebo
int *pb = &i;

Ukazatele pa a pb budou ukazovat na stejnou adresu v paměti, na místo, kde je uložena proměnná i.

Co se týká dotazu k parametru. Funkce která má parametr ukazatel ihned značí, že si žádá adresu a ne hodnotu a že hodnota proměnné, na kterou ukazatel ukazuje, může být měněna.

Máme-li prototyp funkce

void func(int *num);

Pak tuto funkci lze volat těmito způsoby

func(&i);
func(pa);
func(pb);

Dereference se pak používají uvnitř funkce pro přístup k hodnotě proměnné, jejíž adresu jsme předali funkci při jejím volání.

Pamatovat: je třeba počty referencí levé a pravé strany přiřazovacího příkazu udržovat v rovnosti. Jakmile se objeví ve funkci či v definici ukazatel, pak této ukazatelové proměnné se předává pouze adresa, nikoli hodnota.

Odpovědět
12.7.2021 18:19
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Jakub Hrbáček:1.6.2022 13:39

Zdravím, rád bych se zeptal na tento příkaz, který jsem potkal někde na internetu.

char *p_t = "ahoj"; //bez alokace a místo char t[] = "ahoj";

Předpokládám tedy, že pravá strana příkazu ("ahoj") vlastně vrátí adresu na nově vytvořené pole charu. A jelikož pole je skoro pointer, tak to funguje. Mohu tedy vypsat obsah pole nebo pracovat s jednotlivými prvky pole:

printf("%s", p_t); //vypíše ahoj
*(p_t + 2) = ...; //změna 2. prvku
p_t[2] = ...; //změna 2. prvku

Ale nefungují příkazy běžně používané při práci s polem charů nebo pointery.

strcpy(p_t, "novy text");
scanf(" %4[^\n]s", p_text);

Lze také přiřazovat nové adresy pointerů:

p_t = scanf("jiny retezec");

Ale mám pocit, že to je docela nebezpečné, když se ta předchozí paměť neuvolní.
Jaký je tedy smysl nahoře zmíněného příkazu a jak s ním pracovat (jestli vůbec). Jinak nacházel jsem to hlavně ve tvaru:

const char* p_t = "ahoj";

Díky.

 
Odpovědět
1.6.2022 13:39
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Jakub Hrbáček
DarkCoder:1.6.2022 15:13

Smyslem tohoto příkazu je vytváření konstantních řetězců. Proto se i dost často píše s modifikátorem const.

char *p_t = "ahoj";
// nebo
const char* p_t = "ahoj";

Funguje to tak že se vytvoří daný řetězec a uloží se do tabulky řetězců. Překladače jej často ukládají do read-only části paměti. Na tento řetězec se předá adresa ukazateli. Díky tomu jej lze používat, číst, nikoli však měnit!

Naproti tomu varianta:

char a[10] = "ahoj";

Funguje tak, že se vytvoří řetězec, uloží se do tabulky řetězců, následně dojde k jeho kopírování do části paměti, která není určena pro čtení, kterou nám překladač přidělil. Tento proces je tedy o něco pomalejší nežli v případě ukazatele, neboť nedochází ke kopírování řetězce.

Na ukazatel lze aplikovat běžné výstupní funkce (printf(), puts()). Avšak jakékoli zápisy mající za úkol změnit řetězec jsou chybné.

*(p_t + 2) = ...; //změna 2. prvku
p_t[2] = ...; //změna 2. prvku

NELZE! Jakýkoli pokus o modifikaci řetězce na který máme ukazatel může vést k nedefinovanému chování.

Dále nelze přiřazovat ukazateli nový řetězec pomoci funkce strcpy().

Řetězec je dostupný po celou dobu chodu programu (static storage) a paměť se uvolní po jeho skončení. Neprovádí se žádná externí dealokace pomocí free().

Pole a ukazatel mají k sobě velmi blízko, nejsou však totéž!

Několik rozdílů pro následující zápisy:

char a[10] = "ahoj";
// a
char* p = "ahoj";

a je konstantní ukazatel, nelze měnit, p je ukazatel, lze měnit
a[0] = 'x'; je platné, p[0] = 'x'; je neplatné
a = "nazdar"; je neplatné, p = "nazdar"; je platné
sizeof(a) je 10 bytů, sizeof(p) jsou 4 byty

Pokud chci používat v programu řetězec, který nechceme měnit, použijeme formu s ukazatelem.
Pokud chci nebo potřebuji řetězec nějakým způsobem měnit, použiji pole.

Odpovědět
1.6.2022 15:13
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
DarkCoder:1.2.2024 20:23

Dynamické textové řetězce se často vytváří uvnitř funkcí. Proč zde není ukázka toho jak se vrací vytvořený řetězec z funkce?

Odpovědět
1.2.2024 20:23
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
DarkCoder:13. ledna 14:56

Protože budeme k načítání z konzole využívat funkci scanf(), musíme si stejně vytvořit pomocný statický řetězec, do kterého text necháme scanf() uložit.

Řetězec je text uzavřený mezi dvojitými uvozovkami. Jistě to bylo myšleno takto, že si musíme vytvořit pomocné statické pole, do kterého uložíme text načtený pomocí funkce scanf(). Jinak pomocný řetězec není nutné vytvářet, ale to už jsou pokročilejší techniky nad rámec této lekce.
Dále použitá technika se hodí pro vytváření řetězců, nikoli jednoho řetězce. Na to bychom nepotřebovali další pole alokované dynamicky, ale mohli ho nechat ve statickém poli. Pokud by velikost bufferu byla skutečně dostačující, pak by tento způsob byl skutečně snazší a efektivnější nežli pokročilejší technika, která se skutečně může zbavit paměti pro dočasné uložení textu.

Co se týká části odkazu na struktury:

Změna věku Karla se uzivatel2 již netýká. Nakonec druhého uživatele vypíšeme, budou v něm ty samé hodnoty jako měl Karel, věk bude původní

To je pochopitelné a není nutné toto zmiňovat a mást uživatele. Vždyť struktura uzivatel2 nikterak sesouvisí se strukturou karel, krom toho, že byl do ní překopírován obsah karla.

Předávání hodnotou je poněkud nepraktické a to hlavně když chceme nějakou strukturu změnit.

Žádné nepraktické, ono je to nefunkční. Pokud je argument předáván hodnotou, jeho obsah se nezmění vně funkce.

Proč celý program přepisujete a karla vytváříte dynamicky? Takto to vypadá, že pro změnu obsahu je nutné mít vytvořenou strukturu dynamicky což samozřejmě není nutné. Stačí jako argument předávat adresu struktury. Tuto techniku jste vůbec v článku neukázali.

Vysvětlujete to strašně kostrbatě a nedostatečně.. Ve výsledku z toho ten, kdo se snaží látku pochopit, nemá nic.

Odpovědět
13. ledna 14:56
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
DarkCoder
Člen
Avatar
DarkCoder:10. února 13:06

Proč v článku není uvedeno jak vracet z funkce ukazatel na strukturu?

Odpovědět
10. února 13:06
"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 7 zpráv z 27.