Eingabe und danach größe des arrays "festlegen"



  • Hi,

    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.

    Danke
    MfG Gustl



  • Stichwort:

    vector<Struktur> XY;
    Struktur Test;
    // Daten eingeben und in Test speichern
    
    //
    XY.push_back( Test );
    

    Liest Daten ein in die Variable Test und hängt diese hinten an XY dran.


  • Administrator

    Und vielleicht noch als Ergänzung:
    http://www.cplusplus.com/reference/stl/

    Da hast du die Referenz zu den verschiedenen Container der Standardbibliothek.

    Grüssli



  • 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 freigegeben
    

    Gruß
    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. 🙂


  • Administrator

    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 Container

    Die 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 Erweiterungen

    Oder 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::vector intern 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. 🙂


Anmelden zum Antworten