Fragen zu Pointern
-
Hallo,
ich möchte ein Programm (in C++) schreiben, welches Aufgrund der großen Datenmengen mehrere Pointer verwendet, um zeitgünstige Vertauschoperationen zu ermöglichen. Allerdings ist bei dieser Problematik die ganze Pointergeschichte etwas unüberschaubar für mich geworden. Deshalb wäre ich froh wenn mir jemand ein paar Tipps geben könnte, ob der Code das macht, was ich will oder wie ich das erreichen könnte.
Fragen:
Wie speichere ich in einem Arrayelement ein Adresse eines Arrays? (siehe unteres Bsp.)
Wie greife ich auf diese verschachtelten Pointer zu?Problembeschreibung:
Wären die Vertauschoperationen nicht nötig, würde das Konstrukt einem mehrdimensionalen Array von Datenstrukturen gleichen:struct testErgebnis { unsigned int testID, data1, data2; }; meinStruct daten[170][500][30][30];Um das Vertauschen zu ermöglichen habe ich Pointer ("->") eingesetzt. Schematisch wäre das nun:
meinStruct daten[170]->[500]->[30][30];Der erste Pointer soll es mir erlauben verschiedene der 170 Elemente untereinander zu tauschen ohne großartig Daten kopieren zu müssen.
Der zweite Pointer soll es mir ermöglichen auf eine Art Dummy (ein 30*30-meinStruct-Array) zu zeigen, denn viele der 30*30-Arrays werden exakt die gleichen Inhalte wie dieses Dummy-Array haben (hier wird also Speichersparpotential genutzt).Nun mein Vorschlag-Code:
#include <iostream> using namespace std; struct testErgebnis{ unsigned int testID, data1, data2; // 6 Bytes }; int main() { // ein Array fuer alle Datensaetze - jedes Element ist ein Pointer auf ein Array von Tests testErgebnis* datensaetze[170]; // 170 Elemente erzeugen und Array mit Pointern darauf fuellen for( unsigned int i = 0; i < 170; i++) { // jedes Element ist ein Pointer auf einen 30*30-Testdatensatz testErgebnis* tests[500]; // i-tes Element auf erzeugtes 500er-Array zeigen lassen datensaetze[i] = &tests[0]; // funktioniert ohne "&", aber ich möchte ja die Adresse und nicht den Inhalt an den Pointer zuweisen (error: expected primary-expression before '[' token) // 500 2D-Arrays erzeugen und darauf zeigen for( unsigned int j = 0; j < 500; j++) { // 900 testErgebnis -Elemente in einem 2D-Array testErgebnis testErgebnisse[30][30]; // datensaetze[i]->[j] soll auf testErgebnisse-Array zeigen ((datensaetze[i])*[j]) = &testErgebnisse[0][0]; /* Wie greift man auf das j-te Element im Speicher zu, auf das von der Adresse in datensaetze[i] gezeigt wird? wie oben funktioniert auch das "&" hier nicht */ } } return 0; }Ich bedanke mich schonmal dafür, dass ihr bis hierher gelesen habt. Diverse Tutorials zu Zeigern haben mir bis jetzt nur bedingt geholfen.
Grüße,
pete
-
datensaetze[i] = &tests[0]; // wird zu datensaetze[i] = tests;Es gibt hier allerdings ein richtiges Problem.
// 500 2D-Arrays erzeugen und darauf zeigen
Du hast hier Stack-Arrays (
testsundtestErgebnisse), welche nur während des Schleifendurchlaufs existieren. Danach werden sie zerstört. Das heißt, du hast massenweise hängende Zeiger in deinen Zeigerarrays.Edit: Ich habe mal den englischen durch einen deutschen Begriff substituiert.
-
Hallo und Danke für die schnelle Antwort.
Ich habe deinen ersten Tipp mal umgesetzt. Zusätzlich habe ich ein " * " angefügt, um die Pointer-auf-Pointer-Beziehung umzusetzen (nur ein Stern erzeugt Fehler: cannot convert 'testErgebnis* [500]' to 'testErgebnis*' in assignment)
testErgebnis** datensaetze[170];Das mit den "hängenden Zeigern" hatte ich zwischenzeitlich anders gelöst, indem ich mit "new" den Speicher angefordert habe. Das sollte doch funktionieren, oder?
Grüße,
pete
-
indem ich mit "new" den Speicher angefordert habe. Das sollte doch funktionieren, oder?
Ja, und dann leckt der Speicher, und das ganze ist nicht exception-safe. Wie wäre es mit Containern?
-
Ich habe schon die verschiedensten Konstrukte für dieses Programm erdacht (verschiedene Containerformen waren da auch dabei). Allerdings habe ich mittlerweile für alle nötigen Operationen Wege gefunden, die mit den starren Arrays Zeit- und Speichergünstig zu realisieren sind. Deshalb würde ich gern vorerst bei Arrays bleiben. Nur das erstellen der Arrays ist momentan problematisch.
Mein neuer Fortschirtt sieht jetzt so aus:
#include <iostream> using namespace std; struct testErgebnis{ unsigned int testID, data1, data2; // 6 Bytes }; int main() { // ein Array fuer alle Datensaetze - jedes Element ist ein Pointer auf ein Array von Tests testErgebnis**** datensaetze = 0; datensaetze = new testErgebnis*** [170]; // 170 Elemente erzeugen und Array mit Pointern darauf fuellen for( unsigned int i = 0; i < 170; i++) { // jedes Element ist ein Pointer auf einen 30*30-Testdatensatz testErgebnis*** tests = 0; tests = new testErgebnis** [500]; // i-tes Element auf erzeugtes 500er-Array zeigen lassen datensaetze[i] = tests; // 500 2D-Arrays erzeugen und darauf zeigen for( unsigned int j = 0; j < 500; j++) { // 900 testErgebnis -Elemente in einem 2D-Array testErgebnis** testErgebnisse; testErgebnisse = new testErgebnis* [30]; // zweite Dimension dynamisch erstellen for(unsigned int k = 0; k < 30; k++) { testErgebnis* temp; temp = new testErgebnis [30]; testErgebnisse[k] = temp; } // datensaetze[i]->[j] - j soll Zeiger auf testErgebnisse sein (datensaetze[i])[j] = testErgebnisse; // wie funktioniert diese Zuweisung } } cout << "sizeof(datensaetze) [pointer]: " << static_cast<int>(sizeof(datensaetze)) << endl; char inp[10]; cin >> inp; return 0; }Solved. Nach einigen Minuten Abstand bin ich auf die doch recht einfache Lösung gekommen

Falls noch jemand Einwände/Ideen hat, darf er sich gern nochmal melden. Der finale Code steht oben (Achtung: Hinweis wegen Speicherleck beachten!).
(Die Thematik zur Speicherverwaltung werde ich mir nochmal separat vornehmen.)
Danke an Arcoth!
Grüße,
pete
-
Du schreibst hier etwas von Zeit- und Speichergünstig bei den starren Arrays. Wenn du die Arrays aber ohnehin mit New anlegst sind sie weder Zeit- noch Speichergünstiger als ein vector, aber du handelst dir jede menge Probleme mit der manuellen Speicherverwaltung ein. Wozu das ganze?
-
Hi,
also ein Grund warum ich auf Arrays zurückgreife war, dass ich die Vorteile eines Vectors (Elemente anfügen/löschen) nicht brauche oder die Verschiebekosten, falls ich es doch mal machen würde und kein Platz ist, unnötig wären. (Die Arrays haben feste Größen, das wäre also gar nicht so problematisch mit der Speicherverwaltung.)
Allerdings habe ich mir vorgenommen das Ganze nochmal zu überarbeiten:
- die 30*30er-Arrays bleiben Arrays, werden aber in Objekte eingebettet, welche zusätzliche Informationen bereithalten können.
- die ersten 2 Dimensionen könnten zu Vektoren werden (lässt später mehr Möglichkeiten offen, falls doch mal die resize-Option nötig wird; außerdem besserer Stil)Die 30*30er Arrays würden mich als Vektoren wohl je vector nochmal 2 Pointer kosten, was vermeidbar ist:
170 * 500 * 30 * 2 (Pointer) * 8 Byte (AMD64) = 40800000 Byte = 39843,75 kByte = ca. 40 MByteSoweit meine Überlegungen. Oder gibt es noch andere Signifikante Vor-/Nachteile? (Fehlerbehandlung mal abgesehen)
Grüße,
pete
-
Ja.
Nimm entweder vector oder array, und damit meine ich std::array.
Schonmal dran gedacht wie dieses 4-dimensionale Ding löschen willst?
Und auf was für einer Maschine bist du, dass deine Struktur testErgebnisse 6 Byte gross ist? 16Bit Windows 3.1?
Heutzutage dürften das doch eher 12 oder 24 (plus Alignment) sein... zumal du weiter unten ja auch schreibst, dass du auf einem 64 Bit System machst.Aber deine Idee das teilweise in objekte einzukapseln, die gefällt mir. Das mach du mal. Übersichtlichkeit bringt das auch
-
Skym0sh0 schrieb:
Schonmal dran gedacht wie dieses 4-dimensionale Ding löschen willst?
Ja, am Ende des Programms und wohl so wie es entstanden ist - mit einigen for-Schleifen.
Skym0sh0 schrieb:
Und auf was für einer Maschine bist du, dass deine Struktur testErgebnisse 6 Byte gross ist? 16Bit Windows 3.1?
MinGW gibt mir ein 32Bit-Programm, welches im Taskmanager knapp unter 1GB läuft (falls man MS da trauen kann). Werde morgen mal 64Bit compilieren und schauen was rauskommt.
Skym0sh0 schrieb:
Heutzutage dürften das doch eher 12 oder 24 (plus Alignment) sein... zumal du weiter unten ja auch schreibst, dass du auf einem 64 Bit System machst.
Ich hatte mir auch schon überlegt, wie ich die 2 Bytes sinnvoll nutzen könnte, aber zumindest im Debugger wurden die Adressen im Array nun mit "6u *" angegeben, was darauf hindeutet, dass noch mit 6 Bytes gearbeitet wird. Vielleicht fällt es dann aber in der Release-Konfiguration auch der Optimierung zum Opfer.
Grüße,
pete
-
pete92 schrieb:
Hi,
also ein Grund warum ich auf Arrays zurückgreife war, dass ich die Vorteile eines Vectors (Elemente anfügen/löschen) nicht brauche oder die Verschiebekosten, falls ich es doch mal machen würde und kein Platz ist, unnötig wären. (
Wenn du die dynamische Größe nicht benutzt kostet sie auch nichts und wenn du sie nutzt, dann wirst du sie auch brauchen. Dein Code wäre mit vector kein bisschen langsamer, dafür aber korrekt.