Dynamischen langen String Parsen

Es soll ebent nicht 3 Variablen sein, da es eine Auflage in unserem Kurs ist, generische Variablen zu benutzen. D.H. ein typlosen Container (void) der alles beinhalten soll um so die Wiederverwendbarkeit zwischen den Funktionen zu garantieren.
Wer sagt denn, dass du deswegen deine Daten in einen String kodieren musst? Du kannst doch genauso gut einen Zeiger auf ein struct in deiner Liste speichern, z.B.:
C:
typedef struct eintrag
{
    char* wort;
    node* funde;
} eintrag;

typedef struct fund
{
    char* dateiname;
    int zeile;
} fund;
Die Einträge speichern dann selber wieder jeweils eine doppelt verkettete Liste mit den Fundstellen den jeweiligen Wortes.

Grüße,
Matthias
 
Hi Matthias,

verstehe...als wenn ich das dann generisch umbaue, müsste es bei mir so aussehen?
C:
typedef struct node
{
	struct node* right; // Zeiger auf das Nachfolgerelement
	struct node* left;  // Zeiger auf das Vorgängerelement
	void* content; // Für den Dateninhalt	
    node* liste;
} node;
typedef struct liste
{
       char* dateiname;
       int nodeCounter;
       int lineCounter;
} liste;
...

oder prauche ich im unteren Struct noch 2 Zeiger? Wenn ja, warum? Hab ja schließlich ein auf sich selbst zeigende Liste. Und wieso brauche in in Zeile 6 noch node* liste;? Und ich vermisse da in Deinem Beispiel die zwei Zeiger der Liste.
 
Zuletzt bearbeitet:
Da sollen ja auch keine node left und right rein.
Du hast selber gesagt: Der Sinn der Übung ist, Listenfuntionen (wie anhängen, finden, löschen) zu machen, die unabhängig von den gespeicherten Daten funktionieren. Die Daten also als void*

Die node-struct, die du vorher gehabt hast, passt da perfekt:
C++:
typedef struct node
{
    struct node* right; // Zeiger auf das Nachfolgerelement
    struct node* left;  // Zeiger auf das Vorgängerelement
    void* content; // Für den Dateninhalt   
} node;

Mit Matthias Reitingers Vorschlag kommt dann sowas zusammen:
C++:
typedef struct node
{
    struct node* right;
    struct node* left;
    void* content; //da kommt eintrag rein
} node;

typedef struct eintrag
{
    char* wort;
    node* funde; //Eine Liste aus Funden
} eintrag;
 
typedef struct fund
{
    char* dateiname;
    int zeile;
} fund;

In eintrag und fund wird kein left/right mehr gebraucht, weil das ja schon im node ist.
 
Zuletzt bearbeitet:
ok.... und wenn ich jetzt meine Liste so nach dieser Struktur befüllen will, wie wird das denn jetzt realisiert?

vielleicht so? eintrag -> wort und fund -> dateiname bzw. fund -> zeile
oder muss ich das doch umständlicher von node aus machen ? node -> eintrag -> wort und node -> eintrag -> fund -> zeile.

Hab mit derartigen Strukturen noch nie gearbeitet.

Gruß.
 
Vielleicht wäre es ganz sinnvoll, wenn du deine doppelt verkettete Liste zuerst mal komplett losgelöst von deiner eigentlichen Problemstellung implementierst. Also einen Satz von Funktionen, die es erlauben, eine Liste zu erzeugen, sie wieder zu zerstören, Elemente einzufügen, Elemente aufzufinden… Diesen Funktionen muss es komplett egal sein, auf was der content-Zeiger verweist.

Andererseits verwendest du dann zur Lösung deines Problems diesen Satz von Funktionen, ohne irgendwas über die genaue Implementierung der Liste wissen zu müssen. Deine Liste ist dann eine „black box“, also eine Kiste mit Knöpfen (Funktionsdeklarationen) drauf, deren interne Verdrahtung (Implementierung) du nicht kennst.

Vielleicht fällt dir die Abstraktion dann leichter. Weil du vorhin Java erwähnt hattest, könntest du dein Problem auch erst mal in Java mit LinkedList modellieren und dann versuchen, es auf C zu übertragen.

Grüße,
Matthias
 
ich verstehe nur zum Teil deine Argumentation... das beantwortet nur leider nicht meine frage wie ich das jetzt in meine Liste bekomme. wie würdest du jetzt das Wort, den Dateinamen und die Zeilennummer in die Liste von Sheel oben einfügen bzw. initialisieren?

Ich hab jetzt schon ne Ewigkeit versucht das alleine hinzu bekommen, aber ich bin zu doof dafür!

Liste.h
C:
typedef struct node
{
	struct node* right; // Zeiger auf das Nachfolgerelement
	struct node* left;  // Zeiger auf das Vorgängerelement
	void* content; // Inhalt von contdef => Inhaltsdefinition von content.	
} node;
typedef struct contdef
{
	char* wort;
	node* def;  // Erweiterung für ein wort in der Liste
}contdef;
typedef struct def
{
	char* dateiname;
	char* zeile;
} def;
...

Liste.c
C:
...
#include "Liste.h"

node* init_Liste()
{
	node* n = (node*) malloc(sizeof(node));
	n -> right   = n;
	n -> left    = n;
	//n -> content = NULL;
	n -> contdef -> wort = NULL;
	n -> dateiname = NULL;
	n -> zeile = NULL;	
	return n;
}
...
node* anhaengen(node* list, void* neuer_String, void* dateiname, void* (*set)(void*), int counter)
{
      node* kopf      = list;
	node* aktl_Elem = list;

	contdef* neu_Elem = (contdef*) malloc(sizeof(contdef));
      if(neu_Elem == NULL)
	{
		printf("\n Listenelement konnte nicht angelegt werden, da kein Speicher vorhanden ist! \n");
		exit(1);
	}

          neu_Elem -> wort = (char*) set(neuer_String);
		neu_Elem -> dateiname = (char*) set(dateiname);
		
		//printf("conttmp: %s\n", (char*) (neu_Elem -> content) );
		//! Neues Element zeigt mit linkem Zeiger auf aktuelles Element (Liste)
		neu_Elem -> left       = list;
		//! Neues Element zeigt mit rechtem Zeiger auf rechten Nachbarn des Aktuellen Elements
		neu_Elem -> right      = list -> right;
		//! Von aktuellem Element auf rechtes Zeigen und von rechtem Element auf mit left auf 
       neues Element zeigen
		list -> right-> left   = neu_Elem;
		//! Von aktuellem Element mit right auf neues Element zeigen
		list -> right          = neu_Elem;
}

Gruß.
 
Zuletzt bearbeitet:
Liste.h
C:
typedef struct node
{
	struct node* right; // Zeiger auf das Nachfolgerelement
	struct node* left;  // Zeiger auf das Vorgängerelement
	void* content; // Inhalt von contdef => Inhaltsdefinition von content.	
} node;
typedef struct contdef
{
	char* wort;
	node* def;  // Erweiterung für ein wort in der Liste
}contdef;
typedef struct def
{
	char* dateiname;
	char* zeile;
} def;
Die Definitionen von contdef und def haben in Liste.h nichts verloren! Die Liste soll ja generisch sein. Wieso hast du den Typ von zeile auf char* geändert? Du willst doch eine Zeilennummer speichern, also passt der numerische Datentyp int besser.

Liste.c
C:
...
#include "Liste.h"

node* init_Liste()
{
	node* n = (node*) malloc(sizeof(node));
	n -> right   = n;
	n -> left    = n;
	//n -> content = NULL;
	n -> contdef -> wort = NULL;
	n -> dateiname = NULL;
	n -> zeile = NULL;	
	return n;
}
Wiederum: die Funktion init_Liste soll generisch sein, also nichts davon wissen, welche Elemente in ihr gespeichert werden! Die Funktion sollte z.B. so aussehen:
C:
node* init_Liste(void* content)
{
	node* n = malloc(sizeof(node));
	n -> right   = n;
	n -> left    = n;
	n -> content = content;
	return n;
}
content kann jetzt alles sein, also konkret in deinem Fall z.B. ein Zeiger auf ein struct contdef oder auf struct def.

Eine Liste mit einem Eintrag legst du dann z.B. so an:
C:
char wort[] = "foo";
char dateiname[] = "foo.txt";

def* fund = malloc(sizeof(def));
fund->dateiname = dateiname;
fund->zeile = 42;

contdef* eintrag = malloc(sizeof(contdef));
eintrag->wort = wort;
eintrag->def = init_Liste(fund);

node* liste = init_Liste(eintrag);

Glaub es mir einfach: wenn du zuerst deine Liste generisch implementierst und erst dann dein Problem davon losgelöst angehst, tust du dich viel leichter.

Grüße,
Matthias
 
ok wenn ich das so mache, scheint er auch nicht mehr beim Kompilieren zu meckern, dass er die Bezeichner wort und dateinamen nicht kennt. aber da ja meine beiden Zeiger im ersten Strukt (node) stehen, findet er diese jetzt nicht mehr.

Fehlerausgabe lautet:
error: ‘contdef’ has no member named ‘node’
wenn ich das so wie in dem Codebeispiel versuche - zeigertechnisch - in meine Liste zu implementieren.
C:
...
neu_Elem -> wort = (char*) set(neuer_String);
		neu_Elem -> dateiname = (char*) set(dateiname);
		
		//printf("conttmp: %s\n", (char*) (neu_Elem -> content) );
		//! Neues Element zeigt mit linkem Zeiger auf aktuelles Element (Liste)
		neu_Elem -> left       = list;
		//! Neues Element zeigt mit rechtem Zeiger auf rechten Nachbarn des Aktuellen Elements
		neu_Elem -> right      = list -> right;
		//! Von aktuellem Element auf rechtes Zeigen und von rechtem Element auf mit left auf neues Element zeigen
		list -> right-> left   = neu_Elem;
		//! Von aktuellem Element mit right auf neues Element zeigen
		list -> right          = neu_Elem;
...

hab das noch so versucht und es geht gut. nur weiß ich nicht, ob das zulässig ist!
C:
...
     node* kopf      = list;
	node* aktl_Elem = list;

	contdef* neu_Elem = (contdef*) malloc(sizeof(contdef)); //! Speicher für neuen Knoten besorgen 
	//! Überprüfen, ob Speicher angelegt worden ist	
	if(neu_Elem == NULL)
	{
		printf("\n Listenelement konnte nicht angelegt werden, da kein Speicher vorhanden ist! \n");
		exit(1);
	}
       neu_Elem -> wort = (char*) set(neuer_String);
		neu_Elem -> dateiname = (char*) set(dateiname);

		node* neu_Node = (node*) malloc(sizeof(node));
		//printf("conttmp: %s\n", (char*) (neu_Elem -> content) );
		//! Neues Element zeigt mit linkem Zeiger auf aktuelles Element (Liste)
		neu_Node -> left       = list;
		//! Neues Element zeigt mit rechtem Zeiger auf rechten Nachbarn des Aktuellen Elements
		neu_Node -> right      = list -> right;
		//! Von aktuellem Element auf rechtes Zeigen und von rechtem Element auf mit left auf neues Element zeigen
		list -> right-> left   = neu_Node;
		//! Von aktuellem Element mit right auf neues Element zeigen
		list -> right          = neu_Node;

Ich hatte "zeile" als char deklariert, weil zeile mehrere Zeilennummern beherbergen kann und soll. Es soll ja schließlich nur Wörter in die Liste aufgenommen werden, die noch nicht existieren. Also wenn ein Wort aber schon existiert, soll nur dessen Zeilennummer in dem schon existierendem Wort der Liste in "zeilel" hinzugefügt / hinten angehängt werden. Wenn ich also die Variable "zeile" als int deklariere, überschreibe ich ja diesen Wert nur mit der Zeilennummer des mehrfachen vorkommenden Wortes.

also nochma. Wenn das Wort z.B und in einem Text mehrfach vorkommt schon in der liste steht - also: und Gruß.txt 4 - dann soll nur die Zeile des nächst gefundenen und's in der Variable "zeile" hinten angefügt werden. -> und Gruß.txt 4 8 20 45 70. Mann könnte das bestimmt auch mit einem Array machen. aber dann müsste ich wieder ausreichend Listenelemente vorsehen und würde dann wieder nur unnötig Speicher verschwenden und als "char* zeile;" kann ich da mit strcat einfach in dieser Variablen hinten anfüfen und würde dann nur soviel speicher belegen, wie der String groß ist.

Gruß.
 
Zuletzt bearbeitet:
Fehlerausgabe lautet:
error: ‘contdef’ has no member named ‘node’
wenn ich das so wie in dem Codebeispiel versuche - zeigertechnisch - in meine Liste zu implementieren.
C:
...
neu_Elem -> wort = (char*) set(neuer_String);
		neu_Elem -> dateiname = (char*) set(dateiname);
		
		//printf("conttmp: %s\n", (char*) (neu_Elem -> content) );
		//! Neues Element zeigt mit linkem Zeiger auf aktuelles Element (Liste)
		neu_Elem -> left       = list;
		//! Neues Element zeigt mit rechtem Zeiger auf rechten Nachbarn des Aktuellen Elements
		neu_Elem -> right      = list -> right;
		//! Von aktuellem Element auf rechtes Zeigen und von rechtem Element auf mit left auf neues Element zeigen
		list -> right-> left   = neu_Elem;
		//! Von aktuellem Element mit right auf neues Element zeigen
		list -> right          = neu_Elem;
...
Du vermischst hier schon wieder die Implementierung der generischen Liste und problemspezifischen Code. Das kann nicht vernünftig funktionieren. Ich versuche noch ein letztes mal damit bei dir durchzukommen: Implementiere die Liste unabhängig davon, welche Elemente sie speichert. Also kein wort oder dateiname oder zeile in der Implementierung der Listenfunktionen.

Ich hatte "zeile" als char deklariert, weil zeile mehrere Zeilennummern beherbergen kann und soll.
Dann würde sich doch aber ein Array aus ints viel besser eigen!? Abgesehen davon reicht es, genau eine Zeilennummer pro Eintrag speichern, denn:

Es soll ja schließlich nur Wörter in die Liste aufgenommen werden, die noch nicht existieren. Also wenn ein Wort aber schon existiert, soll nur dessen Zeilennummer in dem schon existierendem Wort der Liste in "zeilel" hinzugefügt / hinten angehängt werden.
Du hast den vorgeschlagenen Aufbau nicht ganz verstanden. Deine Hauptliste soll für jedes vorgekommene Wort einen Eintrag besitzen. Jeder Eintrag speichert jeweils 1. das Wort und 2. eine Liste mit den Vorkommnissen (Funde) dieses Wortes. Jedes Vorkommnis verzeichnet 1. den Dateinamen und 2. die Zeilennummer.

Beispiel:
foo.txt
Code:
foo bar
foobar
foo

bar.txt
Code:
foobar
foo

Struktur des Ergebnisses:
Code:
[ # Liste von Einträgen
  { # Eintrag
    wort: "foo",
    funde: [ # Liste von Funden
      { dateiname: "foo.txt", zeile: 1 }, # Fund
      { dateiname: "foo.txt", zeile: 3 }, # Fund
      { dateiname: "bar.txt", zeile: 2 }  # Fund
    ]
  },
  { # Eintrag
    wort: "bar",
    funde: [ # Liste von Funden
      { dateiname: "foo.txt", zeile: 1 } # Fund
    ]
  },
  { # Eintrag
    wort: "foobar",
    funde: [ # Liste von Funden
      { dateiname: "foo.txt", zeile: 2 }, # Fund
      { dateiname: "bar.txt", zeile: 1 }  # Fund
    ]
  }
]
So klarer geworden?

Mann könnte das bestimmt auch mit einem Array machen. aber dann müsste ich wieder ausreichend Listenelemente vorsehen und würde dann wieder nur unnötig Speicher verschwenden und als "char* zeile;" kann ich da mit strcat einfach in dieser Variablen hinten anfüfen und würde dann nur soviel speicher belegen, wie der String groß ist.
Abgesehen davon, dass das überhaupt nicht nötig ist (s.o.), verkomplizierst du die Sache mit einem String nur. Du kannst nicht einfach strcat aufrufen, ohne vorher entsprechend Speicher reserviert zu haben.

Grüße,
Matthias
 
Danke dir Matthias, aber du verwirrst mich nur noch mehr******

Ich geb es auf! ich bau jetzt meine Liste wieder zurück zu einer normalen Liste. Ich hab nähmlich nicht mehr viel Zeit für mein Problem, da ich es übermorgen fertig haben muss.

Ich wollte eigentlich nur gewusst haben, wir Ihr das in einer Funktion, in der nun schon oben dargestellten generischen Liste implementieren würdet. Ich muss ja schließlich auch meiner Fungtion irgendwie mitteilen, wie ich die Zeiger setzten muss um Bestandteil meiner generischen Liste zu sein. Aber Ihr sprecht in Rätseln.
Trotzdem vielen Dank für Eure Bemühungen.

Gruß.
 
Zuletzt bearbeitet:
Zurück