strlen

 ( Uhum2004 | 2011. november 25., péntek - 23:03 )

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ás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

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 extern char *-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

    extern int *x;
    extern int y[];

The first declares x to be a pointer to int; the second declares y 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 extern char word2[256] szerepel, akkor a tárgykód a kiolvasott byte-okat közvetlenül fogja használni. Másként érzékeltetve, a sizeof word2 konstans kifejezés értéke 256.

Ha a hivatkozó file-ban extern char *word2 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 sizeof word2 konstans kifejezés értéke 4.)

Érted a különbséget? Az első esetben a word2[3] 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 a[b] kifejezés mindig annyit tesz, hogy *(a + b). (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):

char word2[256];

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?

char a[] != char *a
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

-Wall -ansi -pedantic 

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.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal