Bestimmen Sie die Größe eines C++ - Arrays programmgesteuert?
Diese Frage wurde inspiriert durch eine ähnliche Frage: Wie funktioniert delete[] "weiß" die Größe des Operanden-array?
Meine Frage ist ein wenig anders: gibt es eine Möglichkeit, bestimmen die Größe eines C++ - Arrays programmgesteuert? Und wenn nicht, warum? Jede Funktion, die ich gesehen habe, dass dauert ebenfalls ein Feld erfordert einen integer-parameter, um ihm die Größe. Aber wie der verlinkte Frage darauf hingewiesen, delete[]
müssen wissen, die Größe des Speichers freigegeben werden.
Betrachten dieser C++ - code:
int* arr = new int[256];
printf("Size of arr: %d\n", sizeof(arr));
Diese Drucke "Size of arr: 4
", die nur die Größe des Zeigers. Es wäre schön, eine Funktion zu haben, die druckt 256, aber ich glaube nicht, dass man existiert in C++. (Nochmals, die Frage ist, warum es nicht existiert.)
Klärung: ich weiß, dass wenn ich deklariert das array auf dem stack statt dem heap (d.h. "int arr[256];
"), dass die sizeof
operator zurückkehren würde, 1024 (array length * sizeof(int)).
- Eigentlich, wenn Sie zugewiesen das array auf dem stack der sizeof-operator zurückkehren würde, 1024 -- die 256 (Anzahl der Elemente) * 4 (die Größe eines einzelnen Elements). (sizeof(arr)/sizeof(arr[0])) geben würde, das Ergebnis 256.
- danke, habe ich übersehen, weil ich war eigentlich mit char[] in meinem test-code (und sizeof(char) == 1)
- Es ist zwar nur hypotethical - da funktioniert es nicht - ich habe darauf hinweisen, dass Sie geschrieben haben soll
printf("Size of arr: %d\n", sizeof(*arr));
stattprintf("Size of arr: %d\n", sizeof(*arr));
denn Sie wollen zum abrufen der Größe des dereferenzierter Zeiger.
Du musst angemeldet sein, um einen Kommentar abzugeben.
delete []
kennt die Größe reserviert wurde. Jedoch, dass das wissen befindet sich in der Laufzeit oder im Betriebssystem Speicher-manager, was bedeutet, dass es nicht verfügbar ist für den compiler während der Kompilierung. Undsizeof()
ist keine wirkliche Funktion, es ist tatsächlich ausgewertet, um eine Konstante vom compiler, das ist etwas, das es nicht für dynamisch zugewiesenen arrays, deren Größe nicht bekannt ist, während der Kompilierung.Auch, betrachten Sie dieses Beispiel:
Wie würde der compiler wissen, was die Größe der
p
ist? Die Wurzel des Problems ist, dass arrays in C und C++ sind nicht die erste-Klasse-Objekte. Sie zerfallen zu Zeigern, und es gibt keine Möglichkeit für den compiler oder das Programm selbst zu wissen, ob ein Zeiger auf den Anfang der einen Teil des Arbeitsspeichers durchnew
oder auf ein einzelnes Objekt oder einen Ort in der Mitte ein Stück des Arbeitsspeichers durchnew
.Ein Grund dafür ist, dass C und C++ lassen Sie den Speicher management für den Programmierer und dem Betriebssystem, das ist auch der Grund, warum Sie nicht haben die garbage collection. Umsetzung von
new
unddelete
ist nicht Teil der C++ - standard, weil C++ verwendet werden soll, die auf einer Vielzahl von Plattformen, die möglicherweise verwalten Sie Ihr Gedächtnis in sehr unterschiedlicher Weise. Kann es möglich sein zu lassen, C++ verfolgen Sie alle zugeordneten arrays und Ihre Größen, wenn Sie schreiben einen word-Prozessor, der für eine windows-Kiste läuft auf der neuesten Intel-CPU, aber kann es völlig undurchführbar, wenn Sie schreiben eine embedded-system läuft auf einem DSP.void foo(int *a);
nimmt einen Zeiger, der aufvoid foo(int (&a)[5]);
nimmt ein array. Array-Namen zerfallen zu Zeigern, das nervt, aber es bedeutet nicht, dass arrays und Zeiger sind die gleiche Sache."x"
ist ist ein lvalue. Arrays und pointer decay ist sehr schlecht, aber Sie werden verschiedene Dinge. Eine Funktionvoid foo(int* a)
nimmt einen Zeiger auf eine ganze Zahl. Die Tatsache, dass dieser Zeiger auf ein element eines Arrays ist, werden es die ersten pointer decay oder in sonstiger Weise, ist irrelevant.int a[4];
ergibt einen zusammenhängenden 4-byte-chunk-Speicher. Was fehlt, von diesem suggeriert Ihnen, dass dies nicht ein array? Ich versuche nicht zu Haufen auf, ich versuche eine Klärung.&"bar"
gültig ist. Aber die letztere Art istchar (*)[4]
das ist nicht kompatibel mitchar **
.Nein, es gibt keine Möglichkeit zu tun, die in Standard-C++.
Gibt es keinen wirklich guten Grund warum nicht, dass ich bewusst bin. Wahrscheinlich, die Größe wurde als ein Implementierungsdetail, und am besten nicht ausgesetzt. Beachten Sie, dass wenn Sie sagen malloc(1000), es gibt keine Garantie, dass der block zurückgekehrt ist 1000 bytes --- nur, dass es mindestens 1000 bytes. Wahrscheinlich ist es über 1020 (1K minus 4 bytes für den overhead). In diesem Fall, das "1020" Größe ist wichtig für die run-time-Bibliothek zu erinnern. Und natürlich, dass würde sich ändern, zwischen den Implementierungen.
Weshalb der Standards committee Hinzugefügt std:vector<>, die nicht nachverfolgen der genauen Größe.
Nun, es ist tatsächlich ein Weg, um die Größe zu bestimmen, aber es ist nicht "sicher" und wird Verschieden von compiler zu compiler.... , so sollte es nicht verwendet werden, auf alle.
Wenn du dies tust:
int* arr = new int[256];
256 ist unerheblich, Sie erhalten 256*sizeof(int) vorausgesetzt, für diesen Fall 1024, dieser Wert wird gespeichert, wahrscheinlich ( arr - 4 )
So geben Sie die Anzahl der "Elemente"
int* p_iToSize = arr - 4;
printf("Anzahl der Artikel %d", *p_iToSize /sizeof(int));
Für jedes malloc, new, was vor den kontinuierlichen Speicherblock, dass Sie erhalten, es ist auch zugewiesen einen reservierten Platz mit ein paar Informationen über den Speicherblock, der Sie gegeben wurden.
Gemeinsamen Weg zu handhaben, ist entweder eine Vektor -
vordefinieren oder die Größe
sizeof(int) * arrSize
ist dieselbe, wie bei malloc('sizeof(int) * arrSize') ist es nicht??C++ entschieden, um neues zu tun, eine typesafe malloc, als neue muss wissen, sowohl in Größe als e-Nummern der Elemente für den Aufruf ctors, so löschen zum aufrufen dtors. In den frühen Tagen haben Sie pass eigentlich zu löschen, die zahlen sind Objekte, die Sie übergeben, um neue.
Aber Sie dachte, wenn die Nutzung der neuen<Typ>[] der Aufwand für eine Zahl war klein. So beschlossen Sie, die neue[n] muss sich erinnern, n und pass es zu löschen. Es gibt drei wichtigsten Möglichkeiten, es zu implementieren.
Vielleicht möglich ist, um die Größe wie:
Oder die Hölle, keiner von denen.
Je nach Anwendung, die Sie erstellen könnte ein "sentinel-Wert" an das Ende von array.
Sentinel-Wert muss eine einzigartige Eigenschaft.
Können Sie dann entweder ein Prozess-array (oder eine lineare Suche) für die sentinel-Wert, zu zählen, wie Sie gehen. Wenn Sie erreichen die sentinel-Wert, müssen Sie das array zählen.
Für einen einfachen C-string, der terminierenden \0 ist ein Beispiel für eine sentinel-Wert.
Einige magic:
Und dies ist, wie wir es tun, in C++11:
Weil deine variable arr ist nur ein Zeiger. Es enthält die Adresse eines bestimmten Speicherort im Speicher, ohne etwas darüber zu wissen. Sie deklarieren int*, das gibt dem compiler einen Hinweis darauf, was zu tun ist, wenn Sie erhöhe den Zeiger. Andere als das, Sie könnten zeigen, in der Anfang oder das Ende des Arrays oder in den stack oder ins ungültigen Speicher zu.
Aber ich Stimme mit Ihnen, die nicht in der Lage zu nennen sizeof ist sehr ärgerlich 🙂
QuantumPete
Gibt es keine portable Möglichkeit zur Bestimmung der Größe einer dynamisch reservierten Arrays in C++ gegeben nur Ihre Zeiger. C++ ist sehr flexibel und geben Kraft für den Benutzer. Zum Beispiel der standard definiert nicht, wie Speicherzuordnungen arbeiten müssen, z.B. durch hinzufügen eines gewünschten Größe Kopfzeile. Nicht die eine header ermöglicht viel mehr Flexibilität.
Als ein Beispiel, sollten Sie einen string implementiert als char * - array. Es ist üblich, verwenden Sie Zeiger in der Mitte der Reihe zu Holen, von Teilstrings. Als ein Beispiel, siehe die strtok-Funktion in der standard-C-Bibliothek. Wenn einige der header-waren erforderlich, um eingebettet werden kurz vor jedem array, müssten Sie in den Papierkorb, Teile des Arrays vor dem Teilstring.
Alternative Möglichkeit zum verarbeiten der Header wäre die array-Header in einem block im Speicher, und haben Sie diese Punkt, um die raw-array-Speicher anderswo. In vielen Situationen, die diese erfordern würden zwei Zeiger-lookups für jede Referenz, die wäre eine große ziehen an der Leistung. Gibt es Möglichkeiten der überwindung dieser Mängel, aber Sie fügen Sie Komplexität und reduzieren Umsetzung Flexibilität.
Std::vector template ist meine Lieblings-Weg, um die Größe eines array an das array selbst.
C ist portabler Assembler mit besserer syntax.
Leider ist dies nicht möglich. In C und C++, ist es in der Verantwortung des Programmierers zu erinnern, von der Länge eines Arrays, da die array-Länge ist nicht überall gespeichert. Delete[] und free() nicht erinnere mich an die Größe des zugeordneten Blocks, aber Sie können mehr Speicher zuzuweisen, als erforderlich ist, damit Ihre internen Datenstrukturen speichern der Größen der zugewiesenen Speicherblöcke möglicherweise nicht geben Sie die genaue Größe des Arrays.
Beachten Sie, dass die C++ - STL-Vektoren, die im Grunde arrays eingewickelt in eine Klasse mit einigen Hilfsfunktionen, lagern Sie die Länge des Arrays, also, wenn Sie wirklich brauchen diese Funktion, Sie könnte nur Vektoren verwenden.
Im Allgemeinen, Nein. Arrays in C und C++ sind nur Blöcke von Speicher mit keine Buchhaltung Informationen beigefügt. Ohne Speicherung der Länge des Arrays im Arbeitsspeicher und hinzufügen overhead zu tun, ist es unmöglich, in den Allgemeinen Fall.
Gibt es eine Ausnahme für arrays sind statisch zugewiesen. Zum Beispiel, wenn Sie erklären:
int a[50]
dannsizeof(a)
arbeiten. Dies ist möglich, weil die [50] ist Teil der statische Typ des Arrays: es ist bekannt, dass der compiler. sizeof interpretiert wird zur compile-Zeit.Allerdings, wenn Sie erstellen Sie einen Zeiger:
int *p = a
, dannsizeof(p)
wird wieder die Größe des Zeigers, wie Sie erwähnen, nicht die Größe des Arrays, da der compiler nicht wissen, was p Punkte zu.Können Sie nicht, grundlegend:
Einem C++ - array ist nichts anderes als eine Sammlung von Objekten, die gespeichert sind, in einem zusammenhängenden Speicherbereich. Da gibt es keine Löcher zwischen Ihnen (die Polsterung ist innen Objekte), können Sie das nächste element eines Arrays, indem Sie einfach incerementing den Zeiger. Auf CPU-Ebene ist dies eine einfache Anpassung. Nur C++ fügt ein sizeof(element) Multiplikator.
Beachten Sie, dass Implementierungen können wählen, zu implementieren "fat pointers" enthalten, die von array-Grenzen. Sie müssten doppelt so groß sein, wie man bräuchte, um einen link zu einer Art "array gebunden descriptor". Als Nebeneffekt, auf solche Implementierungen könnten Sie in der Lage sein zu rufen
delete [] (1+new int[5]);
Nein, es gibt keinen Weg, dies zu tun, müssen Sie verfolgen, wie groß er ist extern. Klassen wie
std::vector
dies für Sie tun.Nun gibt es std::array, eine effiziente compile-Zeit wrapper um eine Konstante Größe-array:
Werden die Parameter
<type, #elements>
.Bekommen Sie auch noch ein paar andere Nettigkeiten, wie Iteratoren, leer(), und max_size().
Der compiler kann nicht wissen, dass
ist ein array von 100 Zeichen, da Sie es nicht schaffen, eine tatsächliche array im Speicher, sondern erstellt nur einen Zeiger auf 100 uninitialisierte bytes im Speicher.
Wenn Sie wollen, um zu wissen, die Größe des gegebenen array benutzen Sie einfach std::vector.
std::vector ist ein array besser einfach.
@Dima,
Der compiler muss wissen, die Größe der p; andernfalls kann er nicht umsetzen
delete[]
. Der compiler braucht nicht zu sagen, jemand anderes, wie es zahlen aus.Für ein Spaß Weg, um dies zu überprüfen, vergleichen Sie die Zeiger zurückgegeben
operator new[]
auf den Zeiger zurückgegebennew[]
.Wenn Sie erstellen Sie ein array von Zeigern (Create wrapper mit der Vorlage Zeiger) kann man nicht, aber wenn Sie erstellen Sie ein array von Objekt -,
Sie können die Größe des Arrays so:
Den
delete[]
Funktion benötigen, zu dekonstruieren, werden alle Objekte in ihm. dasnew[]
Schlüsselwort legt die Anzahl der Elemente, die hinter all dem array.Den Körper der array sieht so aus:
die Weise, die ich tun, ist durch Division der Größe des Arrays durch die Größe des ersten Elements
Druckt es 100
Könnte man erstellen Sie einfach ein zusätzliches element des Arrays und wenden Sie dann die unmöglichsten Nummer, die im array gespeichert werden. Dann bestimmen Sie die Anzahl der Elemente, die durch irgendeine Funktion, indem diese Zahl.
In dem Fall deklarieren und initialisieren ein array im moment der Schöpfung, Sie kann dann Scannen Sie es und generieren Sie dann eine Zahl, die nicht mit einem der Elemente des Arrays. Aber wenn du dann ändern die Elemente, die Sie nicht wissen, ob dieses element speichert den gleichen Wert wie das Letzte element, also Sie haben dann zum generieren einer neuen Nummer zu speichern in das Letzte element.. Gehst durch all das, könnte man auch speichern nur die Gesamtzahl von Elementen, die im moment der Erstellung in einer variable. Und das wird wahrscheinlich der Fall sein, wenn man nur die array innerhalb einer Funktion.