Dobry den,
Teprve se seznamuji s pointry v C a zajímalo by me zda muzu natvrdo, treba na adresu 5 zapsat urcita data.
Diky za reakce.
No, tak jak chápu virtuální prostor já, tak můžeš. Jde o to, že proces má přidělenou VIRTUÁLNÍ paměť od procesoru. V žádném případě nemůžeš spůsobit nestabilitu systému,, s tím teda nesouhlasím, protože OS ti nikdy nepřidělí nějakou problematickou paměť.
takže:
pointer VŽDY ukazuje do virtuální paměti = paměť přidělena pouze procesu (Pokud se nejedná o nějaký velmi spec. kompilátor)
můžeš přepsat adresu, na kterou pointer ukazuje, ale mohl by ses trefit někam hodně blbě. Ale vždy se trefíš do dat TVEHO procesu. Tzn mohl by ses dostat na adresu, na které je zásobník (tvého procesu), to by způsobilo problémy s během aplikace atd.
Tohle je můj názor :)
No tak ale to je přece hodně velikej rozdíl :) Problém není v "přemapování pointeru" ale o tom, kam se trefíš, přesně jak sem to psal.
Dotaz si pochopil správně, odpověděl si špatně .. teda pokud tazatel pod slovem "třeba" myslí například. tzn NAVRDO zapsat samozřejmě lze
Uvidíme až odpoví tazatel .. podle mě řešil princip jestli může zapsat na libovolnou adresu .. to jde, ale jak říkám, můžeš se trefit blbě a vyvoláš chybu.
Co třeba zjistit kam pointer ukazuje a zvětšit jí ... to je uložení natvrdo a na 99% se trefíš do paměti vyhrazenou pro data?!
#10 TheOndrap
Ale to je neco jineho, to už máš pamět přidelenou, neco jako tohle:
int p[5];
p[6] = 6;
kdyz system prideluje pamet pro promene tak to prideluje po blocich a vzdycky jsou tam nevyužite zbytky
Ale ja jsem mel spis namysli že čiste si do pointeru das rucne adresu a to se netrefis
To teda neni ubec nic jiného ...
int p[5];
p[0] = 100; == *p = 100;
p[3] = 100 ... vezmeš adresu pointeru(to kam pointer ukazuje) a přičteš k tomu 3 a na tu adresu uložíš 100.
p[3] = 100 ... *p+3 = 100; /možná je to *(p+3) = 100; nevím přesně, ale spíš ten první způsob/
p je pointer, ukazuje na adresu .. třeba 0xFF0000 .. v tuhle chvíli, když dáš do p = FF0003 tak na 99% budeš zapisovat OK.
EDIT: správně je to *p + sizeof(int) * 3
#15 cibule
:) tak to zkus .. já ti prostě říkám, že když máš alespoň nějakou představu o tom, jak se to chová, (jak OS při vytváření procesu přideluje paměť, kam se ukládá zásobník,PCB , jaká pamět je přidělena datovému prostoru) tak zjistíš, kam můžeš "střílet na slepo" a nic se nestane
No samozřejmě, protože si porušil segmentaci, to už sem psal.
Přečti si něco o přidělení paměti procesu operačením systém při vytvoření procesu. Zjistiš že přidělená pamět se dělí na kód programu, globální konstanty, globální proměnné, zásobník, heap a asi ještě něco .. .
To znamená že ty když si dal takhle nízkou hodnotu, tak si na 90% zapisoval do nějakého vyhrazeného místa, určeného pro funování procesu.
Pokud zjistíš, kde sou uložený konstanty, proměnný a kde je heap, tam můžeš ukládat jak je libo.
#17 cibule
EDIT
btw Ja mam jenom zakladni znalosti OS pridelovani pameti tak možna nemam pravdu jenom rad programuju, ale mam zkušenost si že zapis mimo vyhrazenou pamet i když se povede je pak problem hlavne u dynamicke alokace pri naslednem uvolnovanim pameti
#17 cibule
Pardon, ze vam do toho vstupuju, ale co znamena "adresa 5"? Adresa (pointer) je napr. 32 bit cislo (na 32bit systemu). Pokud chces zapsat na nejakou tebou definovanou adresu musis psat:
void* p = (void*)0x25DF6885
// nebo
unsigned int* p = (unsigned int*)0x25DF6885
// ----
unsigned int i = 2012;
p = &i;
// zapises cislo 2012 do nealokovane pameti na adresu 0x25DF6885, co se pak stane je otazka nahody
? adresa 5 = 0x00000005 ?
nechapu co je na tom za chybu .. chyba je že tvoje adresa je z nějaký vyšší části adresního prostoru, addr 5 je hned na začátku
Program sa skladá z viacerých častí. Inštrukcie zaberajú časť pamäťového priestoru, lokálny stack zas inú časť, heap zas inú...
Ak sa náhodou trafíš do časti do ktorej môžeš zapisovať(inštrukcie ti asi OS nedovolí prepísať), tak program "funguje" ďalej, inak spadne.
Takže kľudne môžeš zapísať na adresu 5 (05, 0x5) hoci čo, prekladač to preloží, ale OS ti to počas behu nemusí povoliť (killne proces)
mam to samozrejme blbe, pro zapsani hodnoty na konkretni adresu to ma byt takto:
int* p = (int*)0x25DF6885;
// ----
// pri kompilaci OK, pri spusteni to padne
int i = 2012;
*p = i; // access violation writing 0x25DF6885
To plati i pro adresu 0x00000005 nebo jakoukoliv jinou nealokovanou. To ze je adresa "na zacatku" nema zadny vyznam.
prosimtě bobe a cibule, podívejte se co napsal vitamin, napsal to samé co ti tady tvrdím já, já už nevím jak to jinak říct .. tvoje přidělená pamět prostě není homogení prostor!!
To ze je adresa na začátku je sakra veliký rozdíl, protože se dá čekat, že tam budou uložené informace důležité pro běh procesu (viz já, vitamin - stack, PCB atd). Ty, jako programátor můžeš zapisovat jenom do povolených segmentů paměti, a to na 99% nebude na začátku adresního prostoru.
My tady přece neřešíme "styl zápisu na danou adresu". Mě jde o to, že v žádném případě není jedno KAM zapíšeš. Tazatel se ptal na to, " zda muzu natvrdo, treba na adresu 5 zapsat urcita data. " A podle mě je odpověď:
Ano, samozřejmě můžeš zapsat kamkoli, ale čelíš tomu riziku, že si vybereš místo do kterého nesmíš zapisovat a program spadne (OS ho odstřelí).
Mozu si skusit tento program:
#include <stdio.h>
const int g = 7;
int main(int argc, char **argv)
{
int i;
(&i)[200] = 23; //lokalny zasobnik ma vecsinou +- 1MB, takze tu to nepadne (aspon mne)
//*((int*)main) = 23; //adreu funkcie by ti OS nemal dovolit prepisat
//*(int*)(int)&g = 44; //adreu konstanty tiez nie
return 0;
}
Honza se ptal jestli "muze", vy odpovidate ano, ale s rizikem padu programu, ja odpovidam jak to udelat at to padne nebo ne. V cem je problem?
Muj prvni post reagoval na cibuli, kde se pokousel inicializovat pointer cislem 5. Ja mu ukazal jak korektne inicializovat pointer konkretni adresou pameti. Jestli se tou pameti zrovna trefi do stacku aplikace nebo ne je mi jedno.
Vubec netusim problem sporu.
Len taky dodatok, nie je jedno ci zada cilo 5 v dec, oct, hex formate?
V C ani nemusi dane cislo pretypovat na spravny typ, to az v C++.
Jen bych možná ještě dodal, že konstatní hodnotu lze změnit na kompilátoru gcc, ale novější g++ to už zakazuje... čili to jak jste tu měli..
const int a = 10;
*((int*)&a) = 20; // bude fungovat na gcc kompilátoru
Nelsem si ale jistej, jestli novější gcc to už taky neopravilo, dřív mi to fungovalo
V gcc 4.6.3 sa to prelozi a hodnota sa zmeni na 20.
V g++ sa to tiez prelozi ale hodnot sa nezmeni a ostane 10.
Toto plati ale len pre automaticke premenne. Akonahle je premenna staticky alokovana tak nastane chyba: "Segmentation fault" (na linuxe).
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku