arr[i+1] vs. arr[i]++ - mi a kulonbseg? [Megoldva]

 ( Tomi87 | 2013. március 15., péntek - 0:33 )

Ugy gondoltam, ha adott egy int arr[] utobbi fogja a pointert es egy int-nyi memoriaval "odeppakolja", hogy arr[] kovetkezo elemere mutasson. Ez effektive ugyanaz lenne, mint arr[i+1]. Ugy tunik tevedtem. El tudna valaki magyarazni mi is tortenik ha arr[i]++-t hasznalok?

A teljesseg kedveert: http://pastebin.com/pkp7wTvz

Valahogy csak nem birta helyesen megjeleniteni...

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ő.

arr[i+1] - pointert odébblökdösi eggyel, ekvivalens: arr++
arr[i]++ - az i. elemet növeli eggyel, ekvivalens: *arr++

Nem?

Ilyenkor aztan fogom a fejem :) Felreertettem az angol magyarazatot (i-edik elem helyett i-t ertettem, ami elegabszurdnak tunt, mivel az is) es nem lattam a nyilvanvalot, igy mar masodik napja torom ezen a fejem.

Koszonom.

Csak hogy keverjek még kicsit rajta:

http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html

Eszerint tévedtem, arr konstans, így azt nem lehet pointeraritmetikával inkrementálni, kell egy arr-ra mutató ptr pointer, és akkor lehet ptr++-t mondani neki.

(Egyébként ez a legrosszabb, ha ez ember végtelen ciklusba kerül valami hülyeségen/félreértésen).

Igaz. Most neztem utana a konyvben amit olvasok. Arra emlekeztem, hogy pointeraritmetikaval kezelte az array-t (magyar megfeleloje mi?? :) ) es arra is, hogy arr "nem egeszen pointer" ezert _bizonyos_ dolgokat nem lehet vele megtenni, de arra pont nem, hogy ezt sem (talan pont azert, mert ezt csinaltak vele, csak valahogy kimaradt, hogy kellett hozza egy "igazi" pointer is. Vagy az ezzel parhuzamos alvaskorrekcio kiserletem ami adott 2 nap alatt 2x20 oranyi ebrenletet de hatasa nem nagyon van :( )

btw nem ugy tunik, hogy felreertettem volna, inkabb a tag irt hulyeseget: "[...]you're incrementing i twice in the loop", de erre ra is jottem volna, ha jobb adatokkal tesztelem. 11,22,33,44 volt amivel probalgattam es el lehettem foglalva az oromommel, hogy nem 1,2,3,4 mert akkor eszre sem vettem volna. (Az utolso elem torlodik, csak kimaradt a pelda-loop-bol)

:)

jobbertek: ami egy egyenlosegjelnek csak a jobb oldalan allhat.
balertek: ami egy egyenlosegjelnek allhat a bal oldalan.
A C nyelvben nincs tomb. Pointerek vannak (tipusosak), valamint jobbertek-pointerek amivel olyan-mintha-tomb jatekot lehet jatszani.

Peldaul az 1 (szammal leirt konstans) jobbertek.

int c;  // az c balertek
c = 1;  // valid
1 = c;  // invalid

int *pc;         //  az pc balertek, de nincs kezdoerteke
pc = malloc(4);  //  valid, kezdoerteket adunk a pc -nek
*pc = 1;         //  valid
pc[0] = 1;       //  valid, es megegyezik az elozovel


int ac[1];       // az ac jobbertek, es van kezdoerteke
ac = malloc(4);  // invalid
*ac = 1;         // valid, a *ac kifejezes mar balertek
ac[1] = 1;       // valid, megegyezik az elozovel
1[ac] = 1;       // valid, megegyezik az elozovel, udvozlunk a C vilagaban :-)

*ac = 1; // valid, a *ac kifejezes mar balertek
ac[1] = 1; // valid, megegyezik az elozovel

Nem inkabb
*ac = 1; // valid, a *ac kifejezes mar balertek
ac[0] = 1; // valid, megegyezik az elozovel

Hiszen *ac != ac[1]

igen, thx.

C-ben van tömb, lásd lejjebb.
Az 1 meg literál.
Amire egyébként gondolsz az az, hogy a [] operátor szemantikája érdekes.
----
India delenda est.
Hülye pelikán

mit nevezunk tombnek.
sokkal jobban jar az egyszeri C programozo, ha ugy tekint a nyelvre, hogy nincs benne tomb. Pointerek vannak, csak eppen egyes pointereket a linker ertekel ki, nem tartozik hozza memoriaterulet.

En a tombtol elvarnam, hogy legyen valami minimalis index validacio, keszites, torles. Ez a *((A)+(B)) egy vicc. megoldottak pointer aritmetikaval. Tobb dimenzios tomb sincs, csak egydimenzios tombok tombje.

Ugyane tartozik a C-beli string, jobban jar a C programozo, ha ugy tekint ra, hogy nincs a C-ben string, csak karakterekre mutato pointer. Foleg az elso
p="ablak";
p[2]=' ';

Utan.

kedvencem meg:
i["ablak"]

Oké, tömb-szemantikán lehet vitatkozni, akár még igazad is van, valóban elég szegényes a C tömb fogalma, már ami a fícsöröket illeti. De itt mire gondoltál: "legyen valami minimalis index validacio"? Ez teljesen szembemenne a C filozófiájával, ha nem valami fordítási idejű dologra gondolsz.
----
India delenda est.
Hülye pelikán

Szerintem arra gondolt, ami pl. anno Turbo Pascalban is volt: egy fordítási opció, amivel lehet kérni, hogy a futási időben történő ellenőrzést a fordító fordítsa bele a programba. Nem csak kezdőknek lenne hasznos.

Az a baj ezzel, hogy a C nem véletlenül nem korlátoz semmi ilyesmit. Lehet, hogy te tudod, mit csinálsz, és szándékosan indexelsz kívül.
----
India delenda est.
Hülye pelikán

A dolog pont forditott, az emberek nagyon kis szazaleka indexel szandekosan a tombon kivul - es a jelenlegi megoldas miatt a validacio megkerulheto lenne pointer aritmetikaval, ha _tenyleg_ kell.

Viszont ha tombkent tekintek a tombre, akkor igenis ne engedjen tulindexelni.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal

És azt mégis hogyan csinálnád anélkül, hogy futásidőben ellenőrzöl?

Márpedig a C egy hardware közeli nyelv, egyes vélemények szerint csak egy fancy assembler, és ezzel nem egyeztethető össze a futásidejű ellenőrzés minden egyes indexelésnél...

Arról nem is beszélve, hogy egy arr[i] kifejezés csak az esetek ha 10%-ban vonatkozik egy int arr[10]; jellegű tömbre, minden más esetben az ellenőrzés kb lehetetlen, azaz mindössze hamis biztonságérzetet ébresztene egy ilyen feature...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Arról volt szó, hogy fordítási kapcsoló (mert a runtime mindig tudja, mekkora a tömb), és ez meg is lenne oldható, csakhogy. Hogy jelezze a hibát? Ha már jelzi a hibát, akkor nem lenne egyszerűbb neked ellenőrizni az indexhatárokat? Vagy ellenőrizzen, és mindenképp hasaltassa el a programot, hogy legalább core legyen? Ennek lenne értelme, de erre való a valgrind.
----
India delenda est.
Hülye pelikán

"mert a runtime mindig tudja, mekkora a tömb"
Ez nem igaz, csak olyan esetben, ha te magad foglaltad le. Kepzeld el azt az esetet, amikor egy masik kodbol (mas altal keszitett kodbol) kapsz meg egy pointert, ami egy tomb kezdocimere mutat. Nem tudod forditasi idoben ellenorizni, hogy sosem indexeled tul.

Futási időről volt szó, azért emlegettem a runtime-ot és nem a fordítót.
Nézzük a négy esetet:
1. Saját kód, konstans méretű tömbbel a stacken vagy a statikus tárterületen (ez a leggyakoribb, a string literálok miatt). Itt nyílván ismeri a fordító és a runtime is a méretet.
2. Saját kód, dinamikusan foglalt tömbbel. Itt szintén ismeri a méretet a runtime, ugyanis a free valahonnét tudja, mennyit kell felszabadítani.
3. Más kódja, dinamikusan foglalt tömb: lásd 2. pont.
4. Más kódja, konstans méretű tömb. Ez nehezebb dió, de mint fentebb mondtam, fordítási kapcsolóról van szó, akkor simán megcsinálhatja a fordító, hogy a stacken lévő tömböket is megméretezi, és akkor a runtime is tudja.

Szóval nem látom a problémát, azon túl, hogy felesleges.
----
India delenda est.
Hülye pelikán

Most akkor futasideju, vagy forditasideju ellenorzesrol beszelunk? Mert ez a szal a forditasideju dologrol szol, te is errol beszeltel meg itt.

Most meg mar futasideju dolgokrol.

Dontsuk el, mit akarunk.

Amugy a mas altal allokalt memoriarol nem feltetlenul tudod te, hogy hogyan allokalodik. Nem feltetlenul kell ugyanazt a memoria allokatort hasznalnia a masik libnek, mint a te allokatorod. mallocbol is tobbfele van.
Ezek persze egymas belso allokacios leiroit nem is latjak.

Szerintem te nem érted a dolgot. Végig futási idejűről volt szó, mint kiderült abból, hogy fordítási időben lehetetlen. Aki felvetette, nyílván futási idejűre gondolt, én csak megerősítést kértem.
----
India delenda est.
Hülye pelikán

De futasi idoben is lehetetlen C eseten. Nem te kontrollalod mas mallocjat. Onnantol kezdve meg nem mukodik a dolog.
Szabvany C-ben ezt nem tudod megcsinalni, ehhez plusz runtime support kell.

Igen, erről van szó, a plusz runtime supportról. Olvass már vissza, az isten áldjon meg. Fordítási kapcsolók meg minden. Nyelvi szinten jelenleg lehetetlen, ezért kell hozzá új fícsör. Mármint kéne, ha lenne értelme az egésznek.
----
India delenda est.
Hülye pelikán

Ebben a hozzaszolasban:
http://hup.hu/node/122809#comment-1582223
irtad le, hogy nincs problema, gond nelkul mehetne a dolog futasi idoben.

De nem mehet, csak akkor, ha korlatozod a runtime altal elerhetove tett memoria allokatorokat, azaz minden jelenlegi libet nem tudsz integralni ez ala. Azaz csak akkor ertelmes a dolog, ha MINDEN lib hasznalja, azaz maga a libc is. Viszont ehhez magat a libc-t kene ugy modositani, hogy ne feleljen meg a C szabvanynak, akarmilyen forditasi kapcsolod van.

Szoval jelenleg runtime tamogatassal sem megoldhato.
A nyelvnek pedig nem resze a runtime (kulonben nem is lehetne operacios rendszereket C-ben implementalni), csak a standard konyvtarat irja elo az alkalmazasok (de nem a rendszer) szamara a szabvany.
Szoval az, hogy nincs ra nyelvi elem, meg nem lenne onmagaban problema, a C standard libet kellene hozza modositani.

Akkor fussunk neki mégegyszer...

Ha van egy arr[i] kifejezés, akkor arról csak abban az esetben tudunk bármit mondani, ha előtte az arr (ezen a néven) az 1-es pontodnak megfelelően lett foglalva.

A 3 másik verzió esetében arr már csak egy közönséges mutató, és semmit sem tudunk róla.
(A free meg úgy működik, hogy feltételezi, hogy a mutatott cím előtt talál majd valami fejlécet. Ha nem a lefoglalt terület 0. elemére mutató mutatót kap, akkor elszáll. A free esetén ezzel együtt lehet élni, de egy arr[i] kifejezés esetén nem.)

De még ha megoldható is lenne, egyszerűen lassú (plusz egy memória olvasás és összehasonlítás), nem véletlen, hogy C++-ban sincs ellenőrzés az operator[] esetében (vector,string,array,stb).

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

"a runtime mindig tudja, mekkora a tömb"

Ahogy persicsb is mondja, egyrészt ez nem igaz, másrészt akkor minden mutatóra külön követni kellene, hogy mégis éppen melyik lefoglalt tömbre mutat, és annak mekkora a mérete.
(Mert ugye egy mutató nem feltétlen mutat a terület elejére...)

Debugra lehet használni efence-et, vagy DUMA-t, ha a Valgrind túl lassú.

Akinek meg általában ilyen elvárásai vannak, az ne akarjon close to metal programozni, és használjon valami magasabb szintű nyelvet (C#, Java, Python, Ruby, stb.)...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Lásd fentebb, lehetségesnek bőven lehetséges, legalábbis én nem látok problémát.
A pointerek meg oda mutatnak, ahova akarnak, ezt is kitárgyaltuk feljebb, ha az ember mutatózik, akkor feltételezzük, hogy tudja, mit csinál, és ez nem számít hibaesetnek, nem is ellenőrizendő.

Az hátsó pontokkal viszont abszolút egyetértek, mondjuk nem kell annyira magasra menni, elég eggyel :)
----
India delenda est.
Hülye pelikán

Sokszor az ember kenyszerbol C-zik, pl. egy interpretalt nyelvnel tul lassu a feldolgozas, es valami gyorsabbra van szukseg. Nem feltetlen a C-nek kellene annak lennie, de ahhoz van tamogatas.

Rengeteg ilyet latok a Ruby vilagaban, hogy vagy valami olyan illesztoreteget kell irni a meglevo C konyvtarhoz, amihez a SWIG keves, vagy pedig egyszeruen meg a legszarabb C kod is koroket ver az interpeterben megvalositott megoldasra. Es mondjuk egy C Ruby interpreterhez a budos eletben nem irsz C# kodot.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal

Na és miért gyorsabb a C kód? Többek között azért mert nem csinál ellenőrzést minden egyes indexelésnél.
Meg persze nem csinál egy csomó más dolgot amit egy absztraktabb nyelv igen.

A sebesség nincs ingyen, cserébe oda kell figyelni, és nem csak hányni a kódsorokat... :)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Egy _interpretalt_ nyelvhez kepest meg egy olyan nyelv is gyorsabb, ami ellenorzeseket csinal. Ne feledjuk el, hogy peldaul a Java mindenfele ellenorzeseket csinal, bizonyos kornyezetben megis tud gyorsabb lenni, mint a JRuby, egyszeruen azert, mert ez utobbi meg mindig tobbe-kevesbe interpretalt nyelv.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal

Problema, hogy C-ben nincs lehetoseg az indexhatarok egyszeru ellenorzesere. Hiszen egy tomb az csak egy pointer, es a pointeraritmetika megengedi, hogy tulcimezd a tombot. A C tomboknek nincs merete. Tehat egy arr[10] -es tombnel a pointeraritmetika miatt teljesen legalis kod az arr[12]. Es a runtime ellenorzes szerintem meg pont azert nincs, mert minden tombhoz plusz metaadatokat kellene valahogy fuzni - az pedig meboritana a tomb memoriaterkepet.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal

1. A tömb nem pointer.
2. A tömbnek van mérete.
3. Az arr[10] az pont egy nagyon jól méretezett tömb.
4. Metaadatokat így is letárol a runtime, ugyanis a freenek tudnia kell, mennyi volt a malloc. Ha ezt a statikus méretű tömbök mellé (vagy ugye a variable length arrayek mellé) is letárolod, kész a runtime support egyik fele.
----
India delenda est.
Hülye pelikán

http://hup.hu/node/122809#comment-1582306

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Azért nem válaszoltam arra, mert semmi értelme nem volt. Az [] operátor működésén kell változtatni (feltételesen). A runtime mindig tudja, tudhatja, hogy az adott mutató mibe mutat, és az mekkora.
----
India delenda est.
Hülye pelikán

Ha van egy ptr mutatóm, és elkezdem használni ptr[i] alakban, akkor a runtime honnan a búbánatból fogja tudni, hogy mégis mekkora az a terület amit lefoglaltam? Ehhez vagy végig kéne szaladni a lefoglalt blokkokon (amit tipikusan nem szoktak tárolni egyébként), hogy kiderüljön minek a közepére is mutat a ptr, vagy a ptr-nek kéne tartalmazni egy második mutatót ami a fejlécre mutat.

A free trükkjét azért nem használhatod, mert ott az az előfeltétel hogy az átadott mutató az a lefoglalt terület 0. elemére mutat, így a fejléc helye kiszámolható. De ezt az előfeltételt nem tudod garantálni tetszőleges ptr[i] kifejezésre, sőt azt sem igazán tudod ellenőrizni konstans időben, hogy ez a feltétel teljesül-e.

Szóval nem, nem tudod a [] operátor működését még feltételesen sem változtatni, maximum a statikus/stacken foglalt tömb esetén, azt is csak akkor ha azt nem egy másik mutatón keresztül éred el.

Illetve de, tudod, de azt úgy hívják, hogy Valgrind.

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

maximum a statikus/stacken foglalt tömb esetén, azt is csak akkor ha azt nem egy másik mutatón keresztül éred el.

Igen, egyetértünk!

Én - mivel fentebb az igény egyik megfogalmazója vagyok - pontosan csak ennyit szeretnék. Nem pointeren keresztül elért, statikus globális és lokális tömbök közvetlen használatát kéne ellenőriznie a fordítónak (az ellenőrzéshez szükséges runtime kódot automatikus odaraknia). Ill. ezekkel ekvivalens még a dinamikusan foglalt struktúrában levő fix méretű (a struktúrán belül statikus) tömböknek a kezelése is. Ezekben az esetben a fordító tudja, hogy az adott tömböt meddig szabad indexelni. Ez egy "syntactic sugar"-szerű dolog lenne, hiszen én magam is beírhatnám oda az assertet, a fordító pusztán megkímélne attól, hogy ezt kézzel kelljen megcsinálnom.

És ez pont az, amit a Turbo Pascal tudott 1990-ben.

1. Mi lenne a hibajelzés módja? Mert ettől függ, hogy van-e értelme az egésznek.
2. Nem érdemes összehasonlítani a Pascalt C-vel, teljesen más a két nyelv célja.
----
India delenda est.
Hülye pelikán

1. Ugyanaz, mint a Turbo Pascalnál volt anno: "Runtime Error" + abort()
2. Azt hadd döntse már el a felhasználó, hogy ő mit szeretne.

1. Ezt támogatom.
2. Ez viszont butaság. A felhasználó döntse el, hogy mit szeretne, és használjon egy olyan nyelvet. A nyelvfejlesztők meg eldöntik, hogy a felhasználóik többsége mit szeretne, vagy ilyen alapvető nyelveknél, mint a C, a felhasználóik összessége számára mi lenne gyümölcsöző és visszafele kompatibilis.
----
India delenda est.
Hülye pelikán

"Nem pointeren keresztül elért, statikus globális és lokális tömbök közvetlen használatát kéne ellenőriznie a fordítónak"
Ami a használati esetek olyan elenyésző százaléka, hogy egyrészt felesleges, másrészt félrevezető ha valaki feltételezi, hogy a fordító fogja a kezét...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Ami a használati esetek olyan elenyésző százaléka, hogy egyrészt felesleges

Azt hadd döntse el a felhasználó, hogy neki felesleges-e. Nekem pl. felesleges a printf paraméterek ellenőrizgetése és warningok dobálása, másnak nem.

másrészt félrevezető ha valaki feltételezi, hogy a fordító fogja a kezét...

Nem feltételezi. Egyszerűen csak megírja a szar kódot a kezdő Dömötör, és random shit happens.

Minden feature-re találsz felhasználót aki szerint az a legfontosabb, a kérdés az, hogy az ilyen felhasználók száma és a szükséges munka mértéke milyen arányban áll egymással.

A printf ellenőrzés pl egy elég egyszerű dolog, futáskor nem kerül semmibe. Bármilyen futás idejű ellenőrzésről ez nem mondható el.

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Akkor mégis miről beszélsz? Tényleg. Te is leírod, hogy lehetséges, hiszen a valgrind megcsinálja. Végig arról volt szó, hogy fordítási kapcsolóval lehessen egy plusz ellenőrzést beletolni, amitől majd a runtime ezt megcsinálja. Akkor mégis melyik része nem adódik össze a fejedben? Indulj ki a triviális megoldásból: valgrindet fordít bele. Innen lehet karcsúsítani.
----
India delenda est.
Hülye pelikán

Leírtam, hogy miért lesz rohadt lassú. (Mint ahogy a valgrind is az.) Azt is, (és mások is), hogy miért kellene speciális runtime hozzá. Ami azt vonja maga után, hogy minden függőségnek is ezt a spec. runtime-ot kéne használni.
Azaz ez a feature jószerivel használhatatlan lenne.

Ha meg mégis kell neked ilyesmi, ott a valgrind, az efence. Mennyivel rosszabbak ezek mint egy mágikus compiler kapcsoló?

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Oké, feladtam. Amikor azt írod, amit én is írtam, és még mindig nem fogod fel, hogy miről beszélgetünk, akkor nincs hova tovább.
----
India delenda est.
Hülye pelikán

Ha ugyanazt írtad volna, nem vitatkoznál...

Én nem azt mondtam, hogy ilyesmi abszolút lehetetlen, hisz ott a valgrind amit tud hasonlókat.
Te azt próbáltad bizonyítani, hogy lehetséges volna egy lightweight, jól használható megoldás, kihasználva azt amit a compiler tud.
Én leírtam, hogy miért nem igazán lehetséges ilyen lightweight megoldás...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Mutass már rá, hol írtam bármiféle ilyesmit. Te ellenben többször is leírtad, hogy lehetetlen.
----
India delenda est.
Hülye pelikán

Mivel én voltam az első aki felhozta a valgrindet, az efence-t és a duma-t, nyilván nem arról beszéltem, hogy bármi ilyen jellegű ellenőrzés lehetetlen.

Arról beszéltem, hogy miért nem fog menni ez egy szimpla fordító kapcsolóval a jelenlegi runtime mellett, miért problémás egy speciális runtime használata, és miért lesz használhatatlanul lassú.
Mert nyilván ha nem tudunk gyorsabbat mint a valgrind, vagy flexibilisebbet mint az efence, akkor mi értelme lenne a fordítóba integrálni? Csak, hogy legyen még egy?

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Ha megnézed, én hoztam föl először a valgrindot.
----
India delenda est.
Hülye pelikán

Valóban, igaz, ott még az az álláspontod, hogy egy ilyen fordítási kapcsoló értelmetlen, mert nem lesz jobb mint a valgrind...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

És tegnap óta erre próbállak rávezetni, hogy még mindig rohadtul ez az álláspontom. Sehol nem állítottam, hogy egyáltalán lenne rá igényem vagy bármi, csak a megvalósíthatósága mellett érveltem.
----
India delenda est.
Hülye pelikán

A ptr[i] kifejezes eseten nem a ptr[0] mutatna az elso elemre? Onnan nem lehetne kiszamolni a metaadat cimet? Csak kerdem.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal

Pont az a lényeg, hogy semmi nem garantálja, hogy a mutató a 0. elemre mutat.
Pl ha van egy kétdimenziós sorfolytonos tömböm (pl egy kép), akkor feldolgozás közben minden további nélkül ráállíthatok egy mutatót a 23. sor 0. elemére, majd használhatom ezt a mutatót ptr[i] alakban.
Ilyenkor a ptr az eredetileg lefoglalt terület közepére mutat...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

C-ben legfeljebb annyi "runtime" van, ami inicializálja a stacket ami a függvényhívásokhoz kell.

Memory managementhez nincs runtime. Malloc, calloc, realloc és free kutyaközönséges függvények, amik maguk is C nyelven vannak megírva, te is írhatsz C-ben azonos funkcionalitású függvényeket. Lehet is párhuzamosan több memória menedzsert használni C-ben (pl. malloc+free kézzel + boehm gc allokáció).

Szóval...
A runtime mindig tudja, tudhatja, hogy ...
Milyen runtime?

Az elején bebionyítod, hogy érted, miről van szó, aztán meg értetlenkedsz. Fuss neki mégegyszer akkor.
----
India delenda est.
Hülye pelikán

Csak egy kerdes, ha a tomb nem pointer es a tombnek van merete, akkor hogyan csinalod meg, hogy egy altalad stacken lefoglalt tombot atadsz egy fuggvenynek, ami tudni fogja a tomb meretet is (hogy veletlenul se indexeljen tul)?

Ne feledd, a fuggveny az mindenfele meretu tomb fogadasara alkalmas kell legyen, hiszen megiscsak programozok vagyunk, nem akarunk felmegoldasokat csinalni.

A tömb neve kussban értelmeződik az első elemére mutató pointerként. A pointer már nem tudja, hogy ő mekkora tömbre mutat.
----
India delenda est.
Hülye pelikán

De ha egy tömbnek van mérete állításod szerint, akkor ezt egy függvényben is el kellene tudnom érni (hiszen a runtime tud róla).

Most akkor mégis van mérete, vagy tényleg pointereket dobálunk ideoda meg egy kis méretinformációt?

1. Attól, mert van mérete, hogy következik, hogy neked le kell tudnod azt kérdezni? Nekem vannak titkaim, mégsem árulom el őket neked. A runtime-nak meg lehet elárulnám.
2. Függvénybe pointerként érkezik, nem tömbként.
----
India delenda est.
Hülye pelikán

Egy titok attol valik titokka, hogy titokkent tekintunk ra. Ha egy informacio letezik, implicite lekerdezHETo. Az mas kerdes, hogy nem biztositunk utat a lekerdezesre - de ettol az informacio csak nehezen lekerdezhetove valik, nem pedig nem letezove.
--
Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal

A tomb nem pointer, hatha elhiszitek vegre:
http://c-faq.com/aryptr/ptrkindofary.html

+1, nem lehet megcsinálni.
Akinke kell futásidjű check, használjn saját containert.

Nem.

arr[i+1] ekvivalens: *(arr+i+1)

Poenos ez a C igy java utan, kar hogy 2. evben egyaltalan nincs belole felveheto tantargy (esetleg C++), csak harmadikban "Malicious software and security programming" (az viszont kotelezo).

C++-t meg inkabb hagyom, mert 1 szemeszternyit nem biztos, hogy erdemes tanulni belole, 2-re meg nem igazan lesz hely az orarendemben, ugyhogy jovore meg egy kis Java, harmadikban C.

És biztos, hogy tisztában vagy az alapokkal? A szintaktika, amit írsz, ugyanúgy működik C-ben és Javaban is, így elvileg értened kéne mi történik. Szóval nem értem, mi az annyira "poénos" a C-ben a Java-hoz képest...

+1

"A szintaktika, amit írsz, ugyanúgy működik C-ben és Javaban is"

Igen, ez igaz, es igen, ezekkel az alapokkal tisztaban vagyok. A pointerek zavartak be, valahogy ugy gondoltam en ezt, hogy arr mutasson az i-edik elemre es ehhez kepest "lokjunk" rajta meg egyet. Persze nem mukodott, mivel arr[i] == *(arr+i), tehat nem is pointer, hanem ertek.

Javaban ugyanez nem okozott volna problemat, ami azert vicces valahol.

Hát jó, te tudod, engem nem kell meggyőzni.

De ha már itt járok, érdekességképp javaslom, hogy próbáld ki, mi történik, ha nem azt mondod, hogy arr[i]++, hanem azt, hogy i[arr]++.

Kiprobaltam, javaban is, c-ben is. Javaban azt csinalja, amire szamitottam, azaz nem mukodik. Azt viszont, hogy c-ben miert mukodik, es mi is tortenik, nem ertem. Kosz a tippet, el is magyarazod?

"Azt viszont, hogy c-ben miert mukodik, es mi is tortenik, nem ertem."
Akkor nem vagy tisztaban az alapokkal.

Mint fentebb irtak, arr[i+1] ekvivalens: *(arr+i+1) azaz arr[i] ekvivalens: *(arr+i). Na, csereld meg arr es i szerepet.
i[arr] ekvivalens azzal, hogy *(i+arr). Ami meg pont *(arr + i), hiszen a + kommutativ szamokra.

Az egesz [] csak egy jeloles, a jelentese mindig a *() valtozat.

Tessek meg azokra az alapokra jobban ragyurni.

Hat ez eleg kemeny :) Az ok volt, hogy arr[i] == *(arr+i) == *(1 + arr), de a kulcs amit az utolso mondatodban irsz, azt nem sejettem, hogy c-ben ezt meg lehet toldani azzal, hogy "== i[arr]", hogy az is meg van engedve. Ezek szerint akkor [] a jobb olvashatosagon kivul abszolut semmi szerepe nincs, olyan mint a x->y...

Koszonom. Most egyelore azzal kell foglalkozzak, hogy kesz legyen aminek kesznek kell lennie, de szabadidore a "The C programming language" mar be van tarazva.

"szabadidore a "The C programming language" mar be van tarazva."

Tehat megsincsenek meg az alapok. Aki C-ben programozik, ennek a konyvnek az elolvasasaval kell kezdenie. Tenyleg.

Amugy igen, termeszetesen az i[arr] is megengedett nyelvi konstrukcio.

Azt arra valaszoltam, amit idezek is a hsz-ben, arra a reszere a problemanak, ami ugyanugy mukodik Javaban is es C-ben is (ami tulajdonkeppen le is fedi az egesz kerdesem, de nem irom le meg egyszer, hogy azok a csunya pointerek zavartak be :) ).

Igen, ami a c-t illeti ez eleg in medias res kezdes volt, ideje volt belekezdeni, ezert szereztem egy "C for java programmers" 60 oldalas kiskonyvet, felutottem a pointereknel es leprogrammoztam amit le kellett. Idokozben viszont felkeltette az erdeklodesem, utanaolvasok alaposabban.

Amugy attol, hogy megengedett, szoktak ezt hasznalni ebben a formaban? Nagyon nem intuitiv az osszes vele ekvivalens valtozathoz kepest, gondolom nem gyakori a hasznalata.

Szokták, leginkább a "ki írja a legolvashatatlanabb kódot" versenyeken. :)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Ez azért nem egészen így van. A tömb és a pointer közötti elég jól elfedett, de létező különbségek vannak.
----
India delenda est.
Hülye pelikán

Ha arra gondolsz, hogy a tombot, ha fix meretu, a stacken allokaljak, a dinamikusat pedig a heapen, akkor igen, ez kulonbseg. De mas nincs. A fix meretu tombok elso eleme ugyanugy egy pointer a stackre (a stack elemeit is nyugodtan varialhatod, igy akar a visszateresi cimet is varialhatod, ha akarod).

A kulonbseg a sizeof()-ban van "char* arr = (char*)malloc(12)" es "char tmp[12]" kozott.

Mivel az egyik esetben a stacken 1 pointer, a masik esetben meg 12 char foglalodik le. Mondom, az a kbseg, hogy a stacken foglalsz-e fix meretet, vagy a heapen dinamikus meretet.
De ettol fuggetlenul *(tmp+i) ugyanugy hasznalhato, a stack is a memoria resze, mint a heap, csak mashol van :)

http://aszt.inf.elte.hu/~gsd/halado_cpp/ch09s07.html

Ez a hiba abból fakad, hogy a tömb nem egy pointer, csak kussban konvertálódik azzá. De a tömb neve a tömböt jelképezi, az első elemre mutató pointer meg egy memóriacím az első elemre, tehát azt dereferálni köll.
----
India delenda est.
Hülye pelikán

Ez tök egyértelmű, hogy miért nem működik, hiszen nem is ugyanazt csinálod.
Ha a t deklarációja int t[], akkor az nem ekvivalens az int* t externnel.
Amikor így hivatkozol rá, akkor nem egy t első elemére mutatót kapsz meg, hanem t első elemét. Míg int* par egy mutató a tömb első elemére.

Az egyik esetben par tartalma egy memóriacím, míg t tartalma már az 1. De ez tök egyértelmű, hiszen most csinálsz a két esetben.

Így van, dereferálni kell, mivel a két deklaráció nem ekvivalens: az egyik a tömb első eleme, a másik meg egy mutató a tömb első elemére. Egyszerűen ellenőrizhető ez azzal, ha kiírod a két változó címét, printf("%x",par) és printf("%x",t) más értéket tartalmaz, így nyilván nem is működik ugyanaz az aritmetika rájuk.
Nyilván, ha a tömb első elemét szeretnéd mutatőként értelmezni, és az 1-es memóriacímre hivatkozni, akkor az runtime erorr lesz.

De ettől még a pointer aritmetika érvényes lesz, ha mindkét memóriaterület ugyanarra a helyre mutat, akár az int*-ként vagy int[]-ként van deklarálva.

"arr[i]++ - az i. elemet növeli eggyel, ekvivalens: *arr++"

Precedencia...
(*arr)++
(*(arr+i))++

Joejszakanak is:

Rég volt, hogy C-vel foglalkoztam :) Holnap átgondolom.

torolve

int arr[MERET];

1) arr[i]=arr[i+1];
vs
2) arr[i]=arr[i]++;

Ez a kérdés?

1) arr i. elemét egyenlővé teszi arr i+1. elemével
2) arr i. eleme egyenlő lesz az arr i. elemével, majd az arr i. elemét növeli 1-el (persze ezt a fordító optimalizálja). Ezt a kifejezést tehát nem sok értelme van leírni..

2) kiértékelése implementációfüggő, szabvány szerint nem lehet tudni, hogy a másolás vagy a növelés hajtódik végre előbb.

mindharom operator precedenciaja kulonbozik, egyertelmu lesz a vegrehajtas sorrendje

szerintem osszekeverted a fuggveny parameter kiertekeles sorrendjevel

---
Egy jól megállapított probléma félig megoldott probléma.
- Charles Kettering

Erről van szó:

arr[i]=arr[i]++;

Szerintem a fordító úri jókedve alapján választhat az alábbiak közül:

1.
tmpval=arr[i];
arr[i]= tmpval; /* értékadás */
arr[i]= tmpval+1; /* poszt-inkrement */

2.
tmpval=arr[i];
arr[i]= tmpval+1; /* poszt-inkrement */
arr[i]= tmpval; /* értékadás */

Amire gondoltok az az, hogy a kiértékelés sorrendje nem kötött. De ez itt nem szempont. A jobb oldal értéke konkrétan az eredeti arr[i], és mindegy, hogy a bal oldalt mikor értékeli ki, mert úgyis felülírja (eleve nem az értékét veszi, hanem a címét).
Akkor lenne izgalmas, ha

arr[i] = arr[i++];

Itt tényleg nem lenne mindegy a kiértékelés sorrendje.
----
India delenda est.
Hülye pelikán

Igaz, de szerintem az előbbi példámban szereplő két lehetőség sem azonos eredményt ad.

Csakhogy a 2. lehetőség nem fordulhat elő. A posztfix ++ szemantikája ilyen.

Hülyeségeket beszélek. Ne figyeljetek.
----
India delenda est.
Hülye pelikán

Kicsit részletesebben? Miért nem lehet ez:

arr[i]=arr[i]++;

tmpval=arr[i];
arr[i]= tmpval+1; /* poszt-inkrement */
arr[i]= tmpval; /* értékadás */

A posztinkrement szabálya az, hogy az inkrementálás 'valamikor később' történik meg... hát ez teljesül itt is. (Na jó, természetesen nem ennyire egyszerű, mert vannak pontok, ami előtt garantáltan megtörténnek a mellékhatások, mint pl az utasítás vége)

Pontosan erre gondoltam.

Ha leszedjük a felesleges körítést, akkor ez az a=a++; esete, ami undefined behaviour.

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o

Teljesen igazatok van, implementáció függő.

GCC 4.6.3 így implementálja x86-on:

i=i++;
83 45 fc 01 add DWORD PTR [ebp-0x4],0x1

arr[i+1] - arr tömb i+1 -ik eleme
arr[i]++ - arr tömb i-ik elemének inkrementálása
arr[i+1]++ - arr tömb i+1 -ik elemének inkrementálása

-fs-
Az olyan tárgyakat, amik képesek az mc futtatására, munkaeszköznek nevezzük.

Ha nem tevedek:

arr[i+1] = i+1. eleme az arr tombnek (a tombelem erteke nem valtozik)
arr[i]++ = arr i. elemet noveli eggyel (a tombelem erteke valtozik)


"Belépés díjtalan, kilépés bizonytalan."

Mostmár ideköhögök én is:

1. arr[i+1] - indexálást változtatod, ez egy értékkel tér vissza, önmagában nincs hatása.

int tmp = i + 1;
arr[tmp];

2. arr[i]++ - a tömbben referált értéket változtatod, ez önmagában is megállja a helyét.

int tmp = arr[i];
tmp++;
arr[i] = tmp;