Saya telah menemukan fungsi yang menghitung kuadrat angka:
int p(int n) {
int a[n]; //works on C99 and above
return (&a)[n] - a;
}
Ini mengembalikan nilai n 2 . Pertanyaannya adalah, bagaimana cara melakukannya? Setelah sedikit pengujian, saya menemukan bahwa antara (&a)[k]
dan (&a)[k+1]
is sizeof(a)
/ sizeof(int)
. Mengapa demikian?
int p(n)
? Apakah itu bisa dikompilasi?int q(int n) { return sizeof (char [n][n]); }
sizeof
adalah untuk menyimpan karakter. Semua orang: kode ini sengaja dikaburkan, perilaku tidak terdefinisi, jawaban @ ouah benar.Jawaban:
Jelas hack ... tapi cara mengkuadratkan angka tanpa menggunakan
*
operator (ini adalah persyaratan kontes pengkodean).setara dengan penunjuk ke
int
di lokasi(a + sizeof(a[n])*n)
dan dengan demikian keseluruhan ekspresi itu
(&a)[n] -a = (a + sizeof(a[n])*n -a) /sizeof(int) = sizeof(a[n])*n / sizeof(int) = sizeof(int) * n * n / sizeof(int) = n * n
sumber
(&a)
sebagai penunjuk ke suatu objekn*sizeof(int)
ketikan
tidak diketahui pada waktu kompilasi. C dulunya bahasa yang sederhana ...Untuk memahami peretasan ini, pertama-tama Anda perlu memahami perbedaan penunjuk, yaitu, apa yang terjadi jika dua penunjuk yang menunjuk ke elemen larik yang sama dikurangi?
Ketika satu pointer dikurangkan dari pointer lainnya, hasilnya adalah jarak (diukur dalam elemen array) antara pointer. Jadi, jika
p
menunjuk kea[i]
danq
menunjuk kea[j]
, makap - q
sama dengani - j
.C11: 6.5.6 Operator aditif (p9):
Sekarang saya mengharapkan bahwa Anda mengetahui konversi nama array ke pointer,
a
mengubahnya menjadi pointer ke elemen pertama dari arraya
.&a
adalah alamat seluruh blok memori, yaitu alamat arraya
. Gambar di bawah ini akan membantu Anda untuk memahami ( baca jawaban ini untuk penjelasan rinci ):Ini akan membantu Anda untuk memahami mengapa
a
dan&a
memiliki alamat yang sama dan bagaimana(&a)[i]
alamat dari array ke- i (dengan ukuran yang sama dengana
).Jadi, pernyataannya
return (&a)[n] - a;
setara dengan
return (&a)[n] - (&a)[0];
dan perbedaan ini akan memberikan jumlah elemen antara pointer
(&a)[n]
dan(&a)[0]
, yang merupakann
array setiapn
int
elemen. Oleh karena itu, total elemen array adalahn*n
=n
2 .CATATAN:
C11: 6.5.6 Operator aditif (p9):
Karena
(&a)[n]
tidak menunjuk ke elemen dari objek array yang sama atau melewati elemen terakhir dari objek array, tidak(&a)[n] - a
akan memunculkan perilaku tidak terdefinisi .Perhatikan juga bahwa, lebih baik untuk mengubah jenis fungsi yang dikembalikan
p
menjadiptrdiff_t
.sumber
&a[k]
adalah alamatk
elemen arraya
. Itu(&a)[k]
akan selalu dianggap sebagai alamat dari sebuah arrayk
elemen. Jadi, elemen pertama adalah pada posisia
(atau&a
), kedua adalah pada posisia
+ (jumlah elemen arraya
yangn
) * (ukuran elemen array) dan sebagainya. Dan perhatikan bahwa, memori untuk array panjang variabel dialokasikan di stack, bukan di heap.a
adalah larik (variabel) darin
int
.&a
adalah penunjuk ke larik (variabel) darin
int
.(&a)[1]
adalah penunjukint
salah satuint
elemen larik terakhir. Pointer ini adalahn
int
elemen setelahnya&a[0]
.(&a)[2]
adalah penunjukint
salah satuint
elemen array terakhir dari dua array. Pointer ini adalah2 * n
int
elemen setelahnya&a[0]
.(&a)[n]
adalah penunjukint
salah satuint
elemen array terakhir darin
array. Pointer ini adalahn * n
int
elemen setelahnya&a[0]
. Kurangi saja&a[0]
ataua
dan Anda sudah memilikinyan
.Tentu saja ini secara teknis adalah perilaku yang tidak terdefinisi bahkan jika berfungsi pada mesin Anda karena
(&a)[n]
tidak menunjuk ke dalam larik atau melewati elemen larik terakhir (seperti yang disyaratkan oleh aturan C aritmatika penunjuk).sumber
[n]
sintaksis menyatakan array dan array terurai menjadi pointer. Tiga hal yang berguna secara terpisah dengan konsekuensi ini.(&a)[n]
ini adalah tipeint[n]
, dan itu mengungkapkanint*
karena array yang diekspresikan sebagai alamat elemen pertama mereka, jika itu tidak jelas dalam deskripsi.Jika Anda memiliki dua pointer yang mengarah ke dua elemen dari array yang sama maka perbedaannya akan menghasilkan jumlah elemen di antara pointer ini. Misalnya cuplikan kode ini akan menghasilkan 2.
int a[10]; int *p1 = &a[1]; int *p2 = &a[3]; printf( "%d\n", p2 - p1 );
Sekarang mari pertimbangkan ekspresi
Dalam ekspresi ini
a
memiliki tipeint *
dan menunjuk ke elemen pertamanya.Ekspresi
&a
memiliki tipeint ( * )[n]
dan poin ke baris pertama dari larik dua dimensi yang dicitrakan. Nilainya sesuai dengan nilaia
meskipun jenisnya berbeda.adalah elemen ke-n dari larik dua dimensi yang dicitrakan dan memiliki tipe.
int[n]
Itu adalah baris ke-n dari larik yang dicitrakan. Dalam ekspresi(&a)[n] - a
itu dikonversi ke alamat elemen pertama dan memiliki tipe `int *.Jadi di antara
(&a)[n]
dana
ada n baris n elemen. Jadi perbedaannya akan saman * n
.sumber
Expression | Value | Explanation a | a | point to array of int elements a[n] | a + n*sizeof(int) | refer to n-th element in array of int elements ------------------------------------------------------------------------------------------------- &a | a | point to array of (n int elements array) (&a)[n] | a + n*sizeof(int[n]) | refer to n-th element in array of (n int elements array) ------------------------------------------------------------------------------------------------- sizeof(int[n]) | n * sizeof(int) | int[n] is a type of n-int-element array
Jadi,
(&a)[n]
adalahint[n]
penunjuka
adalahint
penunjukSekarang ekspresi
(&a)[n]-a
melakukan substraksi penunjuk:(&a)[n]-a = ((a + n*sizeof(int[n])) - a) / sizeof(int) = (n * sizeof(int[n])) / sizeof(int) = (n * n * sizeof(int)) / sizeof(int) = n * n
sumber