Mengapa ukuran parameter array tidak sama dengan main?

104

Mengapa ukuran array yang dikirim sebagai parameter tidak sama dengan 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));
}
Chris_45
sumber

Jawaban:

103

Sebuah tipe array secara implisit diubah menjadi tipe pointer ketika Anda meneruskannya ke sebuah fungsi.

Begitu,

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

dan

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

setara. Jadi apa yang Anda dapatkan adalah nilaisizeof(int*)

Prasoon Saurav
sumber
1
Dalam C ++ Anda dapat meneruskan array dengan mengacu pada fungsi tetapi Anda tidak dapat melakukannya di C.
Prasoon Saurav
13
Anda harus meneruskan ukuran array sebagai parameter terpisah. Maka ukuran array akan menjadi sizeof (* p_someArray) * length
Aric TenEyck
13
Minor nit: sizeofoperator mengembalikan objek jenis size_t, jadi Anda harus mencetaknya dengan %zu(C99), atau mentransmisikannya ke intjika Anda menggunakan %dseperti di atas dalam printfpanggilan Anda .
Alok Singhal
4
Pernyataan Alok benar. Menggunakan penentu format yang salah di printf (..) adalah UB.
Prasoon Saurav
1
@ Chris_45: C tidak memiliki referensi, tapi di C Anda dapat melewatkan sebuah array dengan pointer ke seluruh array seperti di: void PrintSize(int (*p_someArray)[10]). Dalam fungsi Anda dapat mengakses array dengan menggunakan dereference operator *: sizeof(*p_someArray). Ini akan memiliki efek yang sama seperti menggunakan referensi di C ++.
AnT
18

Ini adalah pointer, itulah mengapa implementasi umum untuk meneruskan ukuran array sebagai parameter kedua ke fungsi

pengguna240312
sumber
16

Seperti yang dinyatakan orang lain, array meluruh menjadi pointer ke elemen pertamanya saat digunakan sebagai parameter fungsi. Perlu juga dicatat bahwa sizeof tidak mengevaluasi ekspresi dan tidak memerlukan tanda kurung saat digunakan dengan ekspresi, jadi parameter Anda tidak benar-benar digunakan sama sekali, jadi Anda sebaiknya menulis sizeof dengan tipe daripada nilainya.

#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
sumber
12

Jadi, Anda harus meneruskan lenght array sebagai parameter kedua. Saat Anda menulis kode, di mana Anda berdua mendeklarasikan sebuah array dengan ukuran konstan, dan kemudian meneruskan array itu ke sebuah fungsi, sangat merepotkan jika konstanta panjang array muncul di beberapa tempat dalam kode Anda ...

K&R untuk menyelamatkan:

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

Jadi sekarang Anda bisa melakukannya misalnya:

int a[10];
...
myfunction(a, N_ELEMENTS(a));
SC Madsen
sumber
bagaimana jika ukuran array tidak tersedia pada waktu pengkodean, tetapi hanya tersedia pada waktu proses? Apakah ada cara lain untuk menghitung ukuran array tanpa hard-coding ukurannya?
weefwefwqg3
Metode yang ditampilkan hanya berfungsi, jika deklarasi array "dalam tampilan". Untuk semua kasus lainnya, Anda harus meneruskan panjang array secara manual.
SC Madsen
5

Karena array meluruh menjadi pointer ketika dilewatkan sebagai parameter. Ini adalah cara kerja C, meskipun Anda bisa meneruskan "array" di C ++ dengan referensi dan mengatasi masalah ini. Perhatikan bahwa Anda dapat meneruskan array dengan ukuran berbeda ke fungsi ini:

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

Perilaku yang Anda temukan sebenarnya adalah kutil besar dalam bahasa C. Setiap kali Anda mendeklarasikan fungsi yang mengambil parameter array, compiler mengabaikan Anda dan mengubah parameter menjadi pointer. Jadi semua deklarasi ini berperilaku seperti yang pertama:

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

a akan menjadi penunjuk ke int dalam keempat kasus. Jika Anda meneruskan sebuah array ke func, array itu akan segera meluruh menjadi pointer ke elemen pertamanya. (Pada sistem 64-bit, penunjuk 64-bit dua kali lebih besar dari int 32-bit, sehingga rasio sizeof Anda kembali 2.)

Satu-satunya tujuan aturan ini adalah untuk mempertahankan kompatibilitas mundur dengan kompiler historis yang tidak mendukung penerusan nilai agregat sebagai argumen fungsi.

Ini tidak berarti bahwa tidak mungkin meneruskan array ke suatu fungsi. Anda dapat menyiasati kutil ini dengan menyematkan array ke dalam struct (ini pada dasarnya adalah tujuan dari std :: array 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 */
}

atau dengan meneruskan pointer ke array:

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

Jika ukuran array bukan konstanta waktu kompilasi, Anda dapat menggunakan teknik pointer-ke-array dengan array panjang variabel C99:

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

Di c ++ Anda bisa melewatkan array dengan referensi untuk tujuan ini:

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}
Alexandre C.
sumber
1
Bagaimana ini membantu dengan pertanyaan C?
alk
3

Dalam bahasa C, tidak ada metode untuk menentukan ukuran array yang tidak diketahui, jadi kuantitas perlu diteruskan serta penunjuk ke elemen pertama.


sumber
2
Secara umum, Anda harus selalu meneruskan ukuran (jumlah elemen) dari sebuah array bersama dengan sebuah array ke suatu fungsi, kecuali jika Anda memiliki cara lain untuk menentukan ukurannya (misalnya, terminator karakter null di akhir char[]array string).
David R Tribble
Tolong apa itu " array yang tidak diketahui "?
alk
3

Anda tidak bisa meneruskan array ke fungsi.

Jika Anda benar-benar ingin mencetak ukurannya, Anda dapat meneruskan pointer ke array, tetapi itu tidak akan umum sama sekali karena Anda juga perlu menentukan ukuran array untuk fungsi tersebut.

#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));
}
BAPAK.
sumber
0

Perilaku itu memang sengaja.

Sintaks yang sama dalam deklarasi parameter fungsi berarti hal yang sama sekali berbeda dari pada definisi variabel lokal.

Alasannya dijelaskan dalam jawaban lain.

Pavel Radzivilovsky
sumber
0

Dalam bahasa C ketika Anda melewatkan array sebagai argumen ke fungsi, itu secara otomatis diubah menjadi pointer, array yang lewat dari satu fungsi fungsi lain dikenal sebagai panggilan dengan referensi. Itulah alasan mengapa fungsi yang dipanggil hanya menerima penunjuk yang menunjuk ke elemen pertama dari fungsi Ini adalah alasannya

kesenangan (int a []) mirip dengan kesenangan (int * a);

jadi ketika Anda mencetak ukuran array itu akan mencetak ukuran elemen pertama.

dagrawal
sumber
Di C tidak ada " panggilan dengan referensi ".
alk
" ketika Anda mencetak ukuran array itu akan mencetak ukuran elemen pertama. " tidak, itu mencetak ukuran sebuah pointer.
alk
-1

Dalam 'C' bahasa pemrograman 'sizeof ()' adalah operator dan dia mengembalikan ukuran objek dalam byte.Arumen operator 'sizeof ()' harus berupa tipe nilai kiri (integer, angka float, struct, array Jadi jika Anda ingin mengetahui ukuran sebuah array dalam byte Anda dapat melakukannya dengan sangat sederhana, cukup gunakan operator 'sizeof ()' dan untuk argumennya gunakan nama array, misalnya:

#include <stdio.h>

main(){

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

}

Output pada sistem 32 bit akan menjadi: Size dari n adalah: 40. Karena ineteger pada sistem 32 adalah 4bytes. Pada 64x adalah 8bytes. Dalam hal ini kita memiliki 10 integer yang dideklarasikan dalam satu array, jadi hasilnya adalah '10 * sizeof ( int) '.

Beberapa tips:

Jika kita memiliki sebuah array yang dideklarasikan seperti ini 'int n [] = {1, 2, 3, ... 155 ..};'. Jadi kami ingin tahu berapa banyak elemen yang disimpan dalam array ini. Gunakan alghoritma ini:

sizeof (name_of_the_array) / sizeof (array_type)

Kode: #include

utama(){

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

}

RichardGeerify
sumber
2
Selamat datang di StackOverflow dan terima kasih telah menulis jawabannya. Sayangnya, ini tidak menjawab pertanyaan, yang secara khusus adalah tentang perbedaan antara sizeof(n)variabel lokal dan sizeof(arg)argumen untuk suatu fungsi, meskipun keduanya tampaknya bertipe int[10].
MicroVirus
-3

Array hanya berukuran longgar. Untuk sebagian besar, array adalah penunjuk ke memori. Ukuran dalam deklarasi Anda hanya memberi tahu kompiler berapa banyak memori yang harus dialokasikan untuk array - ini tidak terkait dengan tipe, jadi sizeof () tidak perlu dilanjutkan.

alas tiang
sumber
3
Maaf, jawaban ini menyesatkan. Array juga tidak "berukuran longgar", juga bukan "penunjuk ke memori". Array memiliki ukuran yang sangat tepat, dan tempat di mana nama array merupakan penunjuk ke elemen pertamanya secara tepat ditentukan oleh standar C.
Jens