Wie finde ich die Größe eines Arrays (von einem Zeiger, der auf das erste Elementarray zeigt)?
Lesezeit: 8 Minuten
jkidv
Zunächst einmal ist hier ein Code:
int main()
{
int days[] = {1,2,3,4,5};
int *ptr = days;
printf("%u\n", sizeof(days));
printf("%u\n", sizeof(ptr));
return 0;
}
Gibt es eine Möglichkeit, die Größe des Arrays herauszufinden, die ptr zeigt auf (anstatt nur seine Größe anzugeben, die auf einem 32-Bit-System vier Bytes beträgt)?
Ich habe immer Klammern mit sizeof verwendet – sicher, dass es wie ein Funktionsaufruf aussieht, aber ich denke, es ist klarer.
– Paul Tomblin
29. Januar 2009 um 16:44 Uhr
Warum nicht? Haben Sie etwas gegen überflüssige Klammern? Ich denke, es liest sich ein wenig leichter mit ihnen, ich selbst.
– David Thornley
29. Januar 2009 um 16:44 Uhr
@Paul: gut .. Angenommen, die linke Seite dieses Aufrufs ist ein Zeiger auf int, würde ich es als int *ptr = malloc(4 * sizeof *ptr) schreiben; was für mich viel klarer ist. Weniger zu lesende Klammern und die wörtliche Konstante nach vorne bringen, wie in der Mathematik.
– abschalten
29. Januar 2009 um 17:32 Uhr
@unwind – Weisen Sie kein Array von Zeigern zu, wenn Sie ein Array von Ints meinten!
– Paul Tomblin
29. Januar 2009 um 17:47 Uhr
Hier gibt es keinen “Zeiger, der auf ein Array zeigt”. Nur ein Zeiger, der auf ein int zeigt.
– neues Konto
28. Februar 2013 um 19:01 Uhr
Paul Tomblin
Nein, das kannst du nicht. Der Compiler weiß nicht, worauf der Zeiger zeigt. Es gibt Tricks, wie das Beenden des Arrays mit einem bekannten Out-of-Band-Wert und das Zählen der Größe bis zu diesem Wert, aber das ist nicht sinnvoll sizeof().
Ein weiterer Trick ist der von Zan erwähnte, der darin besteht, die Größe irgendwo zu verstauen. Wenn Sie beispielsweise das Array dynamisch zuweisen, weisen Sie einen Block zu, der um ein Int größer ist als der benötigte, speichern Sie die Größe im ersten Int und kehren Sie zurück ptr+1 als Zeiger auf das Array. Wenn Sie die Größe benötigen, verringern Sie den Zeiger und sehen Sie sich den gespeicherten Wert an. Denken Sie nur daran, den gesamten Block von Anfang an freizugeben, und nicht nur das Array.
Es tut mir leid, dass ich so spät einen Kommentar gepostet habe, aber wenn der Compiler nicht weiß, worauf der Zeiger zeigt, wie weiß Free, wie viel Speicher gelöscht werden muss? Ich weiß, dass diese Informationen intern für Funktionen wie Free to Use gespeichert werden. Meine Frage ist also, warum kann der Compiler das auch?
– viki.omega9
3. März 2013 um 19:19 Uhr
@viki.omega9, weil kostenlos die Größe zur Laufzeit entdeckt. Der Compiler kann die Größe nicht kennen, da Sie das Array je nach Laufzeitfaktoren (Befehlszeilenargumente, Inhalt einer Datei, Mondphase usw.) unterschiedlich groß machen könnten.
– Paul Tomblin
3. März 2013 um 20:48 Uhr
Schnell nachfassen, warum gibt es keine Funktion, die die Größe so zurückgeben kann, wie dies kostenlos der Fall ist?
– viki.omega9
3. März 2013 um 22:52 Uhr
Nun, wenn Sie garantieren könnten, dass die Funktion nur mit mallociertem Speicher aufgerufen wurde und die Bibliothek den mallocierten Speicher so verfolgt, wie ich es meistens gesehen habe (durch Verwendung eines int vor dem zurückgegebenen Zeiger), dann könnten Sie einen schreiben. Wenn der Zeiger jedoch auf ein statisches Array oder ähnliches verweist, würde dies fehlschlagen. Ebenso gibt es keine Garantie dafür, dass Ihr Programm auf die Größe des mallocierten Speichers zugreifen kann.
– Paul Tomblin
3. März 2013 um 23:11 Uhr
@viki.omega9: Eine andere Sache, die Sie beachten sollten, ist, dass die vom malloc/free-System aufgezeichnete Größe möglicherweise nicht die Größe ist, nach der Sie gefragt haben. Sie mallocieren 9 Bytes und erhalten 16. Mallocieren 3 KB und erhalten 4 KB. Oder ähnliche Situationen.
– Zan Luchs
20. Juli 2014 um 3:48 Uhr
Zan Luchs
Die Antwort ist nein.”
C-Programmierer speichern die Größe des Arrays irgendwo. Es kann Teil einer Struktur sein, oder der Programmierer kann ein bisschen schummeln und malloc() mehr Speicher als angefordert, um einen Längenwert vor dem Start des Arrays zu speichern.
So werden Pascal-Strings implementiert
– dsm
29. Januar 2009 um 16:44 Uhr
und anscheinend sind Pascal-Strings der Grund, warum Excel so schnell läuft!
– Adam Naylor
14. Juli 2010 um 19:48 Uhr
@Adam: Es ist schnell. Ich verwende es in einer Liste von Zeichenfolgenimplementierungen von mir. Es ist superschnell für die lineare Suche, weil es so ist: Größe laden, Pos+Größe vorab abrufen, Größe mit Suchgröße vergleichen, wenn gleich strncmp, zur nächsten Zeichenfolge wechseln, wiederholen. Es ist schneller als die binäre Suche bis zu etwa 500 Zeichenfolgen.
– Zan Luchs
14. Juli 2010 um 19:52 Uhr
Ryan
Für dynamische Arrays (malloc oder C++ Neu) müssen Sie die Größe des Arrays speichern, wie von anderen erwähnt, oder vielleicht eine Array-Manager-Struktur erstellen, die das Hinzufügen, Entfernen, Zählen usw. handhabt. Leider macht C dies nicht annähernd so gut wie C++, da Sie es im Grunde erstellen müssen für jeden unterschiedlichen Array-Typ, den Sie speichern, was umständlich ist, wenn Sie mehrere Arten von Arrays verwalten müssen.
Für statische Arrays, wie das in Ihrem Beispiel, gibt es ein allgemeines Makro, das verwendet wird, um die Größe zu erhalten, aber es ist nicht empfohlen da es nicht überprüft, ob der Parameter wirklich ein statisches Array ist. Das Makro wird jedoch in echtem Code verwendet, z. B. in den Linux-Kernel-Headern, obwohl es sich geringfügig von dem folgenden unterscheiden kann:
#if !defined(ARRAY_SIZE)
#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
#endif
int main()
{
int days[] = {1,2,3,4,5};
int *ptr = days;
printf("%u\n", ARRAY_SIZE(days));
printf("%u\n", sizeof(ptr));
return 0;
}
Sie können nach Gründen googeln, um bei solchen Makros vorsichtig zu sein. Vorsichtig sein.
Wenn möglich, die C++ stdlib wie Vektor, die viel sicherer und einfacher zu verwenden ist.
ARRAY_SIZE ist ein allgemeines Paradigma, das von praktischen Programmierern überall verwendet wird.
– Sanjaya R
29. Januar 2009 um 17:19 Uhr
Ja, es ist ein gemeinsames Paradigma. Sie müssen es dennoch vorsichtig verwenden, da es leicht vergessen und auf einem dynamischen Array verwendet werden kann.
– Ryan
29. Januar 2009 um 17:27 Uhr
Ja, guter Punkt, aber die Frage, die gestellt wurde, betraf den Zeiger, nicht den statischen Array.
– Paul Tomblin
29. Januar 2009 um 17:40 Uhr
Dass ARRAY_SIZE Das Makro funktioniert immer, wenn sein Argument ein Array ist (dh ein Ausdruck vom Typ Array). Für Ihr sogenanntes “dynamisches Array” erhalten Sie niemals ein tatsächliches “Array” (Ausdruck des Array-Typs). (Natürlich können Sie das nicht, da Array-Typen ihre Größe zur Kompilierzeit angeben.) Sie erhalten nur einen Zeiger auf das erste Element. Ihr Einwand “überprüft nicht, ob der Parameter wirklich ein statisches Array ist” ist nicht wirklich gültig, da sie sich unterscheiden, da einer ein Array ist und der andere nicht.
– neues Konto
28. Februar 2013 um 18:52 Uhr
Es gibt eine herumschwebende Vorlagenfunktion, die dasselbe tut, aber die Verwendung von Zeigern verhindert.
– Natalie Adams
23. April 2013 um 2:24 Uhr
skurton
Es gibt eine saubere Lösung mit C++-Vorlagen, ohne Verwendung von Größe von(). Folgende getSize() Die Funktion gibt die Größe eines beliebigen statischen Arrays zurück:
Wie alle richtigen Antworten angegeben haben, können Sie diese Informationen nicht allein aus dem verfallenen Zeigerwert des Arrays erhalten. Wenn der verfallene Zeiger das von der Funktion empfangene Argument ist, muss die Größe des ursprünglichen Arrays auf andere Weise bereitgestellt werden, damit die Funktion diese Größe erfährt.
Hier ist ein Vorschlag, der sich von dem unterscheidet, was bisher bereitgestellt wurde, der funktionieren wird: Übergeben Sie stattdessen einen Zeiger auf das Array. Dieser Vorschlag ähnelt den C++-Stilvorschlägen, außer dass C keine Vorlagen oder Referenzen unterstützt:
Aber dieser Vorschlag ist für Ihr Problem irgendwie albern, da die Funktion so definiert ist, dass sie die Größe des übergebenen Arrays genau kennt (daher besteht kaum Bedarf, sizeof überhaupt für das Array zu verwenden). Was es jedoch tut, ist eine gewisse Typensicherheit. Es verhindert, dass Sie ein Array mit einer unerwünschten Größe übergeben.
int x[20];
int y[10];
foo(&x); /* error */
foo(&y); /* ok */
Wenn die Funktion in der Lage sein soll, mit Arrays beliebiger Größe zu arbeiten, müssen Sie der Funktion die Größe als zusätzliche Information zur Verfügung stellen.
David
Für dieses spezifische Beispiel gibt es ja, WENN Sie typedefs verwenden (siehe unten). Wenn Sie es auf diese Weise tun, können Sie natürlich genauso gut SIZEOF_DAYS verwenden, da Sie wissen, worauf der Zeiger zeigt.
Wenn Sie einen (void *)-Zeiger haben, wie er von malloc() oder ähnlichem zurückgegeben wird, dann gibt es keine Möglichkeit festzustellen, auf welche Datenstruktur der Zeiger zeigt, und somit auch keine Möglichkeit, seine Größe zu bestimmen.
Es gibt keine magische Lösung. C ist keine reflektierende Sprache. Objekte wissen nicht automatisch, was sie sind.
Aber Sie haben viele Möglichkeiten:
Fügen Sie natürlich einen Parameter hinzu
Verpacken Sie den Aufruf in ein Makro und fügen Sie automatisch einen Parameter hinzu
Verwenden Sie ein komplexeres Objekt. Definieren Sie eine Struktur, die das dynamische Array und auch die Größe des Arrays enthält. Übergeben Sie dann die Adresse der Struktur.
Objekte wissen, was sie sind. Aber wenn Sie auf ein Unterobjekt zeigen, gibt es keine Möglichkeit, Informationen über das vollständige Objekt oder ein größeres Unterobjekt zu erhalten
– MM
29. Januar 2020 um 4:14 Uhr
14381500cookie-checkWie finde ich die Größe eines Arrays (von einem Zeiger, der auf das erste Elementarray zeigt)?yes
Ich habe immer Klammern mit sizeof verwendet – sicher, dass es wie ein Funktionsaufruf aussieht, aber ich denke, es ist klarer.
– Paul Tomblin
29. Januar 2009 um 16:44 Uhr
Warum nicht? Haben Sie etwas gegen überflüssige Klammern? Ich denke, es liest sich ein wenig leichter mit ihnen, ich selbst.
– David Thornley
29. Januar 2009 um 16:44 Uhr
@Paul: gut .. Angenommen, die linke Seite dieses Aufrufs ist ein Zeiger auf int, würde ich es als int *ptr = malloc(4 * sizeof *ptr) schreiben; was für mich viel klarer ist. Weniger zu lesende Klammern und die wörtliche Konstante nach vorne bringen, wie in der Mathematik.
– abschalten
29. Januar 2009 um 17:32 Uhr
@unwind – Weisen Sie kein Array von Zeigern zu, wenn Sie ein Array von Ints meinten!
– Paul Tomblin
29. Januar 2009 um 17:47 Uhr
Hier gibt es keinen “Zeiger, der auf ein Array zeigt”. Nur ein Zeiger, der auf ein int zeigt.
– neues Konto
28. Februar 2013 um 19:01 Uhr