Dynamische Arraygrössen
-
Hallo zusammen..
Ich habe eine kurze Frage zu einem Array mit dynamischer Grösse.int* array; int size = 10; array = new int[size]; for(int i=0; i<size; i++){ array[i] = i+1; } array[10] = 5; // hier meckert der Compiler nicht aber ich frage mich trotzdem, ob das erlaubt ist, da mein Array ja eigentlich nur 10 Elemente hat und ich hier das elfte Element benutze.
-
Ist natürlich nicht erlaubt.
-
klappt bei mir auch - noch einige elemente weiter. Aber nach unbestimmter Anzahl Elemente kannst du Probleme kriegen. ICh würde es in jedem Fall so nicht machen
-
Der Compiler meckert nicht, weil er nicht feststellen kann, wie groß das Array nun tatsächlich ist (in dieser Konstellation vielleicht, aber generell wird's schwierig). Trotzdem ist das Ergebnis der Aktion undefiniert (und das kann in der Praxis bis zu einem Absturz führen - theoretisch ist ALLES erlaubt).
-
Ok dann erstmal danke für die Antworten.
Es scheint ja manchmal ein Problem zu sein, dass der Compiler zu gutherzig ist und auf solche Fehler nicht hinweist.
Ich frage mich jetzt, ob der folgende Code auch Sachen enthält, die zwar funktionieren aber dennoch nicht erlaubt sind. Vielleicht hat der eine oder andere mal Lust sich das anzuschauen und mir zu sagen, ob das so ok ist oder ob ich da Dinge eingebaut habe, die mir irgendwann um die Ohren fliegen könnten. Bei dem Codestückchen geht es allerdings weniger darum, ob es sinvoll ist oder nicht, sondern eher darum, ob der Code korrekt ist und nicht irgendwann mal Probleme macht.#include <iostream> using namespace std; void array_push(int* arr, int &size, int value){ int* pNewArray; pNewArray = new int[size]; for(int i=0; i<size; i++){ pNewArray[i] = arr[i]; } delete[] arr; size++; arr = new int[size]; for(i=0; i<size-1; i++){ arr[i] = pNewArray[i]; } arr[size-1] = value; } int main(){ int* str; int size = 10; str = new int[size]; for(int i=0; i<size; i++){ str[i] = i+1; cout << str[i] << endl; } cout << endl; array_push(str, size, 199); array_push(str, size, 562); array_push(str, size, 843); for(i=0; i<size; i++){ cout << str[i] << endl; } delete[] str; return 0; }
-
Der Code verursacht zumindest ein Speicherleck (pNewArray wird bei jedem Funktionsaufruf neu angelegt, aber nie freigegeben), außerdem ist er alles andere als sicher (du verlässt dich darauf, daß size und arr nie außerhalb der push_array() geändert werden).
Außerdem übergibst du arr per wert, so daß sich die Änderungen in der Funktion (Neu-Zuweisungen) nicht auf das Hauptprogramm auswirken - das geht hier anscheinend gut, weil der Heap-Manager genug Reserven übrig hat, um dir jedes Mal den selben Speicherblock zuzuweisen. (Primitivlösung:
int*&arr)PS: Auch wenn du nicht über den Sinn reden wolltest: Statt solcher Spielereien solltest du besser mit std::vector<> arbeiten.
-
Danke für die einleuchtenden Kommentare.
Habe schon einiges über std::vector<> gelesen und auch verstanden, dass es die bessere Lösung wäre. Aber erstmal versuche ich hinter einige andere Dinge zu steigen, da ich, wie man an diesem Beispiel sieht, auch bei anderen Dingen (wie z.b. Zeigern) meine Problemchen habe. Jedenfalls war dein Post wirklich hilfreich, also vielen Dank dafür.
-
Eins vielleicht noch:
Du nanntest die "Primitivlösung"
CStoll schrieb:
[c]int*&arr[/c
Was wäre denn die bessere Lösung? Oder könnte man es bedenkenlos so machen?
-
Die bessere Lösung ist es, std::vector<> zu verwenden (oder eine eigene Containerklasse zu schreiben, die dein arr und size intern kapselt).
-
Ehm wenn du schon Arrays nutzen willst:
#include <algorithm> namespace array { template <typename T> void resize(T*& ptr, std::size_t old_size, std::size_t size) { T* tmp = new T[size]; std::copy(ptr, ptr + std::min<std::size_t>(size, old_size), tmp); delete [] ptr; ptr = tmp; } template <typename T> void push_back(T*& ptr, std::size_t& size, T const& data) { resize(ptr, size, size + 1); ptr[size++] = data; } }...
int main() { int* arr = new int[10]; array::resize(arr, 10, 14); array::push_back(arr, 14, 10); std::cout << arr[14] << std::endl; }...
-
(D)Evil schrieb:
template <typename T> void push_back(T*& ptr, std::size_t& size, T const& data) { resize(ptr, size, ++size); ptr[size] = data; } }...
Sehr gefährlich - erstens ist nicht garantiert, in welcher Reihenfolge Funktionsargumente ausgewertet werden (wenn das von hinten nach vorne geschieht, übergibst du den falschen Wert als alte Größe) und Nebeneffekte sich auswirken und zweitens ist ptr[size] garantiert außerhalb des reservierten Speicherbereiches.
-
ehm sorry ich korrigier es kurz ^^ Tippfehler

-
Noch eine letzte Frage:
Hat es einen besonderen Grund, dass ich hier fast alle nur beispielsweise std::cout nutzen sehe, statt "using namespace std; cout << etc."? Gibt es einen Vor- bzw. Nachteil bei einer der Varianten?
-
Für kurze Programmbeispiele nehme ich normalerweise std::..., um explizit auf Standardfunktionen hinzuweisen, ansonsten ist using durchaus beliebter.
(wobei man bei using auch vorsichtig sein sollte, gerade in Headern provozierst du damit förmlich Namenskonflikte)