Dalam sedikit kode berikut, nilai penunjuk dan alamat penunjuk berbeda seperti yang diharapkan.
Tetapi nilai array dan alamat tidak!
Bagaimana ini bisa terjadi?
Keluaran
my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>
int main()
{
char my_array[100] = "some cool string";
printf("my_array = %p\n", my_array);
printf("&my_array = %p\n", &my_array);
char *pointer_to_array = my_array;
printf("pointer_to_array = %p\n", pointer_to_array);
printf("&pointer_to_array = %p\n", &pointer_to_array);
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
sizeof(&array)
kembali?Jawaban:
Nama array biasanya mengevaluasi ke alamat dari elemen pertama dari array, sehingga
array
dan&array
memiliki nilai yang sama (tapi jenis yang berbeda, sehinggaarray+1
dan&array+1
akan tidak sama jika array lebih dari 1 elemen panjang).Ada dua pengecualian untuk ini: ketika nama array adalah operan
sizeof
atau unary&
(address-of), namanya merujuk ke objek array itu sendiri. Dengan demikiansizeof array
memberi Anda ukuran dalam byte dari seluruh array, bukan ukuran pointer.Untuk array yang didefinisikan sebagai
T array[size]
, ia akan memiliki tipeT *
. Ketika / jika Anda menambahkannya, Anda mendapatkan elemen berikutnya dalam array.&array
mengevaluasi ke alamat yang sama, tetapi diberi definisi yang sama, itu menciptakan pointer dari tipeT(*)[size]
- yaitu, itu adalah pointer ke array, bukan ke elemen tunggal. Jika Anda menambah pointer ini, itu akan menambah ukuran seluruh array, bukan ukuran elemen tunggal. Misalnya, dengan kode seperti ini:Kita dapat mengharapkan pointer kedua menjadi 16 lebih besar dari yang pertama (karena ini adalah array dari 16 karakter). Karena% p biasanya mengonversi pointer dalam heksadesimal, itu mungkin terlihat seperti:
sumber
&array
adalah penunjuk ke elemen pertama array, di manaarray
mengacu pada seluruh array. Perbedaan mendasar juga dapat diamati dengan membandingkansizeof(array)
, dengansizeof(&array)
. Namun perhatikan bahwa jika Anda meneruskanarray
sebagai argumen ke suatu fungsi, hanya&array
faktanya yang berlalu. Anda tidak dapat melewatkan array dengan nilai kecuali jika dienkapsulasi dengan astruct
.&array[0]
dilewatkan, bukan&array
yang akan menjadi pointer ke array. Ini mungkin nit-pick tapi saya pikir penting untuk menjelaskannya; kompiler akan memperingatkan jika fungsi memiliki prototipe yang cocok dengan jenis pointer yang disahkan.int *p = array; int **pp = &p;
.Itu karena nama array (
my_array
) berbeda dari satu pointer ke array. Ini adalah alias ke alamat array, dan alamatnya didefinisikan sebagai alamat array itu sendiri.Pointer adalah variabel C normal pada stack. Dengan demikian, Anda dapat mengambil alamatnya dan mendapatkan nilai berbeda dari alamat yang dimilikinya di dalamnya.
Saya menulis tentang topik ini di sini - silakan lihat.
sumber
register
) berapapun durasi penyimpanannya: statis, dinamis atau otomatis.my_array
sendiri adalah pada stack, karenamy_array
merupakan seluruh array.my_array
, ketika bukan subjek operator&
atausizeof
, dievaluasi ke pointer ke elemen pertama (mis.&my_array[0]
) - tetapimy_array
itu sendiri bukan pointer itu (my_array
masih array). Pointer itu hanya nilai sementara (mis. Diberikanint a;
, itu sepertia + 1
) - setidaknya secara konseptual "dihitung sesuai kebutuhan". "Nilai" sebenarnyamy_array
adalah isi seluruh array - hanya saja dengan menjabarkan nilai ini dalam C sama seperti mencoba menangkap kabut dalam toples.Dalam C, ketika Anda menggunakan nama array dalam ekspresi (termasuk meneruskannya ke fungsi), kecuali itu adalah operan dari
&
operator address-of ( ) atausizeof
operator, ia meluruh ke pointer ke elemen pertama.Artinya, dalam sebagian besar konteks
array
sama dengan&array[0]
di kedua jenis dan nilai.Dalam contoh Anda,
my_array
memiliki tipechar[100]
yang meluruh kechar*
ketika Anda meneruskannya ke printf.&my_array
memiliki tipechar (*)[100]
(pointer ke array 100char
). Karena ini adalah operan untuk&
, ini adalah salah satu kasus yangmy_array
tidak segera membusuk ke pointer ke elemen pertama.Pointer ke array memiliki nilai alamat yang sama dengan pointer ke elemen pertama array sebagai objek array hanya urutan yang berdekatan dari elemen-elemennya, tetapi pointer ke array memiliki tipe yang berbeda dengan pointer ke elemen array itu. Ini penting ketika Anda melakukan pointer aritmatika pada dua jenis pointer.
pointer_to_array
memiliki tipechar *
- diinisialisasi untuk menunjuk pada elemen pertama array karena itulah yangmy_array
meluruh dalam ekspresi initializer - dan&pointer_to_array
memiliki tipechar **
(pointer ke pointer ke achar
).Dari jumlah ini:
my_array
(setelah pembusukan kechar*
),&my_array
danpointer_to_array
semua menunjuk langsung pada array atau elemen pertama array dan memiliki nilai alamat yang sama.sumber
Alasan mengapa
my_array
dan&my_array
menghasilkan alamat yang sama dapat dengan mudah dipahami ketika Anda melihat tata letak memori suatu array.Katakanlah Anda memiliki array 10 karakter (bukan 100 dalam kode Anda).
Memori untuk
my_array
terlihat seperti:Di C / C ++, array meluruh ke pointer ke elemen pertama dalam ekspresi seperti
Jika Anda memeriksa di mana elemen pertama array terletak Anda akan melihat bahwa alamatnya sama dengan alamat array:
sumber
Dalam bahasa pemrograman B, yang merupakan pendahulu langsung ke C, pointer dan integer bebas dipertukarkan. Sistem akan berperilaku seolah-olah semua memori adalah array raksasa. Setiap nama variabel memiliki alamat global atau stack-relatif yang terkait dengannya, untuk setiap nama variabel satu-satunya hal yang harus dilacak oleh kompiler adalah apakah itu variabel global atau lokal, dan alamatnya relatif terhadap global atau lokal pertama variabel.
Mengingat deklarasi global seperti
i;
[tidak perlu untuk menentukan jenis, karena semuanya adalah integer / pointer] akan diproses oleh compiler sebagai:address_of_i = next_global++; memory[address_of_i] = 0;
dan pernyataan sepertii++
akan diproses sebagai:memory[address_of_i] = memory[address_of_i]+1;
.Pernyataan seperti
arr[10];
akan diproses sebagaiaddress_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
. Perhatikan bahwa segera setelah deklarasi itu diproses, kompilator dapat langsung lupa tentangarr
menjadi sebuah array . Pernyataan sepertiarr[i]=6;
akan diproses sebagaimemory[memory[address_of_a] + memory[address_of_i]] = 6;
. Kompilator tidak akan peduli apakaharr
mewakili array dani
integer, atau sebaliknya. Memang, tidak akan peduli apakah keduanya array atau keduanya integer; itu akan dengan senang hati menghasilkan kode seperti yang dijelaskan, tanpa memperhatikan apakah perilaku yang dihasilkan kemungkinan akan berguna.Salah satu tujuan dari bahasa pemrograman C adalah untuk sebagian besar kompatibel dengan B. Dalam B, nama array [disebut "vektor" dalam terminologi B] mengidentifikasi variabel yang memegang pointer yang awalnya ditugaskan untuk menunjuk ke ke elemen pertama dari alokasi ukuran yang diberikan, jadi jika nama itu muncul dalam daftar argumen untuk suatu fungsi, fungsi tersebut akan menerima pointer ke vektor. Meskipun C menambahkan tipe array "nyata", yang namanya secara kaku dikaitkan dengan alamat alokasi alih-alih variabel pointer yang awalnya akan menunjuk ke alokasi, memiliki array yang terurai menjadi pointer membuat kode yang menyatakan array tipe-C berperilaku identik. ke kode B yang menyatakan vektor dan kemudian tidak pernah memodifikasi variabel yang menyimpan alamatnya.
sumber
Sebenarnya
&myarray
danmyarray
keduanya adalah alamat dasar.Jika Anda ingin melihat perbedaannya daripada menggunakan
menggunakan
sumber