Array auf Heap bei Laufzeit vergrössen ohne Vector/List



  • #include <cstdio>
    #include <iostream>
    
    int main()
    {
    	char *erstesArray = new char[10];
    
    	sprintf(erstesArray, "123456789");
    
    	std::cout << erstesArray << std::endl;
    
    	char *zweitesArray = new char[11];
    
    	for (int i = 0; i < 10; ++i)
    	{
    		zweitesArray[i] = erstesArray[i];
    	}
    
    	strcat(zweitesArray, "!");
    
    	delete[] erstesArray;
    
    	std::cout << zweitesArray << std::endl;
    
    	delete[] zweitesArray;
    
    	return 0;
    }
    


  • Nun müsste zweitesArray den Namen von erstesArray haben...

    EDIT: Geht das?

    char *array1 = new char[10];
    char *temparray = new char[10];
    for(int c = 0; c < 10; c++)
    {
      temparray[c] = array1[c];
    }
    delete[] array1;
    array1 = new char[11];
    for(int c = 0; c < 10; c++)
    {
      array1[c] = temparray[c];
    }
    array1[10] = '!';
    


  • Du kannst natürlich von vornherein den Array in einer Klasse kapseln (SmartArray). Dann hast du z.B. auch den Schutz gegen Zugriffe mit falschen Indices. Innerhalb der Kapselung kannst du dann den Speicher vergrößern ohne den alten Speicher wegzuschmeißen. Im Prinzip ist programmierst du für deine Bedürfnisse den STL Vector nach. Wenn du nur char brauchst, kannst du ja die templates weglassen.

    Gruß,
    Stephan.



  • EOutOfResources schrieb:

    Nun müsste zweitesArray den Namen von erstesArray haben...

    EDIT: Geht das?

    char *array1 = new char[10];
    char *temparray = new char[10];
    for(int c = 0; c < 10; c++)
    {
      temparray[c] = array1[c];
    }
    delete[] array1;
    array1 = new char[11];
    for(int c = 0; c < 10; c++)
    {
      array1[c] = temparray[c];
    }
    array1[10] = '!';
    

    Ja, aber das geht auch einfacher:

    int main()
    {
    	char *array1 = new char[10];
    
    	char *array2 = new char[11];
    	for (int i = 0; i < 10; ++i)
    	{
    		array2[i] = array1[i];
    	}
    
    	delete[] array1;
    
    	array1 = array2;
    
    	array1[10] = '!';
    
    	delete[] array1;
    
    	return 0;
    }
    


  • #include <iostream>
    
    const int START_SIZE = 1;
    const int END_SIZE = 2;
    
    void GrowArray(char **a1, int n1, int n2);
    void FillArray(char *a, int n, char c);
    
    int main()
    {
    	char *array1 = new char[START_SIZE + 1];
    
    	FillArray(array1, START_SIZE, '!');
    
    	std::cout << array1 << std::endl;
    
    	GrowArray(&array1, START_SIZE, END_SIZE + 1);
    
    	FillArray(array1, END_SIZE, '!');
    
    	std::cout << array1 << std::endl;
    
    	delete[] array1;
    
    	return 0;
    }
    
    void GrowArray(char **a1, int n1, int n2)
    {
    	char *a2 = new char[n2];
    
    	for (int i = 0; i < n1; ++i)
    	{
    		a2[i] = (*a1)[i];
    	}
    
    	delete[] *a1;
    
    	*a1 = a2;
    }
    
    void FillArray(char *a, int n, char c)
    {
    	for (int i = 0; i < n; ++i)
    	{
    		a[i] = c;
    	}
    
    	a[n] = '\0';
    }
    

  • Mod

    Alle so prozedural heute? Warum nicht, wie von tarmin vorgeschlagen, als hübsche, sich selbst verwaltende Klasse? Das wäre um so vieles einfacher und sicherer in der Benutzung.



  • Das sehe ich auch so. Ist vielleicht blöd, wenn man noch keine Klassen kennt, aber ansonsten würde ich dringend zur Kapselung raten.

    Ohne jemanden angreifen zu wollen: Die hier gezeigten Codes sind grauenhaftes C++ (unübersichtlich, mühsam in der Handhabung, sehr fehleranfällig). Am ehesten geht noch kljkljk's Version, aber auch das kann man noch einfacher lösen. 😉



  • Aber grundsätzlich:

    EOutOfResources schrieb:

    Dann brauch ich ein elftes Element. Wie soll ich das Problem am effizientisten lösen (ohne std)?

    Wenn es effizient sein soll, spricht etwas dagegen, es gleich wie std::vector zu lösen? Also vorallokieren und bei Bedarf vergrössern? Dann hat man nämlich nicht bei jedem Einfügen ein Umkopieren der ganzen Sequenz.

    Dann hat man drei Variablen: Zeiger auf dynamisches Array, Kapazität (totale Anzahl Array-Elemente) und Grösse (Anzahl momentan benutzter Array-Elemente). Die kann man mindestens in einem struct zusammenfassen.



  • Anbei als Hilfestellung und Verständnis ein erster Ansatz zur Kapselung des Arrays. Zu ergänzen wären Exceptionhandling beim Range-Check, Vergrößerung des Arrays etc etc.
    Beim Vergrößern kann man jetzt entscheiden, ob man alles umkopieren möchte, oder einen zweiten Speicher anlegt und über Index-Fallunterscheidung intern auf den entsprechenden Speicher zugreift.
    Gruß, Stephan

    template <class T>
    class SmartArray {
    	public:
    		SmartArray(size_t len = 100) : size_(len) {
    			buf_  = new T[len];
    		}
    		~SmartArray(void){ delete [] buf_; }
    		size_t size(void) const { return size_;}
    		T& operator[](size_t i){
    			if(in_range(i)) return buf_[i];	}
    	private:
    		size_t size_;
    		T* buf_;
    		bool in_range(size_t i) const {
    			return (i>=0 && i<size());};		
    };
    


  • tarmin schrieb:

    Anbei als Hilfestellung
    ...

    Ein Code-Beispiel, welches die Dreierregel verletzt, finde ich wahrscheinlich nicht so hilfreich wie Du. Außerdem sollte der Konstruktor explicit sein.



  • ... Dreierregel ... sollte der Konstruktor explicit sein.

    Selbstverständlich! Ist natürlich richtig. Der Range-Check hat auch kein else usw.


Anmelden zum Antworten