Wie finde ich die Größe eines Arrays (von einem Zeiger, der auf das erste Elementarray zeigt)?

Lesezeit: 8 Minuten

Benutzeravatar von jkidv
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

Benutzeravatar von Paul Tomblin
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

Benutzeravatar von Zan Lynx
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


Ryans Benutzeravatar
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

skurtons Benutzeravatar
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:

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

Hier ein Beispiel mit a Fuß Struktur:

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

struct foo_t {
    int ball;
};

int main()
{
    foo_t foos3[] = {{1},{2},{3}};
    foo_t foos5[] = {{1},{2},{3},{4},{5}};
    printf("%u\n", getSize(foos3));
    printf("%u\n", getSize(foos5));

    return 0;
}

Ausgabe:

3
5

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:

#define ARRAY_SZ 10

void foo (int (*arr)[ARRAY_SZ]) {
    printf("%u\n", (unsigned)sizeof(*arr)/sizeof(**arr));
}

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.

Davids Benutzeravatar
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.

#include <stdio.h>

#define NUM_DAYS 5
typedef int days_t[ NUM_DAYS ];
#define SIZEOF_DAYS ( sizeof( days_t ) )

int main() {
    days_t  days;
    days_t *ptr = &days; 

    printf( "SIZEOF_DAYS:  %u\n", SIZEOF_DAYS  );
    printf( "sizeof(days): %u\n", sizeof(days) );
    printf( "sizeof(*ptr): %u\n", sizeof(*ptr) );
    printf( "sizeof(ptr):  %u\n", sizeof(ptr)  );

    return 0;
} 

Ausgabe:

SIZEOF_DAYS:  20
sizeof(days): 20
sizeof(*ptr): 20
sizeof(ptr):  4

Benutzeravatar von DigitalRoss
DigitalRoss

Es gibt keine magische Lösung. C ist keine reflektierende Sprache. Objekte wissen nicht automatisch, was sie sind.

Aber Sie haben viele Möglichkeiten:

  1. Fügen Sie natürlich einen Parameter hinzu
  2. Verpacken Sie den Aufruf in ein Makro und fügen Sie automatisch einen Parameter hinzu
  3. 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


1438150cookie-checkWie finde ich die Größe eines Arrays (von einem Zeiger, der auf das erste Elementarray zeigt)?

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

Privacy policy