strlen

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

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.

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.

(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ó.

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?

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

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.

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.