» »

[C] struct in int[]

[C] struct in int[]

1
2
»

MrBrdo ::

Saj to smo že uvodoma povedali in ugotovili, da nista popolnoma ekvivalentna. Array ima dodatno informacijo o velikosti (razen če je []), za alokacijo poskrbi prevajalnik sam, sicer pa je ekvivalenten kazalcu z konstantno vrednostjo (ki je naslov, kjer so podatki).
Zapis v pomnilniku pa nikakor ni nič drugačen, še vedno gre le za kazalec (naslov) v pomnilnik, kjer se nahajajo podatki eden za drugim in brez kakršnihkoli drugih informacij.
MrBrdo

Zgodovina sprememb…

  • spremenilo: MrBrdo ()

napsy ::

Ekrat sta, drugic nista. ne da se mi vec ... bom zakljucil jaz ...
"If you die, you die. But when you live you live. There is no time to waste."

MrBrdo ::

Že ves čas govorim, da so manjše razlike v smislu samega jezika. Ampak iz arhitekturnega stališča pa sta popolnoma enaka. Tako smo tudi začeli ;)

Sicer pa smo vsaj našli kredibilen vir, ki uporablja enako notacijo (objekt) kot ti. Sicer se mi zdi to zelo neprimerno ampak ker gre očitno za nek relativno respected vir potem ti moramo dat prav. Drugače pa tudi na povezavi ki si jo linkal piše, da sta array in kazalec v Cju več ali manj ekvivalentna.

Mogoče najbolj bistvenega pomena je tole:
Given the declarations above, when the compiler sees the expression a[3], it emits code to start at the location "a," move three past it, and fetch the character there. When it sees the expression p[3], it emits code to start at the location "p," fetch the pointer value there, add three to the pointer, and finally fetch the character pointed to.


V tem primeru res pride do ene pomembne razlike, in sicer ker prevajalnik že vnaprej pozna točno pomnilniško lokacijo (ker jo pač alocira na stacku in je možno dostopat preko ESP skladovnega kazalca/registra), kjer so podatki, lahko namesto spremenljivke že kar hard-codea naslov v kodo (v smislu esp-nekaj). Za razliko od tega pri kazalcu mora iz sklada najprej prebrat naslov, šele potem lahko bere podatke, kar pomeni da imamo eno branje več. Torej v tem smislu pa imaš prav. Samo še vedno lahko govorimo o kazalcu, le da je naslov prevajalniku že vnaprej poznan ter konstanten in lahko zato izvede določene optimizacije. Jaz bi rekel da je array kazalec, kjer pa je naslov impliciten in vnaprej znan.
MrBrdo

Zgodovina sprememb…

  • spremenilo: MrBrdo ()

egonk ::

Tole si preberte, nestrpni lahko začnete kar s section 2.4.1 ;)

How To Write Shared Libraries

Kakorkoli obrneš, C compilerji ločijo arraye in pointerje že zaradi optimizacij.

technolog ::

Če jih dinamično alociraš nimajo kaj ločevat.

egonk ::

Se mi je zdelo vredno na tole odgovorit:

In fact, spodnja stavka sta identična:
char str[] = "Bla bla";
char *str = "Bla bla";


Razlika je v določenih primerih (DLLji) zelo pomembna.

technolog ::

Ne, ta zadeva je sitaktično identična, se prevede v isto zadevo. Oz. naj bi se.

egonk ::

int main()
{
	char str1[] = "x";
	char *str2 = "x";
	printf("%u %u\n", sizeof(str1), sizeof(str2));
}


2 8

technolog ::

Hm, na sizeof() pa nisem pomislil. Tole imaš pa prav.

MrBrdo ::

Naj me kdo popravi, ampak mislim, da tudi če imaš char[], se zanj alocira prostor na stacku in literal ("x" v tem primeru), se skopira na stack, medtem ko pri pointerju je kazalec direktno nekam v .data section in ne na sklad... Tako da v teoriji bi moralo biti možno str1 spreminjat (s tem mislim vsebino, chare), medtem ko spreminjanje str2 bi moralo povzročit nedoločljive posledice (torej možnost da pride do crasha). Ker tudi sicer mislim da popolnoma pravilno bi bilo
const char *str2 = "x";

Saj string literalov načeloma ni dovoljeno spreminjati in naj bi bili konstantni...
Ker nimam tukaj blizu C compilerja nisem sprobal, kot pravim naj me kdo popravi ker govorim na pamet.
MrBrdo

Zgodovina sprememb…

  • spremenilo: MrBrdo ()

Mavrik ::

Govoriš prav. Če inicializiraš char[] s string literalom, bo compiler dal vse skupaj na stack, medtem ko pri char* bo pa na stack šao samo pointer, literal pa bo končal v .text sectionu (lihkar preverjeno z gcc 4.1 na x86, YMMV).
The truth is rarely pure and never simple.

ziga7 ::

In fact, spodnja stavka sta identična:
char str[] = "Bla bla";
char *str = "Bla bla";


Bi se tudi navezal na tole...
Ker je tema C in sem imel pred kratkim podobna vprašanja me zdaj zanima, če sem dobil prave odgovore.

char a[] = "Bla bla"; // tole je OK v C (zasede prostor za naslov in podatke)
char *p = "Bla bla"; // za tole sem dobil odg., da ni OK v C (je pa vredu za C++), ker ni prostora za podatke;
C++ pa tole "pretvori" v:
p = (char *) malloc( N * sizeof(char)); // N = 7 (zasede prostor za podatke)
strncpy(p, "Bla bla", N);

Iz tega izhaja, da kazalcu lahko spremenimo vrednost (p=a), polju pa ne (a=p) vrne napako.

fiction ::

egonk je izjavil:

2 8
2 pride pomoje kot velikost str1, 8 je pa zato ker je tisto pointer in si pravzaprav dobil dolžino pomnilniškega naslova. sizeof(*str2) bi vrnil 1, ker je tako velik char (na kar kazalec kaže). Nimaš pa na ta način pojma, kako veliko prostora je bilo tam alociranega. Ampak to samo po sebi še ničesar ne pove. Teoretično bi bil lahko tudi string literal za str2 na stacku (poleg samega kazalca).

V bistvu je res malo presentljivo, da oba načina inicializacije nista ekvivalentna. Pričakoval bi le to razliko, da vrednost str2 lahko spreminjaš (kam kaže), str1 pa ne (ker je array). Ampak razlaga od MrBrda zadevo logično razloži. Pri čemer moram dodati samo še to, da pri meni string literal pristane v .rodata. Je pa vse to pomoje stvar implementacije prevajalnika, ne jezika C kot takega.

Zgodovina sprememb…

  • spremenil: fiction ()

MrBrdo ::

fiction: ja imena sectionov so stvar implementacije prevajalnika... ni nobenega standarda ali kaj takega, kako naj se imenujejo. npr. tudi za kodo včasih se imenuje code včasih text itd.

ziga7: tisto "ker ni prostora podatke" mi ni cisto jasno v kaksnem smislu je to misljeno. to prvic slisim da bi C++ kopiral string literal ce ga priredis kazalcu. morda je tako, vendar kot pravim prvic slisim za kaj takega.
prva vrstica je sigurno OK. pri drugi vrstici pa bi jaz rekel da imas 2 pravilni moznosti:
1.
const char *p = "Bla bla";

(namreč string literalov ni dovoljeno spreminjati)
2.
char *p = (char *) malloc(8 * sizeof(char));
strcpy(p, "Bla bla");


Kot pravim lahko da je v C++ res pravilno tudi kar si ti napisal ampak jaz za to prvič slišim. Moram pa priznat da mi nikoli ni bilo jasno zakaj prevajalniki ponavadi ne težijo če literal prirediš ne-const char pointerju.
MrBrdo

Nanthiel ::

MrBrdo je izjavil:

Moram pa priznat da mi nikoli ni bilo jasno zakaj prevajalniki ponavadi ne težijo če literal prirediš ne-const char pointerju.


Razlog za tem je ta, da v čistem C "const" ne pomeni konstante, pač pa read-only spremenljivko. Problem je v tem, da lahko stvar še vedno "castamo" v non-const. Zaradi tega so se odločili, da nima smisla sploh česa javljat, ampak naj pač programer pazi — kot se po Cjevsko spodobi. :)

C++ prevajalnik to dopušča samo zaradi kompatibilnosti s Cjem, javi pa:
warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

V C++ "const" namreč pomeni pravo konstanto, ki je ni mogoče več spreminjat.

MrBrdo ::

Zanimivo, hvala za razlago. Sicer me malo moti to, da ne javlja, ker dolgo časa sploh nisem vedel kako je v resnici z string literali v Cju, pa verjamem da tudi še marsikdo ne ve.
MrBrdo
1
2
»


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Pomoc v C-ju

Oddelek: Programiranje
51010 (922) rfmw
»

[C] problem s kazalci

Oddelek: Programiranje
141154 (915) BigWhale
»

strcpy reče segmatation fault

Oddelek: Programiranje
101302 (1253) MasterMind
»

Pointer-ji v C-ju

Oddelek: Programiranje
291550 (1248) rokpok
»

kazalci in polje

Oddelek: Programiranje
51500 (1421) rasta

Več podobnih tem