Eingabe und danach größe des arrays "festlegen"
-
Gustl schrieb:
eine Frage kann man dem Anwender soviele zB. Zahlen/Zeichen in einen Array eingeben lassen und danach wird dann die Größe des array "festgelegt"?
Kann man das mit dynamischer Speicherreservierung realisieren?
Wenn ja, kann mir da einer ein kleines Beispiel dazu schreiben? Wäre echt nice.Hallo Gustl,
verwende die Container der STL, das ist viel einfacher als selbst eine dynamische Speicherreservierung zu basteln. Etwa so:
#include <iostream> #include <vector> // Container mit dynamischer Speicherreservierung int main() { using namespace std; std::vector< int > zahlen; cout << "Gib soviel Zahlen ein wie Du willst; beende die Eingabe mit einem x" << endl; for( int zahl; cin >> zahl; ) zahlen.push_back( zahl ); // hier drin passiert die dynamische Speicherreservierung automatisch cin.clear(); cin.ignore( 9999, '\n' ); // Rest der Zeile ignorieren cout << "Danke fuer " << zahlen.size() << " Zahlen" << endl; // -- hier liegen 'zahlen.size()' Zahlen in 'zahlen' vor return 0; } // am Ende des Scopes von vector<> wird der Speicher wieder automatisch freigegebenGruß
Werner
-
Danke euch, aber leider wollte ich wissen was im push_back() so abläuft.
Also genau wie die dynamische Speicherverwaltung hier abläuft.Aber es funktioniert.

-
Gustl schrieb:
Danke euch, aber leider wollte ich wissen was im push_back() so abläuft.
Also genau wie die dynamische Speicherverwaltung hier abläuft.Dann wäre vielleicht dieser Artikel für dich noch interessant:
http://magazin.c-plusplus.net/artikel/Aufbau der STL - Teil 1%3A ContainerDie anderen zwei sind durchaus auch empfehlenswert zum lesen:
http://magazin.c-plusplus.net/artikel/Aufbau der STL - Teil 2%3A Iteratoren und Algorithmen
http://magazin.c-plusplus.net/artikel/Aufbau der STL - Teil 3%3A Hilfsklassen und ErweiterungenOder willst du es noch genauer wissen? Dann wird das etwas kompliziert, hier so schnell mal zu erklären. Man sollte aber eigentlich genügend Informationen über solche Dinge in den guten C++ Büchern bekommen oder einem guten Buch über die C++ Standardbibliothek.
Grüssli
-
Gustl schrieb:
Danke euch, aber leider wollte ich wissen was im push_back() so abläuft.
Also genau wie die dynamische Speicherverwaltung hier abläuft.Vereinfacht dargestellt:
Der Vector alloziert anfangs ein Array mit einer gewissen Anzahl von Elmenten. Falls beim push_back außerhalb des Bereiches geschrieben werden würde, wird ein größeres Array (z.B. bisherige Größe * 2) alloziert, der Inhalt umkopiert, und anschließend das alte Array gelöscht (Einer der Gründe warum push_back den iterator ungültig machen kann, da dieser noch auf den alten Bereich zeigen würde).cu André
-
Ah ok, ich dachte es geht auch ohne kopieren des "alten" zu kleinen arrays in ein neues. Aber wohl nicht, alles klar danke euch.
MfG Gustl
-
Gustl schrieb:
Ah ok, ich dachte es geht auch ohne kopieren des "alten" zu kleinen arrays in ein neues. Aber wohl nicht, alles klar danke euch.
Kann es ja gar nicht, weil
std::vectorintern immer einen zusammenhängenden Speicherbereich (Array) verwaltet. Wenn dieser zu klein wird, muss eben ein neuer gesucht werden.
-
Gustl schrieb:
Ah ok, ich dachte es geht auch ohne kopieren des "alten" zu kleinen arrays in ein neues. Aber wohl nicht, alles klar danke euch.
Man kann Arrays nicht vergrößern. Das ist auch relativ logisch, da die Elemente im Speicher direkt hintereinander liegen, und man nicht davon ausgehen kann das der Speicherbereich dahinter nicht bereits belegt ist.
Wenn dies zu Performanceproblemen führt muss man abwägen ob andere Container besser geeignet sind (Eine dynamische Liste z.B. arbeitet ohne zusammenhängenden Speicher, dafür ist der Zugriff langsamer...).
-
Du kannst aber, bevor du ihn füllst, eine bestimmte Menge an Platz reservieren. So du diesen Platz beim Füllen nicht überschreitest, wird auch nichts umkopiert. (Stichwort .reserve(int)).
-
Gustl schrieb:
Danke euch, aber leider wollte ich wissen was im push_back() so abläuft.
Also genau wie die dynamische Speicherverwaltung hier abläuft.Hallo Gustl,
ich hatte in meiner Bastelkiste noch einen vector-Light gefunden; da kannst Du sehen, wie die Methode push_back funktioniert.
Folgenden Code kannst Du mit zu dem von mir gepostete Programm hinzufügen und in Zeile 7 schreibst Du:
gustl::vector< int > zahlen;dann sollte alles wieder wie vorher funktionieren. Hier der Code:
#include <cstddef> // std::size_t #include <cassert> namespace gustl { template< typename T > class vector { public: typedef std::size_t size_type; typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* iterator; vector() : m_first(0), m_last(0), m_end(0) {} ~vector() { clear(); } void push_back( const T& x ) { if( !m_first || m_last == m_end ) // falls nicht genug Platz .. grow(); // .. Speicher vergrößern new( m_last ) T( x ); // placement new legt Objekt im Speicher ab ++m_last; } size_type size() const { return m_first? m_last - m_first: 0; } bool empty() const { return !m_first; } void clear() { for( T* p = m_first; p != m_last; ++p ) p->~T(); // Objekte löschen operator delete( m_first ); // Speicher freigeben m_first = 0; } T& operator[]( size_type i ) { assert( i < size() ); return *(m_first + i); } iterator begin() { return m_first; } iterator end() { return m_first? m_last: 0; } private: // -- exceptionsicheres Anwachsenlassen des Speichers void grow() { const size_type new_size = m_first? 2*size(): 1; if( !m_first ) m_last = 0; // neuen größeren Speicher besorgen T* const first = static_cast< T* >( operator new( sizeof(T) * new_size ) ); T* last = first; try { // vorhanden Objekte in neuen Speicher kopieren for( T* src = m_first; src != m_last; ++last, ++src ) new( last ) T( *src ); // Placement new legt das Objekt in den Speicher } catch( ... ) { // es ist ein Fehler aufgetreten => bereits kopierte Objekte wieder löschen for( T* del = first; del != last; ++del ) del->~T(); operator delete( first ); // neuen Speicher wieder freigeben throw; // Exception weitergeben; Zustand von vector<> ist unverändert } clear(); // bisherigen Kram löschen m_first = first; m_last = last; m_end = m_first + new_size; } // -- Kopieren ist nicht implementiert vector( const vector& ); vector& operator=( const vector& ); // -- Member T* m_first; // der Anfang T* m_last; // hinter das letzte Objekt im Speicher T* m_end; // hinter das Ende des Speichers }; }Gruß
Werner
-
Echt klasse, dank dir.
