Fórumok
Bocs a dedós kérdésért, de talán más is volt kezdő... miért nem működik ez nekem?
(gdb) print word2
$31 = "****", '\000'
(gdb) print strlen(word2)
$32 = 1944960
(gdb) print strlen(*word2)
$33 = 1944960
(gdb) print strlen(&word2)
$34 = 1944960
A word2 egyébként: char word2[256];
Hozzászólások
mi a kérdés?
forráskód?
Az a bajom, hogy a futó programban sem 4-et kapok vissza, hanem ilyen millió feletti számot. A forráskód egyszerűbb nem is lehetne:
xtr += strlen(word2);
Az xtr egy győjtőbufferen belül mutatja, hova kell a következő stringet tenni. A behelyezés rendben megtörténik, de nem tudom a behelyezett string hosszának megfelelő mértékben odébb tolni az xtr pointert.
Pont az hiányzik, hogy mi is a word2, és hogy adsz neki értéket.
--
HUPbeszolas FF extension
Az eredeti kérdésben írtam:
A word2 egyébként: char word2[256];
A hogyan adok értéket kérdés macerásabb, mert egy összetett procedura ad értéket neki. De a debuggerben látsik, beidéztem, hogy a tartalma egy asciiz string, amiben 4 db csillag van: ****
és az mindig mögéteszi a \0-t?
Az nem érdekes. A fenti példából látszik, hogy ott van a záró \0.
Szerk.: Lehet, hogy több gond is van és az egyik szempontjából mégis csak érdekes lehet a kérdés. A másikra lentebb utaltam.
> A forráskód egyszerűbb nem is lehetne:
Emeld ki a jelenséget egy önálló, teljes, fordítható, futtatható, pár soros C programba. Enélkül nem tudom, hogy miről beszélsz.
Ennyire azért nem bonyolult. Lentebb írtam is egy tippet, hogy mi lehet az oka.
pastebin: strlen
Nálam gdb-ben is 4-et ad vissza strlen-re.
--
HUPbeszolas FF extension
> Ennyire azért nem bonyolult. Lentebb írtam is egy tippet, hogy mi lehet az oka.
~15 sor. Nem kerül sokba beküldeni.
Ott lesz a dolog elröffentve, hogy a word2 tömbként van definiálva az egyik forrásfile-odban, a másik forrásfile-odban pedig, ahol az strlen()-t ráküldöd, már
-ként van deklarálva. Így az strlen() szépen követi az első 4 byte-ot (gondolom 32 biten vagy), pointer-ként, és a mutatott címen (0x2A2A2A2A?) talál 1944960 byte-ot, mielőtt \0-ba futna.
Kötelező olvasmány:
http://c-faq.com/aryptr/index.html
A gdb kimenete igazából semmit sem jelent, mert ellentmondó deklarációkkal kell megbirkóznia.
ISO C99 6.7.5.2 Array declarators, 8. bekezdés:
EXAMPLE 2
Note the distinction between the declarations
The first declares
to be a pointer to int; the second declares
to be an array of int of unspecified size (an incomplete type), the storage for which is defined elsewhere.
Köszönöm, megpróbálom felfogni :)
Nem tudom, számít-e, hogy egyetlen file az egész és a word2 nem external - bár kétségtelen, hogy a procedurán kívül van deklarálva.
Ha global lenne, akkor nem lenne baj? Hogyan kényszeríthetem ki, hogy global legyen?
(Ezt még korábban írtam:)
Nagyjából a következő történhet:
Az egyik file-odban allokálsz 256 byte-ot (statikus tárolási osztállyal). Ez deklaráció (mert bevezeti a nevet) és definíció is (mert tárhelyet allokál).
A másik file-odban csak deklaráció van (bevezeti a nevet az adott forrásfile számára, de tárhelyet nem allokál).
A kettő összepászítását a linker oldja meg. Amikor a második (a hivatkozó) file-odban az szerepel, hogy "na olvassuk ki a word2-t", akkor a linker ennek az első file-ban allokált 256 byte címét tolja alá. A kérdés az, hogy mennyit olvasol ki, és hogyan használod a tömbből kiolvasott byte-okat.
Ha a hivatkozó file-ban
szerepel, akkor a tárgykód a kiolvasott byte-okat közvetlenül fogja használni. Másként érzékeltetve, a
konstans kifejezés értéke 256.
Ha a hivatkozó file-ban
szerepel, akkor a "word2" a fordító számára a második file-ban egy 4-byte-os területet takar, amelyet pointer-ként kell használni, vagyis oda köll menni, ahova mutat. (Más szóval, a
konstans kifejezés értéke 4.)
Érted a különbséget? Az első esetben a
annyit tesz, hogy a linker betolja a tárterületet, azon belül megkeressük a 4. byte-ot, aztán kalap. A második esetben ugyanez a kifejezés azt jelenti, hogy linker betolja a tárterületet, beolvasunk onnan 4 byte-ot, a beolvasott értékhez (a mutatott címhez) hozzáadunk 3-at, és ami ott van, az a kifejezés értéke.
Az
kifejezés mindig annyit tesz, hogy
. (A kommutativitást most hagyva,) az "a" egy pointer, a "b" a (típushelyes) eltolás a mutatott címhez képest, a "*" pedig a dereferencia. Az egyetlen trükk, hogy amennyiben "a" nem pointer, hanem tömb, akkor automatikusan a legelső elem címe (pointer, &a[0]) kerül be a kifejezésbe. De ettől még a "sizeof a" tök mást fog visszaadni akkor, ha "a" tömb, és akkor, ha "a" mutató.
Még kell rágjam, hogy teljes mélységében megértsem, de valami világosságot felgyújtottál. Köszönöm szépen a részletes magyarázatot!
Ha egyetlen file-od van, és abban ez van (még a függvény előtt):
Akkor ez "file scope", "external linkage", "static storage duration", és (ha a word2-re más tentatív definíció nincs) "external definition". Minden eleme \0-ra inicializálva. Magyarul egy globális változó, amely más file-okból is látható lenne (ha lenne más file-od).
Nem tudsz forrást mutatni? Valami nagy disznóságot sejtek akörül, hogy
Az xtr egy győjtőbufferen belül mutatja, hova kell a következő stringet tenni. A behelyezés rendben megtörténik
Na varj... Mi?
Ezek szerint a word2 az globalis valtozo?
Ezen kivul en ugy tudtam, hogy a
char a[];
es a
char *a;
ekvivalens, hiszen "a" mind a ket esetben egy pointer es mind a ket esetben lehet pointerkent kezelni (a++, a+1, *a...) vagy tombkent (a[i]). Ebben az esetben mi a kulonbseg?
A tömb nem pointer.
--
HUPbeszolas FF extension
Mi a kulonbseg? Mind a ket esetben egy pointert kapsz egy char tipusra.
szerk. Szoval tudomasom szerint egy tomb csak egy pointer egy allokalt memoriaterulet elso elemere. A tombneve[i] ekvivalent a *(tombneve+i)-vel. Ki is probalhatod, hogy ugyanazt az eredmenyt fogod kapni. Ezert is lehet egy c-style string char[] vagy char* mert ugyanaz a ketto. (Az elso esetben annyi elonyod van, hogy irhatsz olyat, hogy char string[123] es ezzel allokalhatsz memoriat a stack-en vagy (globalis valtozo eseteben) a statikus memoriaban. Azonban az erosen nem ajanlott, szoval marad a pointer es a jo oreg malloc.)
A tömb neve mint szimbólum automatikusan konvertálódik pointerré, de ettől még a tömb nem pointer. Ritkán jön elő, de már több helyről hallottam, hogy volt vele gondjuk. A tömb máshogy indexel, mint a pointer.
int arr[10]; //sizeof(arr) == 10*sizeof(int)
int* ptr = new int[10];
Na, ekkor
arr[n] kifejezés értelme: *(&arr + n*sizeof(int))
ptr[n] értelme: *(ptr + n*sizeof(int))
Tehát a tömb szimbólum önmagában a tömböt jelenti, nem a tömb címét. Az, hogy kussban konvertálódik pointerré, még olyan esetekben is, amikor megtévesztő, nem segít persze.
void f(int arr[])
{
sizeof(arr) == sizeof(int*) //mindegy mekkora a tömb
}
A klasszikus példa, hogy fordítási egységek között, ha az egyik helyen tömbként van definiálva, a másik helyen deklarálod mint extern pointer, akkor indexelésnél a címzést el fogja kúrni a fordítóprogram, ugyanis mint fentebb láthatod, máshogy indexeli a pointert és máshogy a tömböt. Csak előled ez el van rejtve.
----
Hülye pelikán
"int arr[10]; //sizeof(arr) == 10*sizeof(int)"
Ez eleg megteveszto lehet...
"arr[n] kifejezés értelme: *(&arr + n*sizeof(int))"
Nem, a szorzast nem kell oda tenni (pointer eseteben a +1 mindig a megfelelo merettel inkremental. Ez egyreszt a ptr++-os megoldasok miatt jo, masreszt azert, mert nem kell aggodnod a memoria cimek igazitasa miatt)
"sizeof(arr) == sizeof(int*) //mindegy mekkora a tömb"
Nekem ugy remlik, hogy ebben az esetben a pointer meretet fogja adni a sizeof.
"A klasszikus példa, hogy fordítási egységek között, ha az egyik helyen tömbként van definiálva, a másik helyen deklarálod mint extern pointer, akkor indexelésnél a címzést el fogja kúrni a fordítóprogram, ugyanis mint fentebb láthatod, máshogy indexeli a pointert és máshogy a tömböt. Csak előled ez el van rejtve."
Ez viszont mindent megmagyaraz. Koszonom.
>Nem, a szorzast nem kell oda tenni (pointer eseteben a +1 mindig a megfelelo merettel inkremental
Tudom, ez kvázi pszeudokód volt, mivel a &arr pont a vita tárgya miatt sem egyértelmű, hogy milyen típusú. Ugye mi a típusa a tömbre mutató pointernek (ilyen nincs).
>"sizeof(arr) == sizeof(int*) //mindegy mekkora a tömb"
> Nekem ugy remlik, hogy ebben az esetben a pointer meretet fogja adni a sizeof.
Így is történt, az int* egy pointer fajta.
----
Hülye pelikán
ok, felreneztem... ugy olvastam, hogy sizeof(int)
Az a jo a pointerekben, hogy amikor mar azt hiszed, hogy mindent tudsz roluk, akkor elojon valami uj. :)
Mi a kulonbseg? Mind a ket esetben egy pointert kapsz egy char tipusra.
Az a különbség, hogy az
extern char *a;
extern char a[];
közül az első egy olyan globális objektumra mutat, amihez egy pointer méretű memóriaterület tartozik, és az "a" értéke az adott objektumhoz tartozó memóriaterületen eltárolt pointer, az &a kifejezés értéke pedig a globális objektum címe.
A második egy olyan globális objektumra mutat, aminek a mérete ismeretlen, és "a" értéke a globális objektumhoz tartozó memóraterület címe. A második objektumnál nem definiált fogalom az &a.
Az első "a"-nak lehet értéket adni, az értékadás alkalmából a pointert beírjuk a memóriaterületre. A második "a"-nek nem lehet értéket adni, az mindig ugyanarra a memóriaterületre fog mutatni.
Ok, tiszta. Koszonom neked is.
Szerintem tegyél fel egy forrást pastebinre vagy bárhova, úgy sokkal többet tudnánk segíteni.
Esetleg próbáld meg
stb. opciókkal fordítani, és eltüntetni a warningokat a kódból, mert ez sok szenvedétől menthet meg.
kicsit off: érdekes pointer challenge:
http://blogs.oracle.com/ksplice/entry/the_ksplice_pointer_challenge
kicsit off: érdekes pointer challenge:
Megvolt :)
lacos, axt:
Köszönöm, megoldódott a dolog. Lesz mit olvasgatnom az eset kapcsán. Köszönöm!
es elarulod mi volt? Probaltam reprodukalni, de sehogy nem jott ossze :)
Workaround lett a vége :)
Ha reprodukálni akarod, próbáld ki, mit ad a strlen(argv[1])
azt amit varok, ha argc > 1 akkor argv[1] hosszat, egyebkent meg argv[1] nincs is.
Őőőő, de. argv[1] mindig létezik, ugyanis az argv tömb 0 terminált, és argv[0] mindig létezik (legalábbis normál esetben). Azaz argc == 1 esetén argv[0] a program indítási módja, argv[1] pedig NULL.
----
Hülye pelikán
> argv tömb 0 terminált
ezt nem tudtam, mindig tanul az ember, viszont kicsit redundans a rendszer mert akkor minek argc..
strlen(NULL) -rol nem is vartam hogy mukodjon, a NULL ptr kozott meg egy (char*) kozzot ami '\0'-ra mutat azert van kulonbseg
Mert igy nem kell megszamolnod a tomben levo elemmeket ahhoz, hogy tudd eleg parametert kapott-e a program. Masik oldalrol meg nem kell szamlaloval szenvedni amikor - akar valami rekurziv cuccal - a parametereket szeretned feldolgozni.
http://flash-gordon.me.uk/ansi.c.txt
"2.1.2.2 Hosted environment"
Milyen C fordító? Milyen rendszeren?
Úgy látom, hogy ez lehet akár a gcc-be beépített strlen hibája is.
askubuntu.com
bugs.debian.org
What GDB is printing is actually the return value of the indirect function, i.e. the address of the actual strlen.
Ha C-n belül nem tudod értelmezni a hibát, akkor ASM szinten debuggolj, nézd meg milyen kezdőcímről indul az strlen, és mi van ott.
Ohm, egy kezdonek ez lehet, hogy rossz tanacs.
--