tömb felépítése

 ( BimbaLaszlo | 2010. május 7., péntek - 9:44 )

Azt tudom, hogy egy egydimenziós tömb az általa mutatott memóriaterület első elemének címét tárolja, és hogy egy töbdimenziós tömb visszavezethető egydimenziós tömbökre, de hogy tudom lekérdezni a tömb (mutatójának) memóriacímét és az általa mutatott memóriacímet? (tehát az első elem címét) Az ok, amiért ezt kérdem a következő:

#include 

int main( void )
{
    /* REKURZIV MUTATO
     * Ugyan nem igazan ertem, hogy hogy mukodhet, mert elsonek az egyelosegjel
     * jobb oldalat kene ertelmeznie, de azt nem lehet, mert itt meg a mutato nem
     * is letezik, de valamiert megis leforditja.
     * Sajat magara mutat. Azert char tipusu, hogy szembetunobb legyen a *mutato
     * jelentese - a benne tarolt adat (azaz a sajat cimenek) utolso bajtjat veszi
     * csak figyelembe, tehat a &mutato utolso ket hexadecimalis szamjegye lesz
     * kiirva a *mutato hatasara. (valszeg a memoriaban forditott sorrendben
     * vannak a bajtok, es ezert nem az elso ket hexa szamot irja ki) Ha az ertek
     * legelso bitje 1, akkor negativ szamnak tekinti es kiegesziti 4 bajtosra - ez
     * a szam ele irt 'ffffff'-bol latszik - de ha a "%x" unsigned int karit var,
     * akkor miert nem nullakkal tolti fel? */
    {
        char
            *mutato = (char *) &mutato;

        printf( "& mutato   %p\n"
                "  mutato   %p\n"
                "* mutato   %x\n\n",
                &mutato, mutato, *mutato
        );
    }

    /* TOBBDIMENZIOS TOMB
     * Miert ugyanaz mindegyik ertek, mikozben ez nem rekurziv mutato? */
    {
        char
            tomb[3]  = "ABC";

        printf( "& tomb     %p\n"
                "  tomb     %p\n"
                "* tomb     %c\n",
                &tomb, tomb, *tomb
        );
    }



    return 0;
}

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

Ááááááá!
A tömb neve gyakorlatilag az első elemre mutató mutató.

Szerk: nekem nem ugyanazt írja ki, amúgy. &tomb és tomb mindkettő mutató, *tomb meg az első karakter.

Szerk2: Az első - mutato - meg nem rekurzív pointer, hanem valami szemét van benne. :-)

KisKresz

Ja, a tomb neve az elso elem cime, tomb[4] = az elso elemtol 4 elemnyi tavolsagra levo elem erteke...

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"

tomb[4] == *(tomb + 4)
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

sőt:

tomb[4] == 4[tomb]

Na igen, ezzel nehany hete talalkoztam en is. Valaki a kornyezetemben igy reagalta le: "Na ezt a szintakszist kurvagyorsan felejtsuk el, es ne is aruljuk el senkinek!"

Ezen ennyit gondolkoztál?

Sőt!

multitomb[sor][oszlop]=1; *(*(multitomb+sor)+oszlop)=1;

p=&tomb[0]; p=tomb;

void func(int *a) == void func(int a[])

Nem, akkor olvastam el eloszor a topicot.
--

()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Közben végiggondoltam. :-) mutato nem rekurzív - nem is értem, ez mit jelentene -, hanem saját magára mutat. Ezért mutato és &mutato ugyanaz. *mutato meg ennek a mutatóértéknek valamilyen karakteres konverziója.

Szerk. Ezt végigolvasva igen jót szórakoztam! :-)

KisKresz

GCC-vel fordítottam Linux alatt és nálam &tomb es tomb megegyezik... Viszont azt nem értem, hogy hogy lehet *mutato helyén szemét, mikor (bármilyen értelmetlenség is) önmagára mutat?
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

&tomb és tomb igen, mindkettő az első elemre mutat, de *tomb nem.
Azt később kijavítottam, hogy szemét, mutato önmagára mutat valóban.

KisKresz

nincs a *mutato helyen szemet.

A mutato egy (char*) tipusu valtozo, ami 32 vagy 64 bit.

a *muatato egy (char) tipusu valtozo, ami 8 bit.

Ha azt mondod, hogy
printf("%x\n",*mutato) akkor a forditoa a *mutato kiszamitasanal csonkolja azt 8 bitre (amit aztan elojelkiterjesztessel az oprendszer 32/64 biten ad at a fuggvenynek).

probald ki a kovetkezo kicsit zizisebb dolgot:

typedef void * POINTER;

int main()
{
        POINTER *mutato = (POINTER *) & mutato;

        printf( "& mutato   %p\n"
                "  mutato   %p\n"
                "* mutato   %x\n\n",
                &mutato, mutato, *mutato
        );
}

char* mutato = (char *) &mutato;
"Ugyan nem igazan ertem, hogy hogy mukodhet, mert elsonek az egyelosegjel
jobb oldalat kene ertelmeznie, de azt nem lehet, mert itt meg a mutato nem
is letezik, de valamiert megis leforditja."

Nem.
Mert ez az egyenlőségjel nem az az egyenlőségjel.
C++-ban feltűnőbb a különbség, ott egész egyértelmű, hogy ilyenkor a típus valamelyik konstruktora hívódik, és nem az = operátor.

Szóval ez itt kérlek egy kezdeti értékadás.
Először lefoglalódik a memóriaterület, aztán kiértékelődik az egyenlőség jobb oldala.

Egyébként ez az önmagára mutató mutató poénnak jó,de tökéletesen értelmetlen.

"TOBBDIMENZIOS TOMB"
Ez egyrészt nem az, másrészt tuti nem ugyanaz a 3 érték.

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

Igazad van a kezdeti értékadással, így utólag belegondolva csak annak adhatunk értéket, ami már létezik...
Valóban nem többdimenziós tömb, csak véletlen maradt benne egy korábbi elgondolásból.
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

Rekurziv mutato nincs. Ez egy mutato ami altal mutatott memoriateruleteten speciel sajat maga talahato de annak tipusa NEM MUTATO. Ha lenne rekurziv mutato akkor lehetne olyat irni, hogy (...(*(*(*mutato)))...) es az meg mindig mutato lenne a tipusa meg (char*******.....)
==
`Have some wine,' the March Hare said in an encouraging tone.
Alice looked all round the table, but there was nothing on it but tea.

Az array és a pointer nem ugyanaz. A 'tomb' egy olyan név, ami konvertálódik az első elem címére; általában nincs is olyan memóriaterület, ahol ez a cím tárolva lenne, illetve nem is tudsz neki értéket adni pl. tomb=NULL -al.

Azt hiszem, itt van a megoldás, ugyanis én alapból egy 'változónak' tekintem magát a tömböt, ami tárolja az első elem memóracímét. Viszont: ha a tömb konvertálódik egy címre, akkor a &tomb esetében a & operátor 'kiiktatódik'?
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

Nem 'iktatódik ki', hiszen más típusú lesz:

int p[2]={1, 2};
int (*q)[2]=&p;
int (*r)[2]=p; // warning

Na most tényleg összekavarodtam... o_O Ha az általam prezentált kódban &tomb és tomb ugyanazt az értéket takarja, akkor itt miért dob warning-ot a fordító a mutató típusára? Pontosabban: milyen típusú akkor a tomb egymagában? Mert ha valóban behelyettesítódik a tomb helyére az általa mutatott cím, akkor miért nem lehet az int (*r)[2] = p módon értéket adni?
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

typedef int Arr [2];
-
int p[2];
Arr p; // ekvivalens definíció p-re
-
int (*q)[2]=&p;
Arr* q=&p; // ekvivalens definíció q-ra

Vagyis p típusa 'int[2]', q típusa pedig 'int[2]' -re mutató pointer. Az, hogy a kettő ugyanaz a cím lesz nálad, az ne tévesszen meg. Más a típusuk, és a statikus típusellenőrzés szempontjából csak ez számít.

:) Elismerésem, jó tanár lennél. Honnan lehet ilyen szinten megtanulni a nyelvet - és egyátalán a programozást? Ugyanis ez a célom.
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

Köszönöm:) Őszintén szólva nem tudom a választ, csak azt, hogy én leginkább a gyakorlaton keresztül tanultam meg, és mindig utánanéztem annak, amit nem tudtam.

Öööö, amit imp bemutatott neked, az tök alap dolog, ha ennyit nem tudsz álmodból felkeltve, akkor semmit sem tudsz a C-ről.

Tudom, hogy 'semmit' sem tudok, ezért tanulom most. De egyébként ahoz képest, hogy tök alap dolog, nem igen találtam róla leírást - mindig csak az indexekről van szó, meg hogy mire mutat a tömb, de arról, hogy a tömb nem egy címet tartalmazó változó, hanem egy 'define konstans szerű cucc', arról nem olvastam. (csak azt, hogy nem lehet megváltoztatni az értékét)
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

Akkor kezdésként javasolnám a Kernighan-Ritchie-féle "A C programozási nyelv" című alapművet. Rengeteg alapdolgot meg lehet belőle érteni.

(egyébként ha guglival rákeresel, még az internetre felrakva is megtalálod magyarul ;-)

Igazából megvan, meg van még miből tanulnom, de jobb szeretem 'akció közben' megtanulni a dolgokat és a könyveket referenciaként használom az aktuális problémám megolásához - kikeresem az adott függvény leírását, vagy talán valamilyen feladatmegoldást és kész. Tudom, hogy rossz szokás, csak sajnos elég kevés időm van a tanulásra, de úgy látom tényleg muszály lesz nekiülnöm az alapoknak a (tudatlan) termelés helyett...
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

szerintem nem lehet konyvbol/szabvanybol megtanulni az alapokat.
Lehet nagy arccal mondani, hogy 'ez es ez mar itt es itt is le van irva, el kene olvasni' csakhogy az informatika tanulasa nem igy mukodik. Ha nem akadsz bele a problemaba, nem jegyzed meg a megoldast.
Ez egy teljesen jo kerdes volt, a viszontreagalasaid teljesen jok, sacc/kb ez a legtobb es leggyorsabb, amit tanulasbol ki lehetne hozni.

"szeretem 'akció közben' megtanulni a dolgokat"
Naon helyes! Így is kell.
--
unix -- több, mint kód. filozófia.
Life is feudal

Kúlság, nőtt a májam, de azért tényleg kell valami alapot adni a dolgoknak. Az a baj, hogy... Na, konkrét példa: a programozás mellett szoktam hébe-hóba matekozni. Most épp a szögfüggvényeket akarom megérteni, pontosabban azt, hogy a számológép milyen algoritmust használhat az adott szög szinuszának, tangensének, stb. kiszámolásához. Van egy elméletem, ami a húrokkal kapcsolatos, ezért - mint egy referencia előkapom Obádovics Matematika bibliáját, odalapozok a húrokhoz, és kilesem, ami kell anélkül, hogy érteném a hátterét. A programozásban is így vagyok, annak ellenére, hogy pont az alapokat akarom megtanulni. Nem jó ez így. Le kell ülni és legalább egyszer átrágni magam a KnR-C, a C in a Nutshell és a C: The Complete Reference útvesztőin, persze közben gyakorolva a tanultakat.
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

Az igazán alapokat érdemes megtanulni, akár könyvből. C-ben az igazán alapokba beletartoznak a mutatók. Ezeket könyvből sokkal gyorsabb megtanulni, mint itt kérdezgetni. Utána viszont tényleg a saját szenvedéséből tanul legjobban az ember.

Az a szerencséd egyébként, hogy ha C-ben, C++-ban tudod az alapokat, akkor szinte minden nyelven tudod az alapokat.

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

Speciell ezért is választottam a 'legnehezebb nyelvet', mert ha a nehezet megértem / megtanulom, a könnyebb számomra még könnyebb lesz - magát a programozást is igazán assembly-vel kezdetem el és ezért utólag is hálás vagyok a sorsomnak. (Nem önszántamból kezdetm el az assembly-t, viszont megtetszett, ezután végigrágtam Peter Norton - Az IBM PC Programozása Assembly Nyelven c. könyvét. :) )
--
Azt akarom, hogy az emberek ne kényszerből tanuljanak, hanem azért, mert tudni akarnak.

char * valtozo1
char valtozo2[]

az elso egy pointer, es balertek (futasi idoben letezo valtozo) a balertek azt jelenti, hogy ertelmes a kovetkezo muvelet:
valtozo1 = 12

a masodik egy pointer, es jobbertek (csak forditasi idoben letezik) a kovetkezo muvelet invalid:
valtozo2 = 12

1 dimenzios tombot C -ben ketfelekeppen tudsz hasznalni:

char *buff; /* letrehozod a pointert, mint valtozot */
buff = (char *)malloc(20); /* futas idoben helyet allokalsz es ennek a helynek a cimet atadod a valtozonak)

Hasznald tombkent:
buff[1]='c';

felszabaditod:
free(buff)

Masik modszer:
char buff[20]; /* letrehozl egy memorateruletet, aminek elejere hivatkozhaszt a buff jobbertekkel*/

buff[1]='c'
/*felszabaditani nem kell */

Akkor ket dimenzios tomb, oks?
char buff[10][20];

for( i =0; i<10; i++) for( j=0; j<20; j++) buff[i][j]='c'
--------
char **buff;
buff=(char**)malloc(10*sizeof(char *));
for(i=0; i<10; i++) buff[i]=(char *)malloc(20);

for( i =0; i<10; i++) for( j=0; j<20; j++) buff[i][j]='c'

for(i=0; i<10; i++) free(buff[i]);
free(buff);

ettol szinte kovethetetlen a C nyelv.
Letezik char *alma[]; konstrukcio is.
Szerintem, ovakodj az ilyenektol.

mit jelent a [] a c-ben?

van egy dereferencia operator: *
100 <- ez egy 100 ertek (int)
*100 <- ez a 100 -as memoriacimen levo cucc

char * buff
buff <- ez egy valtozo, pointer tipusu
*buff <- ez egy char, az elobbi pointer altal mutatott memoriacimen

buff+1 <- ez egy memoriacim, a buff altal mutatott cim utan eggyel
*(buff+1) <- ez egy char a buff+1 cimen
buff[1] <- ez egy char a buff+1 cimen
1[buff] <- ez egy char a 1+buff cimen

a[b] minden kiertekelesben egyenlo *(a+b) -vel

Van egy masik operator, a referenciakepzo operator: &

char a; <- ez egy valtozo
&a; <- ez ennek a valtozonak a cime

char buff[4]; vagy char * buff; most mindegy
&buff[2] ez egyenlo &(*(buff+2)) ez egyenlo buff+2 ez egy cim

char buff[4]
&buff <- invalid, jobberteknek nincs cime

char *buff;
&buff <- valid, a buff valtozora mutato pointer (tipusa char **)

char buff[4];
&buff <- invalid, jobberteknek nincs cime

Valójában a buff lvalue, de nem modifiable lvalue (ld. C standard draft (6.3.2.1)),
ezért a &buff érvényes.

char *mutato = (char *) &mutato;

alatalaban egy definicoban csak a mar definialt ertekeket lehet felhasznalni. KIVETEL hogy nem definialt mutatot fel lehet hasznalni specialis korulmenyek kozott (ha kepes a fordito a pointer tipust felismerni). Belefutottal ebbe a kivetelbe.

ez a kivetel a kovetkezo konstrukcio miatt van:

struct linkedlist {
     int elem;
     struct linkedlist * next;
}

Ez a linkedlist egy egészen más probléma, mert ott csak a típusnévre hivatkozunk a típus definíciója előtt.

A fenti mutatónál pedig látszólag az objektum címére hivatkozunk az objektum létrehozása előtt.

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