it-swarm.com.de

Wie finde ich die 'sizeof' (ein Zeiger auf ein Array)?

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

282
jkidv

Nein, kannst du nicht. Der Compiler weiß nicht, auf was der Zeiger zeigt. Es gibt Tricks wie das Beenden des Arrays mit einem bekannten Out-of-Band-Wert und das anschließende Zählen der Größe bis zu diesem Wert, wobei sizeof jedoch nicht verwendet wird.

Ein weiterer Trick ist der von Zan erwähnte, der darin besteht, die Größe irgendwo zu verstecken. Wenn Sie beispielsweise das Array dynamisch zuweisen, weisen Sie einen Block zu, der einen Int größer ist als der von Ihnen benötigte, speichern Sie die Größe im ersten Int und geben Sie ptr + 1 als Zeiger auf das Array zurück. Wenn Sie die Größe benötigen, dekrementieren Sie den Zeiger und sehen Sie sich den verdeckten Wert an. Denken Sie daran, den gesamten Block von Anfang an freizugeben und nicht nur das Array.

245
Paul Tomblin

Die Antwort ist nein."

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

76
Zan Lynx

Für dynamische Arrays ( malloc oder C++ new ) müssen Sie das speichern Größe des Arrays, wie von anderen erwähnt, oder vielleicht eine Array-Manager-Struktur erstellen, die das Hinzufügen, Entfernen, Zählen usw. handhabt. Leider funktioniert C nicht annähernd so gut wie C++, da Sie es grundsätzlich für jeden anderen Array-Typ erstellen müssen Das Speichern ist umständlich, wenn Sie mehrere Arten von Arrays verwalten müssen.

Für statische Arrays, wie in Ihrem Beispiel, wird ein allgemeines Makro verwendet, um die Größe abzurufen. Es ist jedoch nicht empfohlen, da nicht geprüft wird, ob der Parameter wirklich ein statisches Array ist. Das Makro wird jedoch in echtem Code verwendet, z. in den Linux-Kernel-Headern, obwohl sie sich möglicherweise geringfügig von der folgenden unterscheiden:

#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 aus Gründen googeln, um bei solchen Makros vorsichtig zu sein. Achtung.

Wenn möglich, die C++ - Stdlib wie Vector, die viel sicherer und einfacher zu bedienen ist.

45
Ryan

Es gibt eine saubere Lösung mit C++ - Vorlagen, ohne sizeof () zu verwenden. Die folgende Funktion getSize () gibt die Größe eines 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
17
skurton

Ja, für dieses Beispiel gibt es WENN Sie typedefs verwenden (siehe unten). Wenn Sie dies auf diese Weise tun, können Sie natürlich auch SIZEOF_DAYS verwenden, da Sie wissen, auf was der Zeiger zeigt.

Wenn Sie einen (void *) - Zeiger haben, wie er von malloc () oder ähnlichem zurückgegeben wird, gibt es keine Möglichkeit festzustellen, auf welche Datenstruktur der Zeiger zeigt, und somit 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
5
David

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. Schließen Sie den Aufruf in ein Makro ein und fügen Sie automatisch einen Parameter hinzu
  3. Verwenden Sie ein komplexeres Objekt. Definieren Sie eine Struktur, die das dynamische Array sowie die Größe des Arrays enthält. Übergeben Sie dann die Adresse der Struktur.
4
DigitalRoss

Wie alle richtigen Antworten angegeben haben, können Sie diese Informationen nicht allein aus dem verfallenen Zeigerwert des Arrays abrufen. Wenn der zerfallene Zeiger das von der Funktion empfangene Argument ist, muss die Größe des Ursprungsarrays auf andere Weise angegeben werden, damit die Funktion diese Größe erkennt.

Hier ist ein Vorschlag, der sich von den bisherigen Vorschlägen unterscheidet und funktioniert: Ü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));
}

Dieser Vorschlag ist jedoch etwas albern für Ihr Problem, da die Funktion so definiert ist, dass sie genau die Größe des übergebenen Arrays kennt (daher muss sizeof für das Array überhaupt nicht verwendet werden). Was es jedoch tut, ist eine gewisse Sicherheit zu bieten. Dies verhindert, dass Sie ein Array mit unerwünschter Größe übergeben.

int x[20];
int y[10];
foo(&x); /* error */
foo(&y); /* ok */

Wenn die Funktion in der Lage sein soll, mit einer Array-Größe zu arbeiten, müssen Sie die Größe der Funktion als zusätzliche Information angeben.

3
jxh
int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

Die Größe von Tagen [] ist 20, also keine Elemente. * Die Größe des Datentyps. Während die Größe des Zeigers 4 ist, spielt es keine Rolle, auf was er zeigt. Weil ein Zeiger auf ein anderes Element zeigt, indem er dessen Adresse speichert.

2

Meine Lösung für dieses Problem besteht darin, die Länge des Arrays in einem Strukturarray als Metainformation über das Array zu speichern.

#include <stdio.h>
#include <stdlib.h>

struct Array
{
    int length;

    double *array;
};

typedef struct Array Array;

Array* NewArray(int length)
{
    /* Allocate the memory for the struct Array */
    Array *newArray = (Array*) malloc(sizeof(Array));

    /* Insert only non-negative length's*/
    newArray->length = (length > 0) ? length : 0;

    newArray->array = (double*) malloc(length*sizeof(double));

    return newArray;
}

void SetArray(Array *structure,int length,double* array)
{
    structure->length = length;
    structure->array = array;
}

void PrintArray(Array *structure)
{       
    if(structure->length > 0)
    {
        int i;
        printf("length: %d\n", structure->length);
        for (i = 0; i < structure->length; i++)
            printf("%g\n", structure->array[i]);
    }
    else
        printf("Empty Array. Length 0\n");
}

int main()
{
    int i;
    Array *negativeTest, *days = NewArray(5);

    double moreDays[] = {1,2,3,4,5,6,7,8,9,10};

    for (i = 0; i < days->length; i++)
        days->array[i] = i+1;

    PrintArray(days);

    SetArray(days,10,moreDays);

    PrintArray(days);

    negativeTest = NewArray(-5);

    PrintArray(negativeTest);

    return 0;
}

Sie müssen sich jedoch darum kümmern, die richtige Länge des Arrays festzulegen, das Sie speichern möchten, da dies nicht möglich ist, wie unsere Freunde ausführlich erklärt haben.

2
user4713908

Sie können so etwas tun:

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;

Nein, Sie können sizeof(ptr) nicht verwenden, um die Größe des Arrays zu ermitteln, auf das ptr zeigt.

Das Zuweisen von zusätzlichem Speicher (mehr als die Größe des Arrays) ist hilfreich, wenn Sie die Länge in zusätzlichem Speicherplatz speichern möchten.

1
SKD
 #define array_size 10

 struct {
     int16 size;
     int16 array[array_size];
     int16 property1[(array_size/16)+1]
     int16 property2[(array_size/16)+1]
 } array1 = {array_size, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

 #undef array_size

array_size übergibt an die Variable size :

#define array_size 30

struct {
    int16 size;
    int16 array[array_size];
    int16 property1[(array_size/16)+1]
    int16 property2[(array_size/16)+1]
} array2 = {array_size};

#undef array_size

Verwendung ist:

void main() {

    int16 size = array1.size;
    for (int i=0; i!=size; i++) {

        array1.array[i] *= 2;
    }
}
0
user3065147