PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Pointerprobleme bei verketteter Liste [C]


beos
2006-02-21, 10:57:13
Grüß Euch,

ich kann nicht ganz nachvollziehen, warum es bei der Pointerzuweisung der letzter Zeile im eine Exeption gibt?
Sieht einer von Euch den Fehler bzw kann mir einen Tip geben...?


typedef struct Element
{
int data;
struct Element *next;
}Element;


void einfuegen(Element *wo, int daten);

int main (void)
{

Element *liste = NULL;
einfuegen(liste, 1);
return 0;
}

void einfuegen(Element *wo, int daten)
{
Element *neu = (Element*) malloc(sizeof(Element));
assert(neu!=NULL);
printf ("Pointer von wo %d\n",&wo);
printf ("Pointer von neu %d\n",&neu);
wo->next=(Element*)&neu;

}

noid
2006-02-21, 11:15:01
warum schreibst du nicht einfach "wo->next = neu" ?

beos
2006-02-21, 11:18:58
warum schreibst du nicht einfach "wo->next = neu" ?

Das hatte ich ursprünglich...bringt aber auch eine Exeption :wink:

beos
2006-02-21, 11:25:01
Komisch...selbst das bringt eine Exception bei der Pointer = NULL Zuweisung

typedef struct Element
{
int data;
struct Element *next;
}Element;


int main (void)
{

Element *liste;
liste->next=NULL;
return 0;
}

noid
2006-02-21, 11:39:08
wenn du mir jetzt noch sagst, wo das struct "liste" angelegt worden ist, dann ist alles gut. (sonst ist ein pointer drauf ja total fürn eimer)

muhkuh_rs
2006-02-21, 11:39:21
Komisch...selbst das bringt eine Exception bei der Pointer = NULL Zuweisung

typedef struct Element
{
int data;
struct Element *next;
}Element;


int main (void)
{

Element *liste;
liste->next=NULL;
return 0;
}


Dein erstes Post habe ich nicht genau studiert aber das jetzt ist kein sinvoller Code.

Du deklarierst einen Pointer auf eine Instanz vom Typ Element. Der Pointer ist nicht initialisiert und zeigt lustig in der Gegend rum. Worauf ist Glückssache bzw. vom Compiler im Debug-Build meist auf einen erkennbar ungültigen Wert vorinitialisiert. Der Versucht auf den Speicher zu schreiben, auf den liste zeigt, wird also mit hoher Wahrscheinlichkeit fehlschlagen. Normalerweise sollte der Compiler eine Warnung generieren, dass ein Pointer verwendet wird, der nicht initialisiert ist.

beos
2006-02-21, 11:51:05
Stimmt ihr habt recht...ich muss natürlich erst mal speicher für das Element erzeugen dann gehts..... :rolleyes:

main sieht jetzt so aus

int main (void)
{

Element *liste = (Element*) malloc(sizeof(Element));
liste->data=0;
liste->next=NULL;

einfuegen(liste, 1);

return 0;
}



Allergings klappt es nicht mit dem Pointerverbiegen:

void einfuegen(Element *wo, int daten)
{
Element *neu = (Element*) malloc(sizeof(Element));
assert(neu!=NULL);
printf ("Pointer auf wo %d\n",&wo);
printf ("Pointer auf neu %d\n",&neu);
wo->next=neu;
printf ("Pointer auf wo -> next %d\n",&wo->next);

}

wo->next zeigt immer noch auf wo aber nicht auf das neue element....warum denn bloss :confused:

Expandable
2006-02-21, 12:29:19
Element *liste = (Element*) malloc(sizeof(Element));


Also ich kenn mich jetzt zwar mit der C-Art, Speicher auf dem Heap zu allokieren, nicht aus (ich verwende immer nur das C++-new), aber warum castest Du den Speicher auf Element*? sizeof(Element) gibt ja die größe zurück, die das Struct Element hat. Für einen Pointer auf ein Element brauchst Du aber in jedem Fall nur 4 Byte (oder 8, falls 64 Bit).

In C++ würde man ja auch nicht schreiben:
Element *liste = new Element*();
sondern
Element *liste = new Element();

Möglicherweise funktioniert malloc() so - dennoch würde ich es für sinnvoller halten, nicht nach Element* zu casten, sondern nach Element. Bzw... wenn ich mir das so überlege... nach Element* zu casten macht überhaupt keinen Sinn... das würde ja heißen, dass in dem mit malloc() erzeugten Speicherbereich nur ein Pointer auf ein Element steht. Und das ist ja nicht so (sonst müsste liste ein Pointer auf einen Pointer auf ein Element sein)...

beos
2006-02-21, 12:39:57
Man kann in dem Fall das Casten auch weglassen...

Ich hatte mit einem next void Pointer in der Struktur experimentiert...und dann muss man beim malloc expliziet casten.

Allerdings hat das keine Auswirkungen auf die Pointerprobleme...die sind unverändert - auch beim "nicht casten"...

Hast Du da eine Idee?

Trap
2006-02-21, 12:54:08
Allergings klappt es nicht mit dem Pointerverbiegen:
void einfuegen(Element *wo, int daten)
{
printf ("Pointer auf wo %d\n",&wo);

&wo ist die Adresse des Pointers und vom Typ Element**, du gibst nicht das aus was du wissen möchtest.

muhkuh_rs
2006-02-21, 13:58:23
Also ich kenn mich jetzt zwar mit der C-Art, Speicher auf dem Heap zu allokieren, nicht aus (ich verwende immer nur das C++-new), aber warum castest Du den Speicher auf Element*? sizeof(Element) gibt ja die größe zurück, die das Struct Element hat. Für einen Pointer auf ein Element brauchst Du aber in jedem Fall nur 4 Byte (oder 8, falls 64 Bit).

In C++ würde man ja auch nicht schreiben:
Element *liste = new Element*();
sondern
Element *liste = new Element();

Möglicherweise funktioniert malloc() so - dennoch würde ich es für sinnvoller halten, nicht nach Element* zu casten, sondern nach Element. Bzw... wenn ich mir das so überlege... nach Element* zu casten macht überhaupt keinen Sinn... das würde ja heißen, dass in dem mit malloc() erzeugten Speicherbereich nur ein Pointer auf ein Element steht. Und das ist ja nicht so (sonst müsste liste ein Pointer auf einen Pointer auf ein Element sein)...

liste ist ein Pointer der auf dem Stack liegt und so groß ist, wie das System für Pointer vorsieht. malloc ist eine Funktion und liefert einen (void*) auf ein Stück Speicher zurück, das so groß ist, wie der übergebene Parameter sizeof(Element), also groß genug um ein Element aufnehmen zu können. Da man aber einen (void*) keinem anderen typisierten Pointer zuweisen kann, muss man an dieser Stelle explizit casten.

Coda
2006-02-21, 16:31:11
Also ich kenn mich jetzt zwar mit der C-Art, Speicher auf dem Heap zu allokieren, nicht aus (ich verwende immer nur das C++-new), aber warum castest Du den Speicher auf Element*? sizeof(Element) gibt ja die größe zurück, die das Struct Element hat. Für einen Pointer auf ein Element brauchst Du aber in jedem Fall nur 4 Byte (oder 8, falls 64 Bit).

In C++ würde man ja auch nicht schreiben:
Element *liste = new Element*();
sondern
Element *liste = new Element();

Möglicherweise funktioniert malloc() so - dennoch würde ich es für sinnvoller halten, nicht nach Element* zu casten, sondern nach Element. Bzw... wenn ich mir das so überlege... nach Element* zu casten macht überhaupt keinen Sinn... das würde ja heißen, dass in dem mit malloc() erzeugten Speicherbereich nur ein Pointer auf ein Element steht. Und das ist ja nicht so (sonst müsste liste ein Pointer auf einen Pointer auf ein Element sein)...Der Cast ist vollkommen korrekt. malloc gibt einen void*-Pointer auf den allozierten Speicherbereich zurück. Es ist guter Stil da auf den "richtigen" Pointertyp zu casten, wenn auch nicht notwendig in C (in C++ wäre es notwendig).

Edit: Oh ne, mal wieder zuviel gepostet :(

Expandable
2006-02-21, 19:04:29
Okay, sorry, wie gesagt, ich habe mit malloc() noch nie gearbietet. Es kam mir einfach komisch vor.

Coda
2006-02-21, 19:09:37
Was soll es denn sonst zurückgeben X-D

Expandable
2006-02-21, 20:44:59
Ich war der Meinung, dass man mit malloc(size) Speicherbereich in der Größe von size Byte auf dem Heap allokiert. Nachdem damit kein Typ assoziiert ist, muss man casten. malloc liefert aber scheinbar einen Pointer zurück. New zwar auch, allerdings ist da die Typangabe "einen Level höher"... falls das irgendwie verständlich ist.

Also mit new:
Element *liste = new Element();
mit malloc:
Element *liste = (Element *)malloc(sizeof(Element));

Wie wäre das dann mit Doppelpointern?
Element **liste = new Element*;
Element **liste = (Element **)malloc(sizeof(Element *)); ??

Coda
2006-02-21, 20:49:05
Ist korrekt.

Xmas
2006-02-21, 21:50:49
Nur dass es keinen Sinn mehr macht, Speicherplatz für einen Pointer zu allokieren.

Expandable
2006-02-22, 01:00:02
Nur dass es keinen Sinn mehr macht, Speicherplatz für einen Pointer zu allokieren.

Darum ging's ja aber nicht. Aber gut, also um mit malloc ein zweidimensionales n x m double-Array aufzubauen, würde man schreiben:

int n, m;
n = ?;
m = ?;

double **arr = (double**) malloc(sizeof(double *) * n);

for (int i = 0; i < n; ++i)
arr[i] = (double *) malloc(sizeof(double) * m);

Und dann ganz normal Zugriff über arr[i][j]? Also da ist die new-Variante doch deutlich schöner ;)

Coda
2006-02-22, 09:38:57
Natürlich ist new schöner, schon allein weil es typesafe ist. Aber wer hat jemals behauptet, dass C schön sei?

muhkuh_rs
2006-02-23, 11:45:13
Nur dass es keinen Sinn mehr macht, Speicherplatz für einen Pointer zu allokieren.
Naja, das würde ich nicht sagen. Es ergibt sehr wohl Sinn, Speicher für einen Pointer zu alloziieren. Z.B. ein Array von Pointern vom Typ CAbstractClass*, die auf verschiedene Implementierungen zeigen.

Xmas
2006-02-23, 14:40:07
Setz die Betonung auf "einen". ;)