Warum stimmt die Größe eines Array-Parameters nicht mit der von main überein?

104

Warum stimmt die Größe eines als Parameter gesendeten Arrays nicht mit der von main überein?

#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));
}
Chris_45
quelle

Antworten:

103

Ein Array-Typ wird 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 vonsizeof(int*)

Prasoon Saurav
quelle
1
In C ++ können Sie das Array unter Bezugnahme auf die Funktion übergeben, dies ist jedoch in C nicht möglich.
Prasoon Saurav
13
Sie müssen die Größe des Arrays als separaten Parameter übergeben. Dann wäre die Größe des Arrays sizeof (* p_someArray) * length
Aric TenEyck
13
Minor nit: sizeofOperator gibt ein Objekt vom Typ size_t, so dass Sie es mit gedruckt werden soll %zu(C99) oder werfen es , intwenn Sie verwenden %doben in Ihrem wie printfAnrufe.
Alok Singhal
4
Aloks Aussage ist richtig. Die Verwendung eines falschen Formatbezeichners in printf (..) ist UB.
Prasoon Saurav
1
@ 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 mit dem Dereferenzierungsoperator auf das Array zugreifen *: sizeof(*p_someArray). Dies hat den gleichen Effekt wie die Verwendung von Referenzen in C ++.
AnT
18

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

user240312
quelle
16

Wie andere angegeben haben, zerfallen Arrays in Zeiger 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 er mit einem Ausdruck verwendet wird. Daher wird Ihr Parameter überhaupt nicht verwendet. Sie können also auch die Größe von mit dem Typ und nicht mit dem Wert schreiben.

#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] ) );
}
Pete Kirkham
quelle
12

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 schwierig, 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, jetzt können Sie zB:

int a[10];
...
myfunction(a, N_ELEMENTS(a));
SC Madsen
quelle
Was ist, wenn die Größe des Arrays zur Codierungszeit nicht verfügbar ist, sondern nur zur Laufzeit? Gibt es eine andere Möglichkeit, die Größe des Arrays zu berechnen, ohne seine Größe fest zu codieren?
weefwefwqg3
Die gezeigte Methode funktioniert nur, wenn die Deklaration des Arrays "in view" ist. In allen anderen Fällen müssen Sie die Array-Länge manuell übergeben.
SC Madsen
5

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 beheben 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]);
AraK
quelle
5

Das Verhalten, das Sie gefunden haben, ist tatsächlich 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 Erklärungen 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 Ihre Größe des Verhältnisses 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ützt haben.

Dies 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 (dies ist im Grunde der Zweck des std :: -Arrays 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 Konstante zur Kompilierungszeit ist, können Sie die Zeiger-zu-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 */
}
Walter
quelle
4

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

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}
Alexandre C.
quelle
1
Wie würde dies bei einer C-Frage helfen?
Alk
3

In der Sprache C gibt es keine Methode zum Bestimmen der Größe eines unbekannten Arrays, daher muss die Menge sowie ein Zeiger auf das erste Element übergeben werden.


quelle
2
Im Allgemeinen sollten Sie die Größe (Anzahl der Elemente) eines Arrays zusammen mit einem Array immer an eine Funktion übergeben, es sei denn, Sie haben eine andere Möglichkeit, seine Größe zu bestimmen (z. B. einen Nullzeichen-Terminator am Ende von char[]String-Arrays).
David R Tribble
Bitte, was ist ein " unbekanntes Array "?
Alk
3

Sie können keine Arrays an Funktionen übergeben.

Wenn Sie die Größe wirklich drucken möchten, können Sie einen Zeiger auf ein Array übergeben, der jedoch überhaupt nicht generisch ist, da Sie auch die Arraygröße für die Funktion definieren müssen.

#include <stdio.h>

void PrintSize(int (*p_anArray)[10]);

int main(void) {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* as expected 40 */
    PrintSize(&myArray);/* prints 40 */
}

void PrintSize(int (*p_anArray)[10]){
    printf("%d\n", (int) sizeof(*p_anArray));
}
HERR.
quelle
0

Das Verhalten ist beabsichtigt.

Dieselbe Syntax in der Deklaration von Funktionsparametern bedeutet etwas völlig anderes als in der Definition lokaler Variablen.

Der Grund ist in anderen Antworten beschrieben.

Pavel Radzivilovsky
quelle
0

Wenn Sie in der Sprache C das Array als Argument an die Funktion übergeben, wird es automatisch in einen Zeiger konvertiert. Das Array, das von einer Funktion übergeben wird, wird als Referenzaufruf bezeichnet. Aus diesem Grund empfängt die aufgerufene Funktion nur den Zeiger, der auf das erste Funktionselement zeigt. Dies ist der Grund

fun (int a []) ähnelt fun (int * a);

Wenn Sie also die Größe des Arrays drucken, wird die Größe des ersten Elements gedruckt.

Dagrawal
quelle
In C gibt es keinen " Call by Reference ".
Alk
" Wenn Sie die Größe des Arrays drucken, wird die Größe des ersten Elements gedruckt. " Nein, es wird die Größe eines Zeigers gedruckt.
Alk
-1

In der Programmiersprache 'C' ist 'sizeof ()' der Operator und er gibt die Größe des Objekts in Bytes zurück. Das Argument des Operators 'sizeof ()' muss ein Typ mit linkem Wert sein (Ganzzahl, Gleitkommazahl, Struktur, Array) ). Wenn Sie also die Größe eines Arrays in Bytes wissen möchten, können Sie dies ganz einfach tun. Verwenden Sie einfach den Operator 'sizeof ()' und für sein Argument den Namen des Arrays. Beispiel:

#include <stdio.h>

main(){

 int n[10];
 printf("Size of n is: %d \n", sizeof(n)); 

}

Die Ausgabe auf dem 32-Bit-System ist: Größe von n ist: 40. Weil die Ganzzahl auf dem 32-System 4 Bytes beträgt. Auf 64x sind es 8 Bytes. In diesem Fall haben wir 10 Ganzzahlen in einem Array deklariert. Das Ergebnis ist also '10 * sizeof ( int) '.

Einige Hinweise:

Wenn wir ein Array wie dieses deklariert haben, ist 'int n [] = {1, 2, 3, ... 155 ..};'. Wir möchten also wissen, wie viele Elemente in diesem Array gespeichert sind. Verwenden Sie diesen Algorithmus:

sizeof (name_of_the_array) / sizeof (array_type)

Code: #include

Main(){

int n[] = { 1, 2, 3, 44, 6, 7 };
printf("Number of elements: %d \n", sizeof(n) / sizeof(int));
return 0;

}}

RichardGeerify
quelle
2
Willkommen bei StackOverflow und vielen Dank, dass Sie eine Antwort geschrieben haben. Leider geht dies nicht auf die Frage ein, bei der es speziell um den Unterschied zwischen sizeof(n)einer lokalen Variablen und sizeof(arg)einem Argument für eine Funktion geht, obwohl beide scheinbar vom Typ sind int[10].
MicroVirus
-3

Arrays sind nur lose dimensioniert. Ein Array ist größtenteils ein Zeiger auf den Speicher. Die Größe in Ihrer Deklaration gibt dem Compiler nur an, wie viel Speicher für das Array reserviert werden soll. Sie ist nicht mit dem Typ verknüpft, sodass sizeof () nichts weiter zu tun hat.

Sockel
quelle
3
Entschuldigung, diese Antwort ist irreführend. Weder sind Arrays "lose", noch sind sie "Zeiger auf den Speicher". Arrays haben eine sehr genaue Größe, und die Stellen, an denen ein Array-Name für einen Zeiger auf sein erstes Element steht, werden durch den C-Standard genau festgelegt.
Jens