Seite 1 von 1

Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 10:53 am
von aequatio
Hallo :)

folgendes Problem hätte ich gerade:
Wir müssen für die Hochschule ein Projekt in ANSI C (C99) programmieren (Kompiler soll gcc sein).
Dazu habe ich verschiedene Listen die aus verschiedenen structs bestehen.

Mein Problem ist, ich hätte gerne meine Funktionen zum manipulieren der Listen nicht für jede einzeln, sondern je eine allgemeine zum Anfügen von einem neuen Element, das Löschen von einem Element etc. Dazu übergebe ich der Funktion im Beispiel void *start, das erste Element einer beliebigen Liste, und benenne sie *p um mit ihr weiterzuarbeiten:

Code: Alles auswählen

/* Funktion:	listAdd()					*
 * Input:	void *start - Zeiger auf das erste Objekt	*
 * 		void *new - Zeiger auf neues Objekt		*
 * Output:	void						*
 * Aufgabe:	Element am Ende der Liste hinzufügen		*/
void listAdd( void *start, void *new ) {
	void *p = start;			// Pointer auf aktuelles Objekt

	while( p != NULL ) {			// Schleife bis letztes Element gefunden
		if( p->next == NULL ) {		// Wenn letztes Element
			p->next = new;		// Dann setze neues Element statt NULL
			return;			// Beende Funktion
		}
		else {				// Wenn nicht letztes Element
			p = p->next;		// Sprine
		}
	}
}
Dabei meckert der Kompiler aber:

Code: Alles auswählen

lists.c:74:10: warning: dereferencing ‘void *’ pointer
     p = p->next;   // Sonst springe zu nächsten Element
          ^
lists.c:74:10: error: request for member ‘next’ in something not a structure or union
Gut logisch, er weiß ja nicht was hinter dem void* steckt. Also habe ich folgendes Konstrukt zum um deklarieren meines Pointers je nach Notwendigkeit (Parameter strNR liefer ich entsprechend mit) gebaut:

Code: Alles auswählen

	switch( strNR ) {			// p je nach Typ deklarieren
		case 1:		; product *p = start;
				break;
		case 2: 	; costumer *p = start;
				break;
		case 3:		; order *p = start;
				break;
		case 4:		; costumOrder *p = start;
				break;
		default:	; void *p = NULL;
				break;
	}
Neue Fehlermeldung ist dann:

Code: Alles auswählen

lists.c:32:24: error: conflicting types for ‘p’
   case 2:  ; costumer *p = start;
                        ^
lists.c:30:23: note: previous definition of ‘p’ was here
   case 1:  ; product *p = start;
                       ^
...

Ich hab echt keinen Ansatz wie ich das Problem direkt beheben kann oder meine Daten vll anders Strukturieren kann (Listen sind hier schon sinnvoll da es beliebig viele neue User etc geben soll).

Danke schonmal fürs durchlesen und im vorraus für eure Tipps :)


Gruß
aequatio

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 11:03 am
von aequatio
Edit: in jedem struct wird mit der Variablen next auf das nächste Element gezeigt

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 11:12 am
von aequatio
Ok das Problem mal für andere zu Formulieren hat mich auf ne Idee gebracht:

Statt diesem nicht gerade hübschen Konstrukt mache ich in meinen Header ein Makro:

Code: Alles auswählen

#define STRUCT_TYPE(typ) typ
und habe dann in meiner Funktion:

Code: Alles auswählen

void fkt( char* type, ....) {
          STRUCT_TYPE(type) *p = new;
          ...
Zumindest meckert der Kompiler nichtmehr :)
Ich halt euch auf dem laufenden ob das auch so klappt ;) (falls einer da Anmerkungen hat bitte her damit :) )

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 11:15 am
von cloidnerux
Hallo :)
Hi und Willkommen im Forum :D
Dazu habe ich verschiedene Listen die aus verschiedenen structs bestehen.
Hier liegt das Gesamtproblem.
Die typische Liste(https://www.proggen.org/doku.php?id=struct:list:start) ist eine Datenstruktur um generische Daten zu speichern.

Jetzt legst du mehrere Listen an, die aber keine funktionellen Unterschiede(?) haben, sondern nur von der Art ihreres Datentyps(?)

Code: Alles auswählen

 case 1:      ; product *p = start;
            break;
      case 2:    ; costumer *p = start;
            break;
      case 3:      ; order *p = start;
            break;
      case 4:      ; costumOrder *p = start;
            break;
      default:   ; void *p = NULL;
            break;
Und das funktioniert dann nicht mehr.
Warum kannst du nicht eine generische Liste erzeugen, und dann einfach die Instanzen Spezifisch machen?

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 11:20 am
von aequatio
Danke dir erstmal. Was genau meinst du jedoch mit Instanzen spezifisch machen? (hört sich etwas nach Objektorientiert an und würde das Problem deutlich vereinfachen :D )

Jede Liste besteht aus den gleichen Structs. Ich habe sozusagen für jede Struktur eine Liste, will aber immer mit der gleichen Funktion darauf zugreifen um Code-Wiederholungen zu sparen.

Ich probiere einfach mal ob meine Variante auch so Funktioniert :)

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 11:33 am
von cloidnerux
Danke dir erstmal. Was genau meinst du jedoch mit Instanzen spezifisch machen? (hört sich etwas nach Objektorientiert an und würde das Problem deutlich vereinfachen :D )
Es ist Objektorientierung, nur ohne Klassen.
Was ich meine ist:

Code: Alles auswählen

struct liste
{
    void * data;
    struct liste * next;
}
[...]
struct liste customer;
struct liste prdouct;
struct liste order;
[...]
order.data = &myOrder;
Du hast eine Liste, die generisch ist.
Und deine Unterscheidung, ob es sich nun um Produkte oder Kunden handelt, erfolgt dann nur im Kontext über die Instanz.

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 11:37 am
von aequatio
Mhmm über so ein Konstrukt habe ich vorhin Stundenlang nachgegrübelt und nach gegoogelt...

Hätte wohl früher hier reinschreiben sollen :D :D :D

Gut vielen Dank dir :)

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 2:14 pm
von mfro
Wenn "data" jetzt noch eine union ist, ist das ganze sogar typsicher...

Re: Allgemeine Funktionen um Listen zu bearbeiten (ANSI C)

Verfasst: Fr Mär 13, 2015 4:00 pm
von Xin
mfro hat geschrieben:Wenn "data" jetzt noch eine union ist, ist das ganze sogar typsicher...
Hüstl... es ist zumindest nicht ganz so unsicher. ;-)


Wenn Du es Typsicher haben möchtest, musst Du wirklich mehrere Listen machen:

Code: Alles auswählen

struct Product
{
  struct Product * Next;    // hier ist die Liste...

  char Name[80];   // Produktname
};
Da sich das für alle Datentypen wiederholt, kann man später in C++ den Code so erstellen lassen (generische Programmierung), dass der Compiler einem alle Funktionalitäten für eine Liste für Produkte oder für Order automatisch erstellt. Ohne generische Programmierung, muss man entweder auf Typsicherheit verzichten (also void *), das selbst ausformulieren oder mit Macros arbeiten.