Diskuze: c - ujištění se ohledně pointerů
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
Člen
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.
nespadne to na prvnim radku metody main na access violation?
Ne, ale padá mi to na acces violation, když si chci to pole vrátit přes funkci. A tady jsem už bezradná. Proč to spadne když tam to místo pro pointer na stukturu alokované mám?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char * jmeno; int vek;
}Osoba;
Osoba ** osobyAlok() {
Osoba ** osoby = (Osoba**)malloc(2 * sizeof(Osoba*));
Osoba a; a.jmeno = "Karel"; a.vek = 32;
Osoba b; b.jmeno = "Robot"; b.vek = 5;
osoby[0] = (Osoba*)malloc(sizeof(Osoba));
osoby[1] = (Osoba*)malloc(sizeof(Osoba));
osoby[0] = &a;
osoby[1] = &b;
return osoby;
}
int main() {
Osoba ** osoby = osobyAlok();
if (osoby != NULL) {
printf("%s, %d let\n", osoby[0]->jmeno, osoby[0]->vek);
printf("%s, %d let \n", osoby[1]->jmeno, osoby[1]->vek);
}
free((void**)osoby); osoby = NULL;
return 0;
}
Zapisuje do promenne jmeno , ktera neni naalokovana - pokud to nehodi access violation hned, tak tim prepise nekde neco jinyho, ta sance na accessviolation je tam podle me celkem velka
Na tom prvnim radku v main to nespadne urcite, ta struktura je slokovana na stacku. Promenna jmeno je jenom pointer, stejne tak retezcovy literal.
Ve funkci OsobyAlok vytváříš dvouprvkové pole ukazatelů na strukturu Osoba. Tyto odkazy nasměruješ na struktury a a b, které jsou ale lokálními proměnnými. To znamená, že jakmile vykonávání funkce skončí, de facto přestanou existovat.
Realita je obvykle taková, že místo, kde tyto proměnné byly (a kam tedy odkazují ty dva ukazatele) stále existuje, jen je zaplněno jinými daty (pokud vůbec nějakými). Ty se je pak pokusíš interpretovat jako strukturu Osoba, ale protože tam už pravděpodobně jsou uložena jiná data, dostaneš se do problémů (zejména proto, že jméno osoby je ve struktuře uloženo jako ukazatel na první znak (Cčkový řetězec)... a hodnota toho ukazatele je (potom, co ty lokální proměnné přestaly existovat), řekněme, náhodná, a tedy obvykle vede na neexistující oblast paměti).
Děkuji za objasnění . Jinak teď jsem trochu experimentovala a zkusila napsat toto v té funkci osobyAlok:
//osoby[1] = &b;
*osoby[1] = b;
nevím ale teda co přesně to znamená, ale funguje to , v mainu to ty osoby vypíše. A ještě bych se chtěla zeptat jak naplňovat pole ve funkci, jestli to jde tím řádkem jak jsem teď napsala nebo se to řeší jinak. Děkuji.
Jo vlastne, "Karel" bude nejspis nekde staticky sedet na stacku, takze se do a.jmeno jen hodi ukazatel na tohle misto.
Já bych spíš řekl, že "Karel" bude staticky alokovaný pro celou aplikaci, tím si už úplně jistý nejsem, ale pamatuji si, že když jsem kdysi otevřel .exe zkompilovaný z C kódu v textovém editoru, tak tam ty řetězcové literály byly vidět, z toho soudím, že to bude spíš kompletně statické.
Všechny řetězcové literály definované v kódu jsou staticky alokovány v datovém segmentu binárky. Standardní také je, že pokud máte v kódu více stejných literálů (třeba několikrát přiřazeno "Ahoj", tak se alokuje pouze jednou.
Proto je chyba, když člověk udělá něco takovéhoto:
char *mujstring = "Ahoj";
char *jinystring = "Ahoj";
mujstring[0] = 'a';
Pokud by vám to systém dovolil, tak si přepíšete oba stringy. Typicky to ale bude segfault, protože oblast statických dat je chráněná proti zápisu
Tento řádek
*osoby[1] = b;
překopíruje strukturu Osoba uloženou v proměnné b (člen po členu) na adresu zapsanou v Osoby[1]. Jelikož jsi ten paměťový blok předtím alokovala, tak to bude fungovat. Já bych tam osobně ještě přidal nějakou tu kulatou závorku, protože se v prioritách operátorů moc neorientuju:
*(osoby[1]) = b;
Ono se to dá i trochu odvodit. Víš, že proměnná Osoby má typ Osoba **, proměnná b má typ Osoba. Operátory * a [] oba lze chápat jako něco, co ti z datového typu argumentu odebere jedno přesměrování (jednu *), takže výsledek je takový, že na obou stranách přiřazovacího příkazu máš něco s datovým typem Osoba. A přiřazení znamená kopírování obsahu (pokud jsme v C).
Zobrazeno 13 zpráv z 13.