Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Problem mit realloc

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 <
010
15.09.2005, 12:50 Uhr
netdisaster




Meinen größten Dank an virtual,
Du Gott der Nullen und Einsen!
Es läuft.
Was bin ich froh!

Und dennoch:
so ganz kapiert hab ich die Sache noch nicht.
Das stößt echt an die Grenzen meiner Nachvollziehbarkeit.
Warum genügt es nicht, quasi nur die Speicheradresse des reservierten Speichers per Pointer weiterzugeben. Warum muss ich den ganzen Pointer als cbr durchreichen.
Und meine realloc-Funktion ist doch in cr_newMONT, die ich nur von main() über poco_mont() erreiche. Wieso muss ich da nicht "MONTAGEFOLGE ***MONT_List" als Parameter setzen.

Das ist wie Schwimmen im Bodensee. Bei Nacht und mit Augenbinde. Wie soll man sich da noch zurechtfinden ...

Aussehen tut das Programm inzwischen (stark gekürzt) wie folgt.
Ist das jetzt einigermaßen in Ordnung?

Ich bin euch auf jeden Fall überaus dankbar, speziell eben virtual für seinen entscheidenden Hinweis!

Grüße,
netdisaster


C++:
#define PARTS 10
#define MEM_UP (PARTS*PARTS)

typedef struct {int ...; char ...; float ...;} BAUTEIL;
typedef struct {...; BAUTEIL *;} STABTBG;
typedef struct {...; STABTBG *;} OPERATION;
typedef OPERATION MONTAGEFOLGE[PARTS];

int main()
{
   int montcount=1;
   int maxmont=MEM_UP;
   [...]
   MONTAGEFOLGE *MONT_List;
   MONT_List=(MONTAGEFOLGE *) malloc(maxmont*sizeof(MONTAGEFOLGE));
   if (MONT_List==NULL) {
      fprintf(stderr, "Speicher-ERROR: MONT_List zu gross");
      exit(1);
   }
   [...]
   poco_mont(..., &montcount, &maxmont, &MONT_List, ...);
   [...]
}

void poco_mont(..., int *montcount, int *maxmont, MONTAGEFOLGE **MONT_List, ...)
{
   [...]
            if (cr_newMONT(..., montcount, maxmont, MONT_List)) {
               [...]
               poco_mont(..., montcount, maxmont, MONT_List, ...);
            }
   [...]
}

int cr_newMONT(..., int *montcount, int *maxmont, MONTAGEFOLGE **MONT_List)
{
   MONTAGEFOLGE *MONT_List_alt;
  
   [...]
   parallele_TBG(..., montcount, MONT_List);
   [...]
// Schritt 7:
// falls komplette Montagefolge gefunden, montcount erhöhen
   if (step==PARTS-1) {
      ++(*montcount);
      // bei Bedarf mehr Speicher bereitstellen
      if (*montcount==*maxmont) {
         MONT_List_alt=*MONT_List;
         *maxmont += MEM_UP;
         *MONT_List=(MONTAGEFOLGE *) realloc(MONT_List_alt, (*maxmont)*sizeof(MONTAGEFOLGE));
         if (*MONT_List == NULL) {
            fprintf(stderr, "\n\nSpeicher-ERROR: MONT_List zu gross");
            *MONT_List=MONT_List_alt;
         }
      }
   }
   return (return_value);
}

int parallele_TBG(..., int *montcount, MONTAGEFOLGE **MONT_List)
{
   // hier werden nur Werte in MONT_List gelesen, nicht verändert
   [...]
   return(return_value);
}

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
15.09.2005, 13:18 Uhr
Pablo
Supertux
(Operator)



Zitat von netdisaster:

Du Gott der Nullen und Einsen!
Es läuft.



Hier ist Beefy Gott. A propo beefy, was ist aus ihm geworden?



Zitat von netdisaster:

Warum genügt es nicht, quasi nur die Speicheradresse des reservierten Speichers per Pointer weiterzugeben. Warum muss ich den ganzen Pointer als cbr durchreichen.
Und meine realloc-Funktion ist doch in cr_newMONT, die ich nur von main() über poco_mont() erreiche. Wieso muss ich da nicht "MONTAGEFOLGE ***MONT_List" als Parameter setzen.


das liegt daran, dass Zeiger auch nur Variablen sind. Zeiger sind Variablen, die ein Adresse speichern, nämlich die Adresse auf die ein Zeiger zeigt. Guck dir diesen Code hier an


C++:
void add(int a, int b, int c)
{
    c = a + b;
}

void foo()
{
    int a = 6; int b = 8, c = 0;

    add(a,b,c);
    printf("add(%d, %d) = %d\n", a, b, c);
}



Du wirst sofort sagen, dass die Ausgabe add(6,8,0) ist, und das ist richtig, denn die Adresse der Variable foo::c ist nicht unter add bekannt und add::c ist nur ein Kopie von foo::c. D.h. add::c hat nur den Wert von foo::c aber sie sind 2 unterschiedliche Variablen und die Änderungen von add::c sind unter allen anderen Funktion unsichtbar.

Was muss man machen, damit eine andere Funktion den Wert einer Variable einer anderen Funktion ändern kann? Da kommen die Zeiger ins Spiel. Ein Zeiger ist nicht anders als soz. eine int Variable deren Inhalt die Adresse im Speicher einer anderen variable ist.


C++:
int var = 8;
int* zeiger_auf_var = &var;



welchen Wert zeiger_auf_var speichert ist vom Speicherort von var abhängig. Nehmen wir an, var befindet sich unter 0xdeadbeef. Dann speichert die Variable zeiger_auf_var den Wert 0xdeadbeef. Somit kann man direkt auf den Speicher zugreifen und ihn nach Bedarf ändern.


C++:
int var = 8;
int* zeiger_auf_var = &var;
zeiger_auf_var = ????;



ändert nicht den Wert von var auf ??? sondern lässt den Zeiger auf eine andere Adresse ziegen, während


C++:
int var = 8;
int* zeiger_auf_var = &var;
*zeiger_auf_var = ????;



sorgt dafür, dass der Wert von var auf ??? geändert wird. Warum? Weil man mit *zeiger_auf_var direkt auf den Speicher durch die Speicheradresse zugreifen können. Wenn wir bei der Annahme geblieben sind, dann bedeutet das quasi: "Weise den Wert ??? dem Speicherort 0xdeadbeed zu". Somit erzeugt folgender Code das gewünschte:


C++:
void add(int a, int b, int* c)
{
    *c = a + b;
}

void foo()
{
    int a = 6; int b = 8, c = 0;

    add(a,b,&c);
    printf("add(%d, %d) = %d\n", a, b, c);
}



Alternativ wäre

C++:
int* zeiger = &c;
add(a,c,zeiger);
...



So, beim neuen Code sind foo::c und add::c natürlich unterschiedlich, wie gesagt nur eine Kopie des Inhalts der Variable foo:c. Aber da add::c ein Zeiger ist, kann man durch ihn auf eine Speicheradresse direkt zugreifen. Und somit kann add::c den Wert von add::c ändern.

Nun, mit Doppelzeiger ist es genau dasselbe. Malloc-Family Funktionen liefern ein void* zurück, d.h. ein Zeiger. realloc liefert ebenfalls einen Zeiger.


C++:
void change(int* zeig, size_z len)
{
    int* tmp = realloc(zeig, len);
    if(!tmp) ....
    if(tmp != zeig)
        zeig = tmp;
}

void foo()
{
    int* etwas;

    etwas = malloc(sizeof(int)*10);

    if(!etwas) ...

    change(etwas, sizeof(int)*100);
}



so, hier verhält es sich um change::zeig genau so wie im ersten Beispiel. Wenn change aufgerufen wird und sagen wir mal, realloc eine Adresse liefert, die unterschiedlich mit der alten ist, dann muss der Zeiger geändert werden, da tue ich auch mit "if(tmp != zeig) zeig = tmp;". Spätestens jetzt sollte dir klar sein, dass das in die Hose geht, denn zeig = tmp; heißt, ändere den Zeiger von zeig, sprich ändere den gespeicherten Wert von der Variable zeig. Wenn du Funktion verlassen wird, so ist diese Änderung für foor unsichtbar, genauso wie oben. Da du den Inhalt des Zeigers und nicht der gezeigten Adresse ändern willst, musst du die Adresse des Zeigers liefern, also


C++:
void change(int** zeig, size_z len)
{
    int* tmp = realloc(*zeig, len);
    if(!tmp) ....
    if(tmp != *zeig)
        *zeig = tmp;
}

void foo()
{
    int* etwas;

    etwas = malloc(sizeof(int)*10);

    if(!etwas) ...

    change(&etwas, sizeof(int)*100);
}



so, hast du es verstanden?
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
15.09.2005, 17:34 Uhr
netdisaster



ich versuch's mal (bezogen auf den letzten Kasten):

"etwas" ist eine Variable, die eine Speicheradresse speichern kann. An eben dieser Zieladresse, z.B. 0xdeadbeef, lassen sich 10 int-Werte abspeichern.
"etwas" selbst sitzt an irgendeiner anderen Stelle im Speicher, wegen mir 0xdeadcaca. Also:
&etwas = 0xdeadcaca
etwas = 0xdeadbeef
*etwas = Speicherbereich für 10 int-Werte [0] bis [9]

"change::zeig" dagegen ist eine Variable, die zwar ebenso eine Speicheradresse speichern kann wie "etwas". An dieser Speicheradresse allerdings muss eine weitere Speicheradresse stehen. Erst an dieser Zieladresse müssen wiederum int-Werte abgespeichert werden. "change::zeig" wird wegen mir an der Stelle 0xbebebeef abgespeichert.
Durch den Aufruf "change(&etwas, ...)" in foo() übergebe ich die eigene Speicheradresse von "etwas", also 0xdeadcaca, an "change::zeig", das dann jetzt so aussieht:
&zeig = 0xbebebeef
zeig = 0xdeadcaca
*zeig = 0xdeadbeef
**zeig = Speicherbereich für 10 int-Werte [0] bis [9]

In change() übergebe ich jetzt den Wert von zeig (also das 0xdeadbeef) an realloc().
realloc() sucht mir einen passenden neuen Speicherblock für jetzt 100 int-Werte und findet den z.B. im Speicher an der Stelle 0xcccccccc. Als Rückgabewert liefert es mir einen void-zeiger, also eigentlich gar nichts außer eben dieser Adresse 0xcccccccc, an der ich die 100 int-Werte abspeichern könnte. Dieses 0xcccccccc wird jetzt in tmp abgespeichert. Also:
&tmp = egal
tmp = 0xcccccccc
*tmp = Speicherbereich für 100 int-Werte [0] bis [99]

Nachdem (tmp != *zeig), also (0xcccccccc != 0xdeadbeef), wird tmp an *zeig übergeben.
&zeig = 0xbebebeef
zeig = 0xdeadcaca
*zeig = 0xcccccccc
**zeig = Speicherbereich für 100 int-Werte [0] bis [99]

Somit steht jetzt im Speicher an der Adresse 0xdeadcaca (i.e. &etwas) der Wert 0xcccccccc und nicht mehr 0xdeadbeef, so dass auch "etwas" in foo() auf den neuen Speicherbereich zugreifen kann.

Stimmt das jetzt so?

netdisaster
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: