Wie erstelle ich ein Array, wenn die Größe eine Variable und keine Konstante ist?

Lesezeit: 8 Minuten

Wie erstelle ich ein Array wenn die Grose eine Variable
Denis S.

Ich habe eine Methode, die eine Variable int erhält. Diese Variable stellt eine Array-Größe dar (bitte bieten Sie mir keinen Vektor an). Daher muss ich in meiner Methode eine Konstante int initieren, um ein Array einer bestimmten Größe zu initialisieren. Frage: wie mache ich das?

void foo(int variable_int){
    int a[variable_int] = {0}; //error
}

  • Was ist falsch an einem Vektor? Da dies fehlschlägt, biete ich Ihnen einen intelligenten Hinweis.

    – Chris

    22. Januar 13 um 13:07 Uhr

  • Warum kein Vektor? Warum überhaupt C++ verwenden, wenn Sie nur C-Idiome verwenden möchten?

    – PaulR

    22. Januar 13 um 13:07 Uhr


  • Stellen Sie sich einen Vektor einfach als ein Array vor, das Sie mit einer variablen Größe initialisieren können. Sind Sie sicher, dass Sie Ihre Frage nicht mit “c” markieren wollten?

    – Roddy

    22. Januar 13 um 13:12 Uhr

  • @den-javamaniac Für die meisten Zwecke ein C++ vector ist mindestens so gut wie ein Array! (Falls Sie noch nie mit C++-Vektoren gearbeitet haben: Der Name ist verwirrend, sie verhalten sich eher wie ein Array als wie ein mathematischer Vektor.) Sie können sogar Vektorelemente mit adressieren [] -Operator, wenn Sie möchten (wenn Sie keine Begrenzungsprüfung benötigen/wollen).

    – us2012

    22. Januar 13 um 13:18 Uhr

  • Die Antwort ist die Verwendung eines Vektors. C++ unterstützt keine Arrays mit variabler Länge, und die Speicherverwaltung ohne RAII führt zu Speicherlecks, wenn irgendetwas eine Ausnahme auslöst.

    – Mike Seymour

    22. Januar 13 um 13:18 Uhr

Wie erstelle ich ein Array wenn die Grose eine Variable
Patatahooligan

Sie haben nach einer Nicht-Vektor-Lösung gefragt, aber gehen wir sie noch einmal durch, weil Sie sie möglicherweise aus den falschen Gründen abgelehnt haben. Sie sollten sich keine Gedanken über die Leistung machen, da dies in den Händen eines kompetenten Compilers so ziemlich den gleichen Overhead haben wird wie jede andere standardkonforme Lösung. Auf der anderen Seite gibt es einige Lesbarkeits- und Sicherheitsbedenken, auf die ich weiter unten eingehen werde. Schauen wir uns die Möglichkeiten an, wie Sie dies tun können, von den am meisten empfohlenen bis zu den am wenigsten empfohlenen.

std::Vektor

Der Lieblingscontainer der Community und das aus gutem Grund. Es kann nicht nur mit einer Laufzeitgröße deklariert werden, sondern die Größe kann jederzeit geändert werden. Dies erleichtert die Verwendung, wenn die Größe nicht vorherbestimmt werden kann, z. B. beim wiederholten Abfragen von Benutzereingaben. Beispiele:

// Known size
size_t n;
std::cin >> n;
std::vector<int> vec(n);

// Unknown size
std::vector<int> vec;
int input;
while (std::cin >> input) { // Note: not always the best way to read input
    vec.push_back(in);
}

Es gibt nicht viel Nachteil bei der Verwendung std::vector. Der Fall bekannter Größe erfordert genau eine dynamische Zuordnung. Die unbekannte Größe erfordert im allgemeinen Fall mehr, aber besser geht es sowieso nicht. Die Leistung ist also mehr oder weniger optimal.

Semantisch ist es möglicherweise nicht ideal für Größen, die während der gesamten Ausführung konstant sind. Für den Leser ist möglicherweise nicht ersichtlich, dass dieser Container nicht geändert werden soll. Es ist dem Compiler auch nicht bekannt, sodass Sie etwas falsch machen können, z push_back in ein vector das ist logischerweise von konstanter Größe.

std::unique_ptr (oder std::shared_ptr)

Die sicherste Lösung, wenn Ihnen die Durchsetzung der statischen Größe wichtig ist.

size_t n;
std::cin >> n;
auto arr = std::make_unique<int[]>(n);

arrDie Größe von kann sich nicht ändern, es kann jedoch dazu gebracht werden, das aktuelle Array freizugeben und auf ein anderes mit unterschiedlicher Größe zu verweisen. Wenn also die Größe Ihres Containers logischerweise konstant ist, vermittelt dies die Absicht klarer. Leider ist es auch viel schwächer als std::vector auch im Fall konstanter Größe. Es ist nicht größenbewusst, daher müssen Sie die Größe explizit speichern. Aus dem gleichen Grund bietet es keine Iteratoren und kann nicht im Bereich für Schleifen verwendet werden. Es liegt an Ihnen (und dem betreffenden Projekt), ob Sie diese Funktionen opfern möchten, um eine statische Größe zu erzwingen.

Anfangs hatte ich empfohlen boost::scoped_array aber nach weiterem Nachdenken glaube ich nicht, dass es gegenüber dieser Lösung viel zu bieten hat, also bleibe ich bei der Standardbibliothek.

Neu[] – löschen[]

Technisch gesehen eine Lösung, aber wenn Sie nicht gezwungen sind, einen alten C++-Standard zu verwenden, oder Sie eine Low-Level-Bibliothek schreiben, die den Speicher intern verwaltet, sind sie streng schlechter als die std::unique_ptr oder std::shared_ptr Lösung. Sie bieten keine Features mehr, sind aber deutlich weniger sicher, weil man den Speicher explizit freigeben muss, wenn man damit fertig ist. Andernfalls wird es auslaufen, was zu erheblichen Problemen führen kann. Um die Sache noch schlimmer zu machen, mit delete[] kann für Programme mit komplizierten Ausführungsabläufen und Ausnahmebehandlung nicht trivial sein. Bitte verwenden Sie dies nicht, wenn Ihnen die oben genannten Lösungen zur Verfügung stehen!

size_t n;
std::cin >> n;
int* arr = new int[n];
...
// Control flow must reach exactly one corresponding delete[] !!!
delete[] arr;

Bonus: Compiler-Erweiterung

Einige Compiler sind möglicherweise mit dem folgenden Code einverstanden

size_t n;
std::cin >> n;
int arr[n];

Sich darauf zu verlassen, hat schwerwiegende Nachteile. Ihr Code kann nicht auf allen C++-konformen Compilern kompiliert werden. Es kompiliert wahrscheinlich nicht einmal auf allen Versionen des angegebenen Compilers. Außerdem bezweifle ich, dass die produzierte ausführbare Datei den Wert überprüft n und weist bei Bedarf auf dem Haufen zu, was bedeutet, dass Sie Ihren Stapel sprengen können. Diese Lösung ist nur sinnvoll, wenn Sie die Obergrenze von kennen n klein ist und Ihnen die Leistung so wichtig ist, dass Sie bereit sind, sich auf das Compiler-spezifische Verhalten zu verlassen, um sie zu erhalten. Das sind wirklich Ausnahmefälle.

1643848814 290 Wie erstelle ich ein Array wenn die Grose eine Variable
Zennehoy

int *a = new int[variable_int];

Denken Sie daran, zu löschen[] den zugewiesenen Speicherplatz, wenn Sie damit fertig sind!

  • Oder noch besser, std::vector<int> a(variable_int). Jetzt müssen Sie nicht daran denken, es zu löschen oder die Speicherlecks zu debuggen, die andernfalls unvermeidlich auftreten, wenn eine Ausnahme ausgelöst wird.

    – Mike Seymour

    22. Januar 13 um 13:13 Uhr

  • @MikeSeymour Einverstanden, aber die Verwendung eines Vektors war keine Voraussetzung für die Frage.

    – zennehoy

    22. Januar 13 um 13:14 Uhr

  • Tut mir leid, diese seltsame Anforderung ist mir nicht aufgefallen. Dann viel Glück beim Debuggen der Speicherlecks.

    – Mike Seymour

    22. Januar 13 um 13:16 Uhr

  • Ein weiterer einfacher Weg ist alloca, int *a = alloca(variable_int);, die wie diese Antwort den Speicher nicht auf einen bestimmten Wert initialisiert, aber den Vorteil hat, ein sehr schnelles Zuordnungsschema zu sein: Speicher wird im Vergleich zum Heap auf dem Stapel zugewiesen, sodass Sie auch keinen Speicher erhalten Ausnahme (hier besteht die Möglichkeit, dass der Stapelspeicher knapp wird, aber dann haben Sie größere Probleme). Verwenden Sie diesen Trick für kleine Zuweisungen (bis zu einigen Kilobyte).

    – radikal7

    22. Januar 13 um 13:18 Uhr


  • @MikeSeymour – Ich bin bei dir: Benutze einen Vektor. Die Erfüllung seltsamer Anforderungen ist ein Zeitfresser.

    – Peter Becker

    22. Januar 13 um 13:29 Uhr


1643848815 842 Wie erstelle ich ein Array wenn die Grose eine Variable
Mike Seymour

C++ unterstützt keine Arrays variabler Länge. Stattdessen müssen Sie das Array dynamisch zuweisen:

std::vector<int> a(variable_int);

oder da Sie sagen, dass Sie aus irgendeinem Grund keinen Vektor verwenden möchten:

class not_a_vector
{
public:
    explicit not_a_vector(size_t size) : a(new int[size]()) {}
    ~not_a_vector() {delete [] a;}
    int & operator[](size_t i) {return a[i];}
    int   operator[](size_t i) const {return a[i];}

    not_a_vector(not_a_vector const &) = delete;
    void operator=(not_a_vector const &) = delete;

private:
    int * a;
};

not_a_vector a(variable_int);

UPDATE: Die Frage wurde gerade mit dem “C”-Tag sowie “C++” aktualisiert. C (seit 1999) unterstützt Arrays mit variabler Länge, daher sollte Ihr Code in dieser Sprache in Ordnung sein.

Sie können einfach durch Schreiben eine konstante Variable aus einer nicht konstanten Variablen machen const int bar = variable_int; – aber das wird dir nicht helfen. In C++ muss die Größe eines Arrays mit automatischer Speicherung a sein Kompilierzeit Konstante. Sie können eine Variable nicht in eine Kompilierzeitkonstante umwandeln, also ist das, was Sie wollen, einfach nicht möglich.

Je nach Ihren Bedürfnissen könnten Sie machen a einen Zeiger und weisen Sie Speicher mit zu new (und dann später delete it) oder, wenn der Parameter to foo wird immer zur Kompilierzeit bekannt sein, könnten Sie umdrehen foo in eine Template-Funktion wie diese:

template<int n> void foo() {
    int a[n] = {0};
}

Um zu tun, was Sie wollen, müssen Sie die dynamische Zuordnung verwenden. In diesem Fall würde ich ernsthaft vorschlagen, stattdessen Vektor zu verwenden – es ist die “richtige” Vorgehensweise in C++.

Aber wenn Sie immer noch keinen Vektor verwenden möchten [why you wouldn’t is beyond me]der richtige Code lautet:

 void foo(int variable_int){
    int *a   = new int[variable_int]();   // Parenthesis to initialize to zero.
    ... do stuff with a ... 
    delete [] a;
 }

Wie andere vorgeschlagen haben, können Sie auch calloc verwenden, was den gleichen Effekt der Initialisierung auf Null hat, aber nicht wirklich die “c++”-Lösung.

  • Vergessen Sie nicht, catch für die Ausnahmesicherheit auszuprobieren 😉 Es lohnt sich immer, sich anzusehen, wie viel Beinarbeit std::vector für Sie erledigt!

    – Roddy

    22. Januar 13 um 13:15 Uhr

  • Danke für die Klammern, ich habe segfault ohne em bekommen. 🙂

    – Denys S.

    22. Januar 13 um 13:27 Uhr

Wie erstelle ich ein Array wenn die Grose eine Variable
Peter Holz

Wenn Sie Arrays verwenden, ist es eine gute Idee, sie zu kapseln:

template<typename Type>
class Vector {
    //...
};

Die Standardbibliothek enthält eine Implementierung: std::Vektor

  • Vergessen Sie nicht, catch für die Ausnahmesicherheit auszuprobieren 😉 Es lohnt sich immer, sich anzusehen, wie viel Beinarbeit std::vector für Sie erledigt!

    – Roddy

    22. Januar 13 um 13:15 Uhr

  • Danke für die Klammern, ich habe segfault ohne em bekommen. 🙂

    – Denys S.

    22. Januar 13 um 13:27 Uhr

.

748330cookie-checkWie erstelle ich ein Array, wenn die Größe eine Variable und keine Konstante ist?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy