structura pointer

Fórumok

Kicsit belekeveredtem és már nem tudom hogy címezzek meg egy structura pointert.Lenne ez:


typedef char * char_pointer;

struct data_struct
{
   char_pointer data1;
   char_pointer data2;
   char_pointer data3;
};

......

struct data_struct *data_pointer;
char_pointer data_array[sizeof(struct data_struct)];

......

data_pointer=(struct data_pointer *)data_array[0];
printf("%s\n",data_pointer->data2);

...

Tehát egy a tömb elemei pont úgy követik egymást, mint a struktúra elemei szerintem.
De a kiiratásnál "Segmentation fault"-et kapok.

Mit is ronthatok el?

Hozzászólások

Évek óta nem láttam C-t, úgyhogy kéretik ennek megfelelően kezelni a dolgot, de a a sizeof(struct data_struct) nem három, hanem 12 lesz (32 bites pointerek esetén) szerintem.
Így a data_array-d 12 db (jelen esetben inicializálatlan), char típusra mutató mutatóból fog állni.
--
geri / otperc.net

A gond ezzel van:
data_pointer=(struct data_pointer *)data_array[0];

Ugyanis: data_array[0] egy char lesz (nem char* !!), amit a tipus kenyszeritesnel atalakit egy cimme (de az erteket alakitja!).
Neked inkabb ilyesmi kellene:
data_pointer=(struct data_pointer *)data_array;

Vagy:
data_pointer=(struct data_pointer *) &data_array[0];

Kozben rajottem, hogy beneztem.
char_pointer data_array[sizeof(struct data_struct)];
Ez ugyanis egy char ** lesz, igy az elozo hozzaszollasom hulyeseg.

"If you must mount the gallows, give a jest to the crowd, a coin to the hangman, and make the drop with a smile on your lips" The Wheel of Time series

Nincs mit.

Amugy ezt azert csinaltad igy, mert igy akartal neki memoriat foglalni?
Ha igen, akkor inkabb a malloc/calloc fuggvenyek ajanlatosak a C-ben (vagy a new operator a c++-ban).

pl.:
struct data_struct *dp = (struct data_struct *) malloc( sizeof( struct data_struct ) );

"If you must mount the gallows, give a jest to the crowd, a coin to the hangman, and make the drop with a smile on your lips" The Wheel of Time series

Lenne egy hosszú string, amibe adatok vannan szeparátorral elválasztva. A szeparátorokat kicserélem 0-ra és a tömb elemeit meg ráállítom az adatokra, majd hogy könnyen lehessen utánna kezelni az adatokat, így a struktúra pointert is ide rakom, így nagyon könnyen kiolvashatóak az adatok a stuktúra segítségével.
Kicsit olyan mint egy asszociatív tömb, csak pointerrel, lehetne egy enum is ami meghatározná a tömb elemeinek helyét, de mivel több típusú adathalmaz lehet, így talán egyszerűbb.

Már rendsen működik, ahogy írtam is.
A leljes kódrészlet itt van:



typedef char * char_pointer;

struct data_struct
{
   char_pointer data1;
   char_pointer data2;
   char_pointer data3;
};

struct data_struct *data_pointer;
char_pointer data_array[sizeof(struct data_struct)];

data_pointer=(struct data_pointer *)data_array;

        char * point_position;
        int position;
        position=0;
        point_position=input_data; // data source "1234;asded;1a2a3a;"
        while(point_position!=NULL)
        {
            *point_position=0;
            data_array[position++]=(char *)(((char *)point_position)+1);
            point_position=strchr(point_position+1,';');
        }

printf("Második adat: %s\nElső adat: %s\nHarmadik adat: %s\n",data_pointer->data2,data_pointer->data1,data_pointer->data3);

Ezen még van mit csiszolni, mert igencsak sokáig kellett nézni, hogy megértsem.
Úgy kell programozni, hogy ne kelljen 6 egyetemi diplomával és doktorival rendelkeznie annak, aki meg akarja érteni.

A data1, data2, data3 mezők minek kellenek neked? Nem is használod őket, csak a kiírásnál!

Honnan veszed, hogy a C fordító a 'data_struct'-ot 4 egymást követő pointerként tárolja el és a legelső a data1, a második a data2, a harmadik a data3?

Erről a C szabvány semmit nem ír. Megteheti, hogy data3-at a 0. byte-on tárolja, data2-t a 9-ediken, data1-et pedig a 248-on. Nincs olyan szabvány, ami megtiltaná.

Ez a program mondjuk gcc 4.3-mal lehet, hogy működni fog a többiről meg semmit nem tudunk.

Nem lenne jobb az egészet egy tömbbe bepakolni?

A struktúra adatszerkezetekre való, nem pedig tömbnek.

teljesen jogosak a felvetések, bár értelmetlen lenne egy nem egymás után létrehozni a változókat, de valóban, ha ez nincs specifikálva, akkor ez egy hibás megközelítés.

Akkor inkább csinálók enum-okat, amikkel lehet név alaján majd hivatkozni a tömb elemeire, és így egyételmő lesz a program, és biztos megoldás a jövőre nézve is

Köszönöm, az észrevételeket.

A pointerekkel meg vigyázz, mert veszélyesek.

Ha létrehozol egy pointert, azt berakod egy másodikba, azt harmadikká cast-olod, akkor már fogalmad sem lesz a végén, hogy az eredeti pointer hogyan keletkezett és mekkora a mögötte álló lefoglalt adatmennyiség.

Ebből könnyen keletkezhetnek puffertúlírások.

A kódodat sokáig nézegettem, de nem sikerült megfejtenem, hogy az "a;b;c;d;e;f" okozhat-e puffertúlírást.

Tudom, hogy C-ben nem lehet pointerek nélkül megélni, de csak módjával kell kezelni őket. Az áttekinthetőség azért nagyon fontos, hogy azonnal észrevegye valaki, ha a kód hibásan működik.

Hogy én hogyan oldanám meg a feladatot:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* megszámlálja a ';' elemeket */
int get_size( char * buffer )
{
   int c = 0, i = 0;
   if( buffer[ 0 ] == 0 )
      return 0;
   while( buffer[ i ] != 0 )
   {
      if( buffer[ i ] == ';' )
         c++;
      i++;
   }
   /* egyet hozzáadok, mert a "hello" is értéknek számít, hiába nincs benne ';' */
   return c + 1;
}

/* visszatér egy pointer tömbbel, ami az elemekre mutat, a tömböt 0 pointerrel zárja */
char ** get_pointers( char * buffer )
{
   int size = get_size( buffer );
   /* helyfoglalás a pointer tömbnek */
   char ** res = (char **)malloc( sizeof( char * ) * ( size + 1 ) );
   int i=0;
   int p=0;
   while( buffer [ i ] != 0 ) {
      /* a sor elejét eltárolom */
      res[ p++ ] = buffer + i;
      /* a sor végét megkeresem */
      do {
         i++;
      } while( buffer[ i ] != 0 && buffer[ i ] != ';' );
      /* felülírjuk a ';'-t 0-val */
      if( buffer[ i ] != 0 ) {
         buffer[ i ] = 0;
         i++;
      }
   }

   /* null pointerrel zárjuk */
   res[ p ] = 0;
   return res;
}

/* teszelés */

int main( void )
{
   char * input = strdup( "ez;az;amaz;hello;ertekek" );
   char ** splitted = get_pointers( input );
   int p = 0;
   while( splitted[ p ] != 0 )
   {
      printf( "Érték:%s\n", splitted[ p ] );
      p++;
   }

   free( input );
   free( splitted );
}

Nem vagyok egy C guru, de nekem nem tetszik, hogy a get_pointers maga foglalja le a területet, mert így sokkal esélyesebb, hogy az ember elfelejti felszabadítani.
(A legtöbb C lib amit láttam elkerüli az ilyesmit, kivéve a gtk-t, de ott meg saját "konstruktora" és "destruktora" van az "osztályoknak")

Arról nem is beszélve, hogy így csak a malloc használható, más nem, ahogy a verem sem...

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

Ez C-ben lett megírva. Nincsenek sem konstruktorok, sem destruktorok. Azok C++-ban vannak, ott elegánsabban is meg lehetne mindezt oldani.

Persze át lehet a függvényeket nevezni + újakat hozzáadni:
myclass_create,
myclass_free,
myclass_get_size
myclass_get_item,
...
Egy 100 soros programnál nekem nem érte meg a többlet munkát, persze 10.000-nél már számítana.

A C az sajnos ilyen, mellesleg az strdup-ra sincs kiírva, hogy fel kell utána szabadítani a memóriát.
Csak akkor veszed észre, ha az alkalmazásod 1 gigát fogyaszt, úgy hogy tkp. semmit sem csinál.

Amikor megírtam a progamot így is hibáztam:

char ** res = (char **)malloc( sizeof( char * ) * size + 1 );

A zárójelek hiányoztak (size+1), ezért kevesebb helyet foglalt le eredetileg, mint kellett volna. A valgrind azonnal kilökte, hogy puffertúlírás van. Volt egy másik puffertúlírási hiba is, azt is javítottam.

A C nyelv nem életbiztosítás: első nekifutás után 100 sorban 2 puffertúlírási hiba jött elő a tesztelésnél.

Azért vallom be, mert szerintem a legnagyobb kernel hackerek is vétenek ugyanilyen hibákat. Nyilván kevesebbet, mert éjjel nappal C-ben programoznak, szemben velem, aki 2 havonta max. 1-szer.

Gtk+ is C.
C-ben nincs osztály/konstruktor/destruktor, ezért írtam idézőjelben.
Azért használtam ezeket a szavakat, mert Gtk esetében lényegében erről van szó, szokták is objektum-orientáltnak nevezni...

"A C az sajnos ilyen, mellesleg az strdup-ra sincs kiírva, hogy fel kell utána szabadítani a memóriát."

A C nem ilyen, csak ha a kedves programozó ilyenné teszi. Nem véletlen, hogy a libC-ben az strdup tudtommal az _egyetlen_ ilyen fv.

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

Ami a GTK-t illeti, azt inkább hagyjuk.

Lehet, hogy ezt a problémát ugyan megoldja, de nekem egy életre elment a kedvem a használatától, amikor azért, hogy egy vacak ablakba belerakjak egy Xine videólejátszót napokig a források között kellett turkálnom.

Ez KDE/Qt alatt úgy megy, hogy megnyitom az API dokumentációját és az osztályok között keresek valami olyan nevűt ami mindezt megoldja.

Amikor egy Qt ablakot bezársz automatikusan felszabadul minden. 10.000 soros programban max. 20 delete-t kell meghívni átlagban.

A GTK tipikus C-s szemétdomb. Olyan, mint az X.Org, vagy a Windows API, szerencsére semmi dolgom sincs vele.

A GTK# persze már dokumentálva van, logikus és áttekinthető. Ha GTK-t kell legközelebb használnom, azt valószínűleg C# alól fogom csinálni, mert nincs energiám a C-s marhaságokkal foglalkozni.

(Legközelebb zárd le a <code> tag-et)

Én nem szeretem a Gtk-t de egy álom minden más C-libhez képest amit láttam... (pl libav*... Brrrr)

De igazából ez offtopic...

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

"objektum-orientáltnak nevezni..."
Tudod, ez inkabb ironia, semmint valos ertelemmel biro elnevezes. Amugy meg nem a Gtk+-t hanem az alapjat kepezo Glibet szokas igy csufolni.

Amugy a C tenyleg olyan, hogy ha nem figyelsz elegge, millio helyen folyhat a memoria. C++ eseten a garantalt cuccok miatt ez nincs igy. Ezt most azert tudom, mert tegnap este egy mar kesz cuccomon valgrind-eztem a fobb belepesi pontokat (amiket napi szinten hasznalunk), es ledobbentem. Most mar nem emlexem, mennyi volt a git diff statisztika vege, de nagyon durva mennyisegu kod kerult bele, egy kulon uj fuggvenyt is kellett irni az egyik struct kiirtasara. C++ -ban talan 2 sor lett volna _valoban_ hibas.
--


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

"Tudod, ez inkabb ironia, semmint valos ertelemmel biro elnevezes"

Akkor biztos poénból írják ezt még a hivatalos oldalaikon is:

"C lacks syntactic sugar for object-oriented programming, it in no way prohibits an object-oriented approach.

GTK+ implements its own custom object system, which offers standard object-oriented features such as inheritance and virtual functions."
http://developer.gnome.org/doc/GGAD/cha-objects.html

Ha már a szavakon lovagolunk, abba nem tudsz belekötni, hogy obejktum orientált megközelitésű...

(Unom ezt a témát...)

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

Igen, nem könnyű C-ben objektum orientáltan programozni.

Az objektumorientált programozás lényege, hogy el kell rejteni a belső adatszerkezetet és mindent publikus metódusokkal megoldani.

C-ben csak publikus, vagy privát (amit a headerből nem látni) adatok/metódusok vannak.

A protected hiányzik. De öröklést sem lehet megvalósítani, csak igen kacifántos módon.
Igazi objektumorientált programot nem lehet írni C-ben, csak valami hasonlót.

Hat nem tudom. En programoztam mar tobbfele oo-nak mondott nyelvben (C++, Java, C#, VB.Net, Python, Ruby) - es a C nagyon nem az. Amit a GLib/GTK csinal, az csak annak latszodo valami.
Persze, en is tudok struct-okkal meg function pointerekkel varazsolni, de az messze nem objektumorientalt. Hol van az automata konstruktor/destruktor hivas? Hogyan csinalsz tobbszoros oroklodest, virtualis fuggvenyeket, interfesz osztalyokat? Nem mondom, hogy sok szopassal nem lehet ezek egy reszet megoldani - de az mar minden, csak nem oo. Csak annak van csufolva.
--


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

"Erről a C szabvány semmit nem ír. Megteheti, hogy data3-at a 0. byte-on tárolja, data2-t a 9-ediken, data1-et pedig a 248-on. Nincs olyan szabvány, ami megtiltaná."

Igen ez pontosan így van! Emlékszem egyszer volt a NavNGo-nak egy álláshirdetése, ahol a hirdetés weblapcímét egy C++ kód kimenetéből lehetett kikövetkeztetni.

Ugyanilyen Class-t -> char tömbbe castolás volt benne... Írtam is nekik, hogy biztos azok helyett keresnek képzettebb embereket akik a hirdetést írták, de nem válaszoltak... ;)

A szabvány annyit követel meg, hogy bár a struct elemei között lehet tetszőleges padding, azonos felépítésű struktúrák esetén azonos paddingnek kell lenni. Tehát azonos felépítésű struktúrák másoláskor nem fordulhat elő hogy az egyik struktúra paddingjét belemásolod a másik adatmezejébe.

Régen programoztam C/C++-ban de azt hiszem a legtöbb fordítóban külön van #pragma, ami kötelezi a fordítót arra, hogy 0 paddinget használjon...

Mindent meg lehet oldani, csak akarat kérdése.

Minden szál más statikus tömböt ad vissza. Lekérdezed az éppen futó thread ID-jét és annak megfelelő statikus tömbbel térsz vissza.

Nem muszáj a malloc-ot meghívni, ha újra meg is tudod írni az egészet.

Láttam már olyat, hogy valaki a << egész operátort exp + log függvényekkel oldotta meg.

Biztos órabérben fizették...

subscribe

/mazursky

Love your job but never love your company!
Because you never know when your company stops loving you!

ezzel csak egy bajom van, nem ismeri fel az egymás után jövő szeparátorokat. pl alama;korte;;;;;szilva
el lesz
1- alma
2- korte
3- szilva
és nem
1- alma
2- korte
3-
4-
5-
6-
7- szilva

de itt a kérdés nem a szeparálás volt, hanem a cikluson belüli érték átadás változónak valami egyszerű módon.