[Powered by Google Translate] [Pointer]
[Rob Bowden] [Harvard University]
[Ini adalah CS50] [CS50.TV]
>> Mari kita bicara tentang pointer.
Sampai sekarang, kami selalu hanya disebut hal-hal dalam memori eksplisit dengan nama.
Kami telah mengatakan int n = 42, dan kemudian ketika kita ingin menggunakan n variabel,
kita hanya menyebutnya dengan nama yang kita berikan dengan menulis sesuatu seperti n * 2.
Tapi variabel yang harus tinggal di suatu tempat di memori.
Bila Anda ingin menggunakan nilai yang saat ini disimpan di dalam n,
atau memperbarui nilai bahwa n adalah memegang,
Program Anda harus tahu di mana dalam memori untuk mencari n.
Dimana dalam memori kehidupan variabel disebut alamatnya.
Ini seperti alamat rumah.
Saya bisa menemukan rumah seseorang selama saya tahu alamat rumah mereka,
dan program komputer dapat menemukan variabel asalkan tahu alamat memori.
Apa pointer berikan adalah cara langsung berhubungan dengan alamat memori.
>> Banyak kekuatan di C berasal dari mampu untuk memanipulasi memori seperti ini.
Tapi dengan kekuatan besar datang tanggung jawab besar.
Pointer dapat digunakan berbahaya cukup bahwa banyak bahasa pemrograman
menyembunyikan pointer seluruhnya.
Jadi, mengapa C memberi kita petunjuk kemudian?
Seperti yang Anda ketahui, argumen untuk fungsi C
selalu disalin ke parameter fungsi.
Jadi, memanggil sesuatu seperti swap pada beberapa variabel x dan y
tidak dapat menukar nilai-nilai x dan y dalam pemanggilan fungsi,
meskipun itu mungkin berguna.
Seperti yang akan kita lihat nanti swap, menulis ulang untuk mengambil pointer ke lokasi yang perlu ditukarkan
memungkinkan untuk mempengaruhi variabel pemanggil-nya.
>> Mari kita berjalan melalui contoh yang relatif mudah dari apa pointer dapat dilakukan.
Katakanlah kita memiliki n int = 4, dan int * pointer_to_n = & n.
Whoa! Sedikit sintaks baru untuk menutupi.
Pertama, mari kita menafsirkan ini & n.
Ingatlah bahwa segala sesuatu dalam memori memiliki alamat beberapa.
Ampersand ini disebut "alamat" operator.
Jadi, & n mengacu ke alamat di memori dimana n disimpan.
Sekarang, kita menyimpan alamat ini dalam variabel baru, pointer_to_n.
Apa jenis ini variabel baru?
Tanda bintang adalah bagian dari jenis variabel,
dan kita akan membaca tipe sebagai * int.
* Int berarti bahwa pointer_to_n adalah variabel yang menyimpan alamat integer.
Kita tahu bahwa & n adalah int * sejak n adalah integer, dan kami mengambil alamat dari n.
* Int adalah contoh dari jenis pointer.
Segera setelah Anda mulai melihat tanda bintang dalam jenis,
Anda tahu bahwa Anda sedang berhadapan dengan pointer.
Sama seperti kita dapat mendeklarasikan variabel sebagai int x dan char y,
kita dapat mengatakan int * z dan char * w.
Int * dan char * hanya jenis baru bagi kita untuk menggunakan.
Lokasi * dapat pergi ke mana pun sebelum nama variabel.
Jadi, baik int * pointer_to_n - dengan * sebelah int, seperti yang kita miliki di sini -
dan int * pointer_to_n dengan * sebelah pointer_to_n berlaku.
Tapi di sini, saya akan menempatkan * berikutnya untuk int.
Tidak peduli yang Anda inginkan, hanya konsisten.
>> Mari kita menggambar diagram untuk ini.
Kami pertama memiliki n variabel, yang kita akan menarik sebagai sebuah kotak kecil dari memori.
Untuk contoh ini, mari kita mengatakan bahwa kotak ini terletak di alamat 100.
Di dalam kotak ini, kita menyimpan nilai 4.
Sekarang, kita memiliki variabel baru, pointer_to_n.
Ia memiliki kotak sendiri dalam memori,
yang akan kita katakan adalah di alamat 200.
Di dalam kotak ini, kita menyimpan alamat n,
yang kita sebelumnya mengatakan adalah 100.
Sering dalam diagram, Anda akan melihat ini ditampilkan sebagai panah literal
meninggalkan kotak pointer_to_n menunjuk ke kotak yang menyimpan n.
Sekarang, apa yang bisa kita benar-benar melakukan dengan pointer_to_n?
Nah, jika kita mengatakan sesuatu seperti * pointer_to_n = 8, ini adalah penggunaan yang berbeda untuk asterisk
yang benar-benar terpisah dari penggunaan tanda dalam mendeklarasikan variabel
dari jenis pointer.
Di sini, tanda ini disebut operator dereference.
Dalam diagram kita, apa * pointer_to_n = 8 berarti adalah,
pergi ke pointer_to_n kotak yang berisi, ikuti panah,
dan kemudian menetapkan ke kotak di ujung panah nilai 8.
Ini berarti bahwa setelah baris ini, jika kita mencoba untuk menggunakan n itu akan memiliki nilai 8.
'Pointer' Kata ini digunakan dalam banyak konteks yang berbeda.
Di sini, kita akan mencoba untuk konsisten.
Sebuah jenis pointer adalah sesuatu seperti * int.
Dalam video ini, pointer hanya akan digunakan untuk berarti nilai dengan tipe pointer,
seperti pointer_to_n yang memiliki tipe int *.
Di mana saja kita digunakan untuk hanya mengatakan n, kita sekarang dapat mengatakan sebaliknya pointer_to_n *,
dan semuanya akan bekerja sama dengan baik.
>> Mari kita berjalan melalui contoh lain yang sederhana.
Katakanlah kita memiliki n int = 14; int * pointer = &n; n + +, dan (* pointer) + +.
Baris pertama menciptakan kotak baru dalam memori berlabel n.
Kali ini, kami tidak akan label kotak dengan alamat eksplisit, tetapi masih memiliki satu.
Di dalam kotak, kita menyimpan nomor 14.
Baris berikutnya menciptakan pointer kotak berlabel kedua.
Dan dalam kotak ini, kita menyimpan pointer ke kotak berlabel n.
Jadi, mari kita menarik panah dari pointer ke n.
Sekarang, n + + increment nilai dalam kotak berlabel n,
jadi kami pergi 14-15.
Akhirnya, (* pointer) + + pergi ke pointer kotak berlabel,
dereferences nilai dalam kotak, yang berarti mengikuti panah ke tempat itu menunjukkan,
dan kenaikan nilai yang tersimpan di sana, jadi kami pergi 15-16.
Dan itu saja.
N sekarang menyimpan nomor 16 setelah dua kali telah bertambah -
sekali langsung dengan menggunakan n nama variabel, dan lainnya melalui suatu pointer_to_n.
>> Cepat kuis. Apa yang Anda pikir itu berarti jika saya mencoba untuk mengatakan sesuatu seperti && n?
Nah, mari kita menulis ulang ini sebagai & (& n) yang menyelesaikan hal yang sama.
The (& n) mengembalikan alamat dari n variabel dalam memori.
Tapi kemudian kemudian ampersand luar mencoba untuk mengembalikan alamat dari alamat.
Itu seperti mencoba untuk melakukan & 2.
Ini tidak masuk akal untuk mendapatkan alamat hanya beberapa nomor
karena itu tidak disimpan dalam memori.
Menggunakan dua ampersands berturut-turut tidak pernah ide yang tepat.
Tapi sekarang, apa artinya jika saya mencoba mengatakan int ** double_pointer = & pointer?
Sekarang, saya sedang membuat kotak baru berlabel double_pointer,
dan di dalam kotak bahwa aku menyimpan alamat dari pointer,
yang berarti saya menggambar panah dari kotak ke kotak double_pointer pointer.
Perhatikan jenis double_pointer, suatu ** int.
N adalah integer, pointer menyimpan alamat n, dan sehingga memiliki * tipe int.
Sekarang, double_pointer menyimpan alamat pointer, sehingga memiliki tipe int **.
>> Jadi, apa yang kita pikirkan cara ini -
Double_pointer ** = 23?
Perhatikan bahwa saya sekarang dereferencing dua kali.
Cukup ikuti diagram kotak-dan-panah kita sudah menyiapkan.
Pertama, kita pergi ke kotak berlabel double_pointer.
The * pertama berarti mengikuti panah sekali.
Sekarang, kita berada di pointer kotak berlabel.
Bintang kedua mengatakan mengikuti panah lagi,
dan sekarang kita berada di kotak berlabel n, dan kami menetapkan nilai dari kotak ini untuk 23.
Perhatikan bahwa 'alamat' dereference dan operator invers satu sama lain.
Hal ini memungkinkan saya untuk melakukan sesuatu seperti * & * & n = 42.
Sementara ini bekerja, Anda tidak harus melakukan sesuatu seperti ini dalam praktek.
Apa yang kita benar-benar lakukan di sini?
Ampersand pertama meraih alamat dari n variabel.
Kemudian, kita memiliki operator dereference, yang berarti kita akan ke alamat tersebut di memori,
jadi kita kembali pada n.
Sekarang, kita ambil alamat n lagi dan segera dereference,
jadi kita kembali pada n dan toko 42.
Jadi, setiap pasangan * & hanya membatalkan.
>> Ada sebuah pointer khusus yang disebut null pointer.
Ini adalah pointer yang kita tidak pernah harus dereference.
Seperti pointer penting karena memberi kita cara untuk membedakan antara
pointer yang harus dan tidak boleh dereferenced.
Jika Anda mencoba untuk dereference pointer nol,
biasanya program anda akan crash dengan kesalahan segmentasi,
yang Anda mungkin telah melihat sebelumnya.
Jadi, katakanlah kita memiliki kode int * x = null; * x = 4.
Dalam contoh ini, mungkin tampak jelas bahwa kita sedang melakukan sesuatu yang buruk,
tapi ingat bahwa nol benar-benar bisa menjadi nilai kembali dari panggilan ke fungsi
seperti malloc, jika malloc tidak dapat mengalokasikan memori yang diminta oleh pengguna.
Untuk alasan ini, jika sebaliknya kita menetapkan nilai x dari panggilan untuk malloc,
seperti dalam int * x = malloc (sizeof (int)), maka kita harus selalu memeriksa eksplisit
untuk melihat apakah null dikembalikan.
Jika (x == null); / / uhoh! return; lain kita dapat melanjutkan dan mengatakan * x = 4.
>> Jadi, sekali lagi, mengapa harus kita pernah menggunakan pointer?
Mari kita lihat contoh program di mana kita perlu menggunakan pointer -
fungsi sederhana swap.
Katakanlah saya memiliki dua bilangan bulat, int x = 4, dan int y = 15;
dan saya ingin menulis sebuah fungsi yang disebut swap yang dapat saya gunakan seperti: swap (x, y).
Setelah baris ini, nilai-nilai dalam variabel x harus 15,
dan nilai dalam variabel y harus 4.
Nilai-nilai dalam x dan y telah bertukar.
Tanpa pointer, kita mungkin mencoba sesuatu seperti swap void (int a, int b);
int tmp = b, b = a; a = tmp.
Tapi, apakah Anda melihat masalah dengan ini?
Ingat bahwa nilai yang disimpan dalam variabel hanyalah sebuah salinan dari nilai x,
dan nilai dalam b disalin dari y.
Setiap perubahan yang dibuat untuk a dan b tidak akan tercermin dalam x dan y.
Jadi, sementara nilai-nilai a dan b dengan benar bertukar,
x dan y tidak berubah sama sekali.
Sekarang, mari kita mengubah fungsi swap sehingga argumen nya
adalah pointer ke variabel itu harus swap, seperti:
Swap void (int * a, int * b); int tmp = * b; * b = * a; * a = tmp.
Ingat bahwa swap argumen sekarang pointer,
dan jadi kita perlu melewati alamat x dan y dalam panggilan untuk swap, seperti:
swap (& x, & y).
Ini sekarang benar swap nilai-nilai x dan y.
>> Mari kita menggambar diagram kotak-dan-panah untuk melihat mengapa ini bekerja.
Kita mulai dengan dua kotak dalam memori, x dan y.
Di dalam kotak untuk x adalah nomor 4, dan dalam kotak untuk y kita memiliki 15.
Sekarang, dalam panggilan ke fungsi swap, kita memiliki dua kotak lagi
untuk argumen a dan b;
poin ke kotak untuk x, dan poin b ke kotak untuk y.
Sebuah kotak baru dibuat untuk tmp variabel,
dan di dalamnya kita menyimpan hasil dereferencing b,
yang berarti 'mengikuti panah dari kotak berlabel b.'
Jadi, kita menyimpan 15 dalam tmp.
Kemudian, kita mengikuti panah di b dan menyimpan di sini hasil dari suatu dereferencing,
yang merupakan nilai 4.
Akhirnya, kita mengikuti panah di toko dan apa yang saat ini dalam tmp, yaitu 15.
Perhatikan bahwa kotak berlabel x dan y telah benar bertukar nilai-nilai.
>> Setelah kita mempelajari lebih lanjut tentang malloc dan manajemen memori dinamis,
kita akan melihat bahwa kita tidak punya pilihan selain menggunakan pointer.
Berjalan melalui diagram kotak-dan-panah untuk program apapun
dapat membantu Anda mengetahui program apa yang benar-benar melakukan.
>> Nama saya Rob Bowden, dan ini adalah CS50.
[CS50.TV]
>> Ini adalah penggunaan yang berbeda untuk tanda bintang - bleah, aku benci kata itu.
Di mana saja kita digunakan untuk hanya mengatakan n, kita sekarang dapat mengatakan pointer_to_n - tidak Anda tak bisa - pointer_to_n *.