Warum ist die Größe eines Array-Parameters nicht dieselbe wie innerhalb von main?

Lesezeit: 4 Minuten

Benutzeravatar von Chris_45
Chris_45

Warum ist die Größe eines Arrays, die als Parameter gesendet wird, nicht die gleiche wie innerhalb von main?

#include <stdio.h>

void PrintSize(int p_someArray[10]);

int main () {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* As expected, 40 */
    PrintSize(myArray);/* Prints 4, not 40 */
}

void PrintSize(int p_someArray[10]){
    printf("%d\n", sizeof(p_someArray));
}

Ein Array-Typ ist implizit in einen Zeigertyp konvertiert, wenn Sie ihn an eine Funktion übergeben.

So,

void PrintSize(int p_someArray[10]) {
    printf("%zu\n", sizeof(p_someArray));
}

und

void PrintSize(int *p_someArray) {
    printf("%zu\n", sizeof(p_someArray));
}

sind gleichwertig. Was Sie also bekommen, ist der Wert von sizeof(int*)

  • In C++ können Sie das Array per Referenz an die Funktion übergeben, aber das ist in C nicht möglich.

    – Prasun Saurav

    29. Dezember 2009 um 15:32 Uhr


  • Sie müssten die Größe des Arrays als separaten Parameter übergeben. Dann wäre die Größe des Arrays sizeof(*p_someArray) * length

    – Aric TenEyck

    29. Dezember 2009 um 15:38 Uhr

  • Kleines Manko: sizeof Der Operator gibt ein Objekt vom Typ zurück size_talso sollten Sie es mit drucken %zu (C99), oder werfen Sie es auf int wenn du benutzt %d wie oben in Ihrer printf Anrufe.

    – Alok Singhal

    29. Dezember 2009 um 15:41 Uhr

  • Aloks Aussage ist richtig. Die Verwendung eines falschen Formatbezeichners in printf(..) ist UB.

    – Prasun Saurav

    29. Dezember 2009 um 15:55 Uhr


  • @ Chris_45: C hat keine Referenzen, aber in C können Sie ein Array per Zeiger auf das gesamte Array übergeben, wie in: void PrintSize(int (*p_someArray)[10]). Innerhalb der Funktion können Sie auf das Array zugreifen, indem Sie den Dereferenzierungsoperator verwenden *: sizeof(*p_someArray). Dies hat denselben Effekt wie die Verwendung von Referenzen in C++.

    – AnT steht zu Russland

    31. Dezember 2009 um 4:46 Uhr

Benutzeravatar von user240312
Benutzer240312

Es ist ein Zeiger, deshalb ist es eine übliche Implementierung, die Größe des Arrays als zweiten Parameter an die Funktion zu übergeben

Wie andere gesagt haben, zerfallen Arrays zu Zeigern auf ihr erstes Element, wenn sie als Funktionsparameter verwendet werden. Es ist auch erwähnenswert, dass sizeof den Ausdruck nicht auswertet und keine Klammern erfordert, wenn es mit einem Ausdruck verwendet wird, sodass Ihr Parameter überhaupt nicht verwendet wird, sodass Sie sizeof genauso gut mit dem Typ statt mit dem Wert schreiben können.

#include <stdio.h>

void PrintSize1 ( int someArray[][10] );
void PrintSize2 ( int someArray[10] );

int main ()
{
    int myArray[10];
    printf ( "%d\n", sizeof myArray ); /* as expected 40 */
    printf ( "%d\n", sizeof ( int[10] ) ); /* requires parens */
    PrintSize1 ( 0 ); /* prints 40, does not evaluate 0[0] */
    PrintSize2 ( 0 ); /* prints 40, someArray unused */
}

void PrintSize1 ( int someArray[][10] )
{
    printf ( "%d\n", sizeof someArray[0] );
}

void PrintSize2 ( int someArray[10] )
{
    printf ( "%d\n", sizeof ( int[10] ) );
}

Sie müssen also die Länge des Arrays als zweiten Parameter übergeben. Wenn Sie Code schreiben, in dem Sie beide ein Array mit konstanter Größe deklarieren und dieses Array später an eine Funktion übergeben, ist es mühsam, wenn die Array-Längenkonstante an mehreren Stellen in Ihrem Code angezeigt wird …

K&R zur Rettung:

#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 

So können Sie jetzt zB:

int a[10];
...
myfunction(a, N_ELEMENTS(a));

Das Verhalten, das Sie gefunden haben, ist eigentlich eine große Warze in der C-Sprache. Immer wenn Sie eine Funktion deklarieren, die einen Array-Parameter akzeptiert, ignoriert der Compiler Sie und ändert den Parameter in einen Zeiger. Diese Deklarationen verhalten sich also alle wie die erste:

void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)

a ist in allen vier Fällen ein Zeiger auf int. Wenn Sie ein Array an func übergeben, zerfällt es sofort in einen Zeiger auf sein erstes Element. (Auf einem 64-Bit-System ist ein 64-Bit-Zeiger doppelt so groß wie ein 32-Bit-Int, sodass Ihr sizeof-Verhältnis 2 zurückgibt.)

Der einzige Zweck dieser Regel besteht darin, die Abwärtskompatibilität mit historischen Compilern aufrechtzuerhalten, die die Übergabe von Aggregatwerten als Funktionsargumente nicht unterstützten.

Das bedeutet nicht, dass es unmöglich ist, ein Array an eine Funktion zu übergeben. Sie können diese Warze umgehen, indem Sie das Array in eine Struktur einbetten (das ist im Grunde der Zweck von std::array von C++11):

struct array_rly {
int a[5];
};
void func(struct array_rly a)
{
printf("%zd\n", sizeof(a.a)/sizeof(a.a[0]));  /* prints 5 */
}

oder indem Sie einen Zeiger auf das Array übergeben:

void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints 5 */
}

Falls die Arraygröße keine Kompilierzeitkonstante ist, können Sie die Pointer-to-Array-Technik mit C99-Arrays variabler Länge verwenden:

void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints n */
}

Benutzeravatar von Khaled Alshaya
Khaled Alshaya

Weil Arrays in Zeiger zerfallen, wenn sie als Parameter übergeben werden. So funktioniert C, obwohl Sie “Arrays” in C++ als Referenz übergeben und dieses Problem umgehen können. Beachten Sie, dass Sie Arrays unterschiedlicher Größe an diese Funktion übergeben können:

 // 10 is superfluous here! You can pass an array of different size!
void PrintSize(int p_someArray[10]);

Benutzeravatar von Alexandre C
Alexandre C.

In c++ können Sie zu diesem Zweck ein Array per Referenz übergeben:

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}

  • Wie würde das bei einer C-Frage helfen?

    – alk

    30. Dezember 2017 um 18:12 Uhr

1422070cookie-checkWarum ist die Größe eines Array-Parameters nicht dieselbe wie innerhalb von main?

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

Privacy policy