Linked Liste, Speicherverwaltungsfehler
-
Warum immer mindestens ein Element da ist, kann man aus den beiden Funktionen nicht sehen. Sehe daran auch nichts, was zum Absturz führen sollte, aber:
Was spricht gegen std::list?
Der Code ist eigentlich reines C, mit der Ausnahme, daß du alles in eine Klasse gepackt hast. Freispeicher fordert man in C++ mit new an und gibt ihn mit delete wieder frei. C++ hat eigene Casts, den C-Cast sollte man vermeiden.if ( strncmp(Pointer->Name,VariablenName,strlen(VariablenName)) == 0 )
Ist nicht sehr effizient, weil in der Schleife strlen ausgeführt wird. Wenn du VariablenName zudem als const std::string & übergibst, kannst du auch lesbarer schreiben:
if (VariablenName == Pointer->Name)
Naja, nur so'n paar Anmerkungen. Für deine Fehler bräuchte man wohl den gesamten Code der Klasse, aber vielleicht sieht ja auch jemand mehr als ich.
-
Huch, da fällt mir doch was in der addItem-Funktion auf:
strcpy( ActualElement->Name, VariablenName );
Du mußt für ActualElement->Name natürlich Speicher reservieren, bevor du was dorthin kopieren kannst. Benutz also am besten die STL-Container, dann bleibt dir sowas erspart.
-
ne die std::list hat keine namen/wert abhängigkeiten, wie sie hier verlangt werden.
@Ritchie dann benutz lieber std::string anstatt char* damit ist der code gleich viel schöner und weniger fehleranfällig. oder benutz gleich eine std::map, die hat eine schlüssel/wert speicherung der daten
-
otze schrieb:
ne die std::list hat keine namen/wert abhängigkeiten, wie sie hier verlangt werden.
Du kannst aber eine Liste von Paaren nutzen, beides ist in der STL.
-
Hallo Leute,
erstmal danke für die zahlreichen antworten.
Bei einigen Antworten muss ich mir jedoch erst das entsprechende Wissen nochmals reinziehen.
Man merkt wohl, das ich führ mehr C Programm geschrieben habe und ausser die üblichen C++ Lernprogramme, dies mein erstes wirkliches C++ Programm wird.Ich nehme daher die Kritik gerne an. Insbesondere das mit dem New und delete stimmt.
Hier noch das Interface und die Struktur von der Liste
typedef struct tag_IOElement IOElement; struct tag_IOElement { unsigned char I2CAdresse; // I2C Adresse 0=Memory Var unsigned char Enabled; // Ist diese Variable aktiv unsigned char Locked; // Ist eine Sperre auf diese Var. char Name[10]; // Name der Variable long InitValue; // Startwert der Variable unsigned char ScanRate; // Abtastrate in 100 milli Sek. long Value; // Aktueller Wert float LastScan; // mSek. seit dem letzten Scan unsigned char Type; // Datentyp 0=Byte 1=Word 2=Long unsigned char UpdateRequest; // Wert neu einlesen unsigned char IOAddress; // I/O Adresse des I2C Slave unsigned char ValueChanged; // Mitteilung, das Wert geändert hat long NextWriteValue; // Schreibwert beim naechsten Zyk. IOElement *LastElement; // Vorheriges Element in der Liste IOElement *NextElement; // Zeiger auf das naechste Element }; // ---------------------------------------------------------------------------- // Interface des IO Buffer Objektes // ---------------------------------------------------------------------------- class PitbullyIOBuffer { private: // Siehe jede Instanz nur IOElement *ActualElement; // Actives Element der Instanz protected: // Sehen alle Instanzen gleich int AnzahlDerInstanzen; // Anzahl der Objekte IOElement *MainListe; // HauptListe public: PitbullyIOBuffer(void); // Konstruktor ~PitbullyIOBuffer(void); // Destruktor void SetVariableName(char*); // Setze den Namen der Var. char* GetVariableName(void); // Ermittle den Variblen Name // Setze/frage nach Eigenschaften der Verbindung void SetEnableStatus(unsigned char); // Freigabe der Var. steuern int SetLockStatus(unsigned char); // Sperrung der Var. setzen int IsEabled(void); // Ist die Variable freigegeben int IsLocked(void); // Ist die Variable gesperrt int IsNew(void); // Hat sich der Wert geaendert void MoveFirst(void); // Browse Funktionen void MoveNext(void); void MoveLast(void); int EndOfFile( void ); int BottomOfFile( void ); // Informationsfelder fuer die Erstellung einer Verbindung void SetScanRate(unsigned char); // Scanrate festlegen void SetIOSize( unsigned char ); // Groesse der Variable void SetI2CAdress(unsigned char); // Setze die aktive I2C Adresse void SetIOAdress(unsigned char); // Zieladresse des Slave void SetInitValue(long); // Basis Wert, bis eingelesen void AddItem(char*); // Fuege eine neues Element hinzu void RemoveItem(void); // Entfernt einen Block // Memberroutinen, welche Übertragungsfunktionen ausführen void DoEvent(void); // Ausstehende Events durchführen. long GetValue(void); // Wert ermitteln long SetValue(void); // Wert setzen };
Reserviert man unter C++ noch Speicher in der Art String[10] ?
Ach ja, der Quellcode sieht bei mir auf dem Bildschirm etwas besser eingerückt aus.
Gruss
-
Ach ja,
nur zur Info. Der Compiler ist schon etwas älter, da ich unbeding 80186 Code benötigt.
So, ich habe den Fehler gefunden. In der InitRoutine des Klasse habe ich vergessen im Ursprungszeiger das Link-Element zu setzen.
Danach noch bei dem ersten Additem das Root Element vermerken. (zeiger anpassen).
Gruss
-
otze schrieb:
ne die std::list hat keine namen/wert abhängigkeiten, wie sie hier verlangt werden.
Hö? Ich seh nur, daß er beim Einfügen schaut, ob bereits ein Element dieses Namens existiert. Das kann er doch genauso mit std::list und find() aus <algorithm> machen...
-
Hi Cocaine,
wie geht das den mit std::list und find() ?
Diese Funktion kenne ich noch nicht.
Gruss
-
@cocaine schau dir mal an wie das datenobjekt ausschaut welches er benutzt, und dann sag mir, ob ein find funktionieren würd
.
wenn dann std::find_if.
std::find_if durchsucht die liste mithilfe einer funktion die man bestimmen kann.
mehr dazu gibts hier:
http://www.sgi.com/tech/stl/find_if.htmlund am besten immernoch die gute alte map, dann braucht man nämlich keinen algorithmus zu benutzen und hat weniger schreibarbeit.(und in der geschwindigkeit nimmt sich das auch nicht viel)
-
otze schrieb:
@cocaine schau dir mal an wie das datenobjekt ausschaut welches er benutzt, und dann sag mir, ob ein find funktionieren würd
.
wenn dann std::find_if.
Hast recht. Dachte an nen operator==, aber mit dem geht's ja nur, wenn man die Elemente nicht als Pointer in die Liste legt.
Ich schreib hier trotzdem mal ein Beispiel, damit Ritchie sieht, wie man std::find benutzen kann (ich geb auch gerne zu, daß ich erst ausprobiert hab, bevor ich dir Recht geben konnte
):
#include <iostream> #include <list> #include <string> #include <algorithm> #include <cassert> struct MyElement { MyElement(const char *new_name) : name_(new_name) { } MyElement(const MyElement &other) : name_(other.name_) { } bool operator==(const char *other) { return name_ == other; } std::string name_; }; int main() { std::list<MyElement> lst; lst.push_back(MyElement("Das")); lst.push_back(MyElement("geht")); lst.push_back(MyElement("doch")); lst.push_back(MyElement("oder?")); std::list<MyElement>::iterator it = std::find(lst.begin(), lst.end(), "geht"); std::cout << it->name_ << std::endl; it = std::find(lst.begin(), lst.end(), "nioht?"); assert(it == lst.end()); return 0; }
otze schrieb:
und am besten immernoch die gute alte map, dann braucht man nämlich keinen algorithmus zu benutzen und hat weniger schreibarbeit.(und in der geschwindigkeit nimmt sich das auch nicht viel)
Dazu müßte man aber den Namen aus dem Objekt ziehen (also als Index der Map benutzen), oder?
-
ja, würde aber keinen unterschied mehr machen
-
Hallo Leute,
ich für zwei Tage Offline und konnte daher nicht antworten. Ist sonst nicht meiner Art. Ich werde mir gleich mal diese Funktion ansehen.
Scheint ja auf den ersten Blick übersichtlicher zu sein.
Muss ich aber erst mal verdauen.
Gruss
-
Tja,
in meinem C++ gibt es keine cassert.
Was nun ?
Gruss
-
Das von mir da oben ist nur ein Anwendungsbeispiel für std::find - nicht so nachbauen, sonst wird, sobald in der std::list ein Copy-Ctor aufgerufen wird, jedesmal der String umkopiert (und das passiert nicht selten).
-
Hi Cocaine,
der Compiler hat mit der Zeile
#include <cassert>
ein Problem.
Ist es kein lauffähiges Beispiel?
Ich schreib hier trotzdem mal ein Beispiel, damit ... sieht, ...
Gruss
-
↓
-
Hab dich doch nicht paepstlicher als der Papst. Anscheinend ist es ein veralteter Compiler, der cassert nicht kennt. In dem Fall einfach wie gehabt assert.h verwenden.
-
Hallo bashar,
danke für den Tip.
Ich kenne leider nicht die ganze Ersetzungen und wusste nicht, das man hier assert.h verwenden muss.
Gruss
-
Mein Beitrag war eigentlich an Lars gerichtet, aber der hat sich inzwischen wegeditiert.
-
Ne, soweit bin ich noch nicht gegangen... Musste mal Marcus fragen, ob ich kurz Admin werden darf... Dann vielleicht.