397 Stimmen

Wie findet man die 'sizeof' (einen Zeiger, der auf ein Array zeigt)?

Zunächst einmal ist hier etwas 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, das ptr verweist (anstatt nur die Größe anzugeben, die auf einem 32-Bit-System vier Byte beträgt)?

344voto

Paul Tomblin Punkte 172816

Nein, das können Sie nicht. Der Compiler weiß nicht, worauf der Zeiger verweist. Es gibt Tricks, wie z.B. das Array mit einem bekannten Wert außerhalb des Bandes zu beenden und dann die Größe bis zu diesem Wert zu zählen, aber das ist keine Verwendung von sizeof() .

Ein anderer Trick ist der, der von Zan Das heißt, die Größe irgendwo zu verstecken. Wenn Sie zum Beispiel das Array dynamisch zuweisen, weisen Sie einen Block zu, der einen int größer ist als der benötigte, speichern Sie die Größe im ersten int und geben Sie ptr+1 als Zeiger auf das Array. Wenn Sie die Größe benötigen, dekrementieren Sie den Zeiger und schauen Sie sich den gespeicherten Wert an. Denken Sie nur daran, den gesamten Block von Anfang an freizugeben und nicht nur das Array.

117voto

Zan Lynx Punkte 51045

Die Antwort lautet: "Nein".

C-Programmierer speichern die Größe des Arrays irgendwo. Das kann ein Teil einer Struktur sein, oder der Programmierer kann ein bisschen schummeln und malloc() mehr Speicher als angefordert, um einen Längenwert vor dem Beginn des Arrays zu speichern.

57voto

Ryan Punkte 7525

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. übernimmt. Leider macht C dies nicht annähernd so gut wie C++, da man es im Grunde für jeden verschiedenen Array-Typ, den man speichert, aufbauen muss, was umständlich ist, wenn man mehrere Arten von Arrays hat, die man verwalten muss.

Für statische Arrays, wie das in Ihrem Beispiel, gibt es ein allgemeines Makro, das verwendet wird, um die Größe zu ermitteln, aber es ist nicht empfohlen da es nicht prü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 etwas anders aussehen kann als das untenstehende:

#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, warum Sie bei solchen Makros vorsichtig sein sollten. Seien Sie vorsichtig.

Wenn möglich, die C++ stdlib wie Vektor, die viel sicherer und einfacher zu bedienen ist.

19voto

skurton Punkte 341

Es gibt eine saubere Lösung mit C++-Vorlagen, ohne die Verwendung von sizeof() . Die folgenden getSize() 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 ist ein Beispiel mit einer foo_t 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

11voto

jxh Punkte 66464

Wie alle richtigen Antworten gezeigt haben, können Sie diese Information nicht allein aus dem zerfallenen Zeigerwert des Arrays gewinnen. Wenn der zerfallene Zeiger das Argument ist, das die Funktion erhält, dann muss die Größe des ursprünglichen Arrays auf eine andere Weise angegeben werden, damit die Funktion diese Größe erfährt.

Hier ist ein Vorschlag, der sich von den bisherigen Vorschlägen unterscheidet und der funktionieren wird: Übergeben Sie stattdessen einen Zeiger auf das Array. Dieser Vorschlag ähnelt den Vorschlägen im C++-Stil, mit der Ausnahme, 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 ziemlich albern, da die Funktion so definiert ist, dass sie genau die Größe des übergebenen Arrays kennt (daher gibt es kaum eine Notwendigkeit, sizeof überhaupt auf das Array anzuwenden). Was es jedoch tut, ist eine gewisse Typsicherheit zu bieten. Sie 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 einem beliebig großen Array zu arbeiten, müssen Sie der Funktion die Größe als zusätzliche Information übergeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X