
Pennen
Diese Frage wurde von einer ähnlichen Frage inspiriert: Wie löscht[] „Kennen“ Sie die Größe des Operanden-Arrays?
Meine Frage ist etwas anders: Gibt es eine Möglichkeit, die Größe eines C++-Arrays programmgesteuert zu bestimmen? Und wenn nicht, warum? Jede Funktion, die ich gesehen habe und die ein Array verwendet, benötigt auch einen Integer-Parameter, um ihm die Größe zu geben. Aber wie die verknüpfte Frage zeigte, delete[]
muss die Größe des Speichers kennen, der freigegeben werden soll.
Betrachten Sie diesen C++-Code:
int* arr = new int[256];
printf("Size of arr: %d\n", sizeof(arr));
Das druckt “Size of arr: 4
“, was nur die Größe des Zeigers ist. Es wäre schön, eine Funktion zu haben, die 256 ausgibt, aber ich glaube nicht, dass eine in C++ existiert. (Auch hier ist ein Teil der Frage, warum es nicht existiert.)
Klärung: Ich weiß das, wenn ich das Array auf dem Stack statt auf dem Heap deklariert habe (dh “int arr[256];
“) dass die sizeof
Operator würde 1024 (Array-Länge * sizeof(int)) zurückgeben.

Dima
delete []
kennt die zugewiesene Größe. Dieses Wissen befindet sich jedoch in der Laufzeit oder im Speichermanager des Betriebssystems, sodass es dem Compiler während der Kompilierung nicht zur Verfügung steht. Und sizeof()
ist keine echte Funktion, sie wird tatsächlich vom Compiler als Konstante ausgewertet, was er für dynamisch zugewiesene Arrays, deren Größe während der Kompilierung nicht bekannt ist, nicht tun kann.
Betrachten Sie auch dieses Beispiel:
int *arr = new int[256];
int *p = &arr[100];
printf("Size: %d\n", sizeof(p));
Wie würde der Compiler wissen, wie groß die ist p
ist? Die Wurzel des Problems liegt darin, dass Arrays in C und C++ keine erstklassigen Objekte sind. Sie zerfallen zu Zeigern, und es gibt für den Compiler oder das Programm selbst keine Möglichkeit zu wissen, ob ein Zeiger auf den Anfang eines Speicherblocks zeigt, der von zugewiesen wurde new
oder an ein einzelnes Objekt oder an eine Stelle in der Mitte eines Speicherblocks, der von zugewiesen wurde new
.
Ein Grund dafür ist, dass C und C++ die Speicherverwaltung dem Programmierer und dem Betriebssystem überlassen, weshalb sie auch keine Garbage Collection haben. Implementierung von new
und delete
ist nicht Teil des C++-Standards, da C++ auf einer Vielzahl von Plattformen verwendet werden soll, die ihren Speicher möglicherweise auf sehr unterschiedliche Weise verwalten. Es kann möglich sein, C++ alle zugewiesenen Arrays und ihre Größen verfolgen zu lassen, wenn Sie ein Textverarbeitungsprogramm für eine Windows-Box schreiben, die auf der neuesten Intel-CPU läuft, aber es kann völlig unmöglich sein, wenn Sie ein eingebettetes System schreiben, das darauf läuft ein DSP.
Nun, es gibt tatsächlich eine Möglichkeit, die Größe zu bestimmen, aber es ist nicht “sicher” und wird von Compiler zu Compiler unterschiedlich sein …. sollte also gar nicht verwendet werden.
Wenn Sie dies tun: int* arr = new int[256];
Die 256 ist irrelevant, Sie erhalten 256*sizeof(int), wenn Sie für diesen Fall 1024 annehmen, wird dieser Wert wahrscheinlich bei ( arr – 4 ) gespeichert.
Um Ihnen also die Anzahl der “Elemente” zu geben
int* p_iToSize = arr – 4;
printf(“Anzahl der Elemente %d”, *p_iToSize / sizeof(int));
Für jedes malloc, new, was auch immer vor dem kontinuierlichen Speicherblock, den Sie erhalten, wird auch ein reservierter Platz mit einigen Informationen bezüglich des Ihnen gegebenen Speicherblocks zugewiesen.
Nein, in Standard C++ gibt es dafür keine Möglichkeit.
Es gibt keinen wirklich guten Grund, warum nicht, dass ich mir bewusst bin. Wahrscheinlich wurde die Größe als Implementierungsdetail angesehen und am besten nicht offengelegt. Beachten Sie, dass es keine Garantie dafür gibt, dass der zurückgegebene Block 1000 Bytes groß ist, wenn Sie malloc(1000) sagen – nur, dass es so ist wenigstens 1000 Byte. Höchstwahrscheinlich sind es etwa 1020 (1K minus 4 Bytes für Overhead). In diesem Fall ist die Größe „1020“ für die Laufzeitbibliothek wichtig. Und das würde sich natürlich zwischen den Implementierungen ändern.
Aus diesem Grund hat das Standardkomitee std:vector<> hinzugefügt, das die genaue Größe verfolgt.
Die übliche Methode, dies zu handhaben, besteht darin, entweder einen Vektor zu verwenden
int main()
{
std::vector<int> v(256);
printf("size of v is %i capacity is %i\n", sizeof(int) * v.size(), sizeof(int) * v.capacity());
}
oder die Größe vorgeben
const int arrSize = 256;
int main()
{
int array[arrSize];
printf("Size of array is %i", sizeof(int) * arrSize);
}
C++ hat beschlossen, new hinzuzufügen, um einen typsicheren Malloc auszuführen, da new sowohl die Größe als auch die Anzahl der Elemente zum Aufrufen von ctors kennen muss, also delete zum Aufrufen von dtors. In den Anfangszeiten musste man tatsächlich übergeben, um die Nummern eines übergebenen Objekts neu zu löschen.
string* p = new string[5];
delete[5] p;
Sie dachten jedoch, dass bei Verwendung von new[] der Overhead einer Nummer war gering. Also haben sie das neu entschieden[n] muss sich an n erinnern und es zum Löschen übergeben. Es gibt drei Hauptwege, um es zu implementieren.
- Halten Sie eine Hash-Tabelle von Zeigern auf die Größe
- schrieb es direkt in der Nähe des Vektors
- etwas ganz anderes machen
Vielleicht ist es möglich, die Größe so zu erhalten:
size_t* p = new size_t[10];
cout << p[-1] << endl;
// Or
cout << p[11] << endl;
Oder zur Hölle nichts davon.

Bärenvarietät
Abhängig von Ihrer Anwendung können Sie am Ende Ihres Arrays einen “Sentinel-Wert” erstellen.
Der Sentinel-Wert muss eine eindeutige Eigenschaft haben.
Sie können dann entweder das Array nach dem Sentinel-Wert verarbeiten (oder eine lineare Suche durchführen) und dabei zählen. Sobald Sie den Sentinel-Wert erreicht haben, haben Sie Ihre Array-Anzahl.
Bei einem einfachen C-String ist das abschließende \0 ein Beispiel für einen Sentinel-Wert.
Etwas Magie:
template <typename T, size_t S>
inline
size_t array_size(const T (&v)[S])
{
return S;
}
Und so machen wir es in C++11:
template<typename T, size_t S>
constexpr
auto array_size(const T (&)[S]) -> size_t
{
return S;
}
10133500cookie-checkBestimmen Sie die Größe eines C++-Arrays programmgesteuert?yes
Wenn Sie das Array auf dem Stapel zuweisen, würde der sizeof-Operator tatsächlich 1024 zurückgeben – das ist 256 (die Anzahl der Elemente) * 4 (die Größe eines einzelnen Elements). (sizeof(arr)/sizeof(arr[0])) würde das Ergebnis 256 ergeben.
– Kevin
13. Oktober 2008 um 16:03 Uhr
danke, das habe ich übersehen, weil ich eigentlich char benutzt habe[] in meinem Testcode (und sizeof(char) == 1)
– Kipp
13. Oktober 2008 um 16:20 Uhr
Obwohl es nur hypothetisch ist – da es nicht funktioniert – muss ich darauf hinweisen, dass Sie hätten schreiben sollen
printf("Size of arr: %d\n", sizeof(*arr));
anstattprintf("Size of arr: %d\n", sizeof(*arr));
da Sie die Größe des dereferenzierten Zeigers abrufen möchten.– mg30rg
12. Juni 2014 um 10:32 Uhr