[Powered by Google Translate] [Bagian 6] [Lebih Nyaman] [Rob Bowden] [Harvard University] [Ini adalah CS50.] [CS50.TV] Kita dapat menuju ke bagian kami dari pertanyaan. Aku mengirim URL untuk ruang sebelumnya. Awal bagian dari pertanyaan mengatakan- ternyata aku tidak sepenuhnya unsick-adalah pertanyaan yang sangat mudah hanya apa yang Valgrind? Apa Valgrind lakukan? Siapapun ingin mengatakan apa Valgrind tidak? [Mahasiswa] Cek kebocoran memori. Ya, Valgrind adalah checker memori umum. Ini, pada akhirnya, memberitahu Anda jika Anda memiliki kebocoran memori, yang sebagian besar apa yang kita menggunakannya untuk karena jika Anda ingin melakukannya dengan baik pada set masalah atau jika Anda ingin mendapatkan di papan besar, Anda perlu tidak memiliki kebocoran memori apapun, dan jika Anda memiliki kebocoran memori yang Anda tidak dapat menemukan, juga perlu diingat bahwa setiap kali Anda membuka file dan jika Anda tidak menutupnya, itu adalah kebocoran memori. Banyak orang mencari simpul beberapa bahwa mereka tidak membebaskan ketika benar-benar, mereka tidak menutup kamus pada langkah pertama. Ia juga memberitahu Anda jika Anda memiliki valid membaca atau menulis, yang berarti jika Anda mencoba dan menetapkan nilai itu di luar akhir tumpukan, dan itu tidak terjadi kesalahan seg tapi Valgrind menangkap itu, karena Anda tidak harus benar-benar bisa menulis di sana, dan sehingga Anda pasti tidak harus memiliki salah satu dari mereka baik. Bagaimana Anda menggunakan Valgrind? Bagaimana Anda menggunakan Valgrind? Ini adalah pertanyaan umum dari jenis menjalankannya dan melihat output. Output melanda banyak kali. Ada juga kesalahan menyenangkan di mana jika Anda memiliki beberapa hal yang sangat salah terjadi dalam satu lingkaran, maka pada akhirnya akan mengatakan, "Terlalu banyak kesalahan. Aku akan berhenti menghitung sekarang. " Ini pada dasarnya output tekstual bahwa Anda harus mengurai. Pada akhirnya, ia akan memberitahu Anda kebocoran memori apapun yang Anda miliki, berapa banyak blok, yang dapat berguna karena jika satu unfreed blok, maka biasanya lebih mudah untuk menemukan dari 1.000 blok unfreed. 1.000 blok unfreed mungkin berarti Anda tidak membebaskan Anda terkait daftar tepat atau sesuatu. Itu Valgrind. Sekarang kita memiliki bagian kita pertanyaan, yang Anda tidak perlu men-download. Anda dapat klik pada nama saya dan menarik mereka di ruang. Sekarang klik pada saya. Revisi 1 akan menjadi tumpukan, yang kita lakukan pertama kali. Revisi 2 akan antrian, dan Revisi 3 akan menjadi linked list sendiri-sendiri. Mulai off dengan tumpukan kami. Seperti dikatakan di sini, tumpukan adalah salah satu dari yang paling dasar, dasar struktur data dari ilmu komputer. Contoh prototipikal adalah sangat tumpukan nampan di ruang makan. Pada dasarnya setiap kali Anda sedang diperkenalkan ke stack, seseorang akan berkata, "Oh, seperti tumpukan nampan." Anda tumpukan nampan up. Kemudian ketika Anda pergi untuk menarik nampan, baki pertama yang mendapatkan ditarik adalah yang terakhir yang dimasukkan pada stack. Tumpukan juga-seperti yang dikatakan di sini- kita memiliki segmen memori yang disebut stack. Dan mengapa disebut stack? Karena seperti struktur tumpukan data, itu mendorong dan muncul frame stack di stack, di mana frame tumpukan seperti panggilan khusus dari suatu fungsi. Dan seperti stack, Anda akan selalu harus kembali dari panggilan fungsi sebelum Anda bisa mendapatkan ke dalam stack frame yang lebih rendah lagi. Anda tidak dapat memiliki panggilan foo bar panggilan utama dan kembali bar untuk langsung main. Itu selalu harus mengikuti tumpukan yang benar mendorong dan muncul. Dua operasi, seperti saya katakan, adalah push dan pop. Mereka adalah istilah universal. Anda harus tahu push dan pop dalam hal tumpukan tidak peduli apa. Kita akan melihat antrian yang agak berbeda. Ini tidak benar-benar memiliki istilah universal, tapi push dan pop yang universal untuk tumpukan. Push hanya menempatkan pada stack. Pop adalah mengambil dari tumpukan. Dan kita lihat di sini kita memiliki tumpukan struct typedef kami, sehingga kita memiliki string char **. Jangan takut oleh **. Ini akan berakhir menjadi sebuah array string atau sebuah array dari pointer ke karakter, di mana pointer ke karakter cenderung string. Tidak harus string, tapi di sini, mereka akan menjadi string. Kami memiliki sebuah array dari string. Kami memiliki ukuran, yang mewakili berapa banyak elemen saat ini di stack, dan kemudian kita memiliki kapasitas, yang adalah berapa banyak elemen dapat berada di stack. Kapasitas harus memulai sebagai sesuatu yang lebih besar dari 1, tetapi ukuran akan memulai sebagai 0. Sekarang, pada dasarnya ada tiga cara yang berbeda yang dapat Anda pikirkan stack. Nah, ada mungkin lebih, tetapi dua cara utama adalah Anda dapat menerapkannya menggunakan array, atau Anda dapat menerapkannya menggunakan linked list. Daftar link adalah jenis sepele untuk membuat tumpukan dari. Hal ini sangat mudah untuk membuat tumpukan menggunakan linked list, jadi di sini, kita akan membuat stack menggunakan array, dan kemudian menggunakan array, ada juga dua cara Anda dapat berpikir tentang hal itu. Sebelumnya, ketika saya mengatakan kami memiliki kapasitas untuk stack, sehingga kami dapat muat elemen pada stack. Salah satu cara itu bisa terjadi adalah segera setelah Anda mencapai 10 elemen, maka Anda sudah selesai. Anda mungkin tahu bahwa ada batas atas dari 10 hal di dunia bahwa Anda tidak akan pernah memiliki lebih dari 10 hal pada stack Anda, dalam hal ini Anda dapat memiliki batas atas ukuran tumpukan Anda. Atau Anda bisa memiliki tumpukan Anda harus tak terbatas, tetapi jika Anda melakukan sebuah array, yang berarti bahwa setiap kali Anda mencapai 10 elemen, maka Anda akan harus tumbuh menjadi 20 elemen, dan ketika anda menekan 20 elemen, Anda akan harus tumbuh array Anda untuk 30 unsur atau elemen 40. Anda akan perlu untuk meningkatkan kapasitas, yang adalah apa yang akan kita lakukan di sini. Setiap kali kita mencapai ukuran maksimum tumpukan kami, ketika kita mendorong sesuatu yang lain, kami akan perlu untuk meningkatkan kapasitas. Di sini, kami telah mendorong dinyatakan sebagai dorongan bool (char * str). Str * Char adalah string yang kita mendorong ke stack, dan bool hanya mengatakan apakah kita berhasil atau gagal. Bagaimana bisa kita gagal? Apa keadaan-satunya yang dapat Anda pikirkan di mana kita akan perlu kembali palsu? Ya. [Mahasiswa] Jika itu penuh dan kita sedang menggunakan implementasi dibatasi. Ya, jadi bagaimana kita mendefinisikan-ia menjawab jika itu penuh dan kita sedang menggunakan implementasi dibatasi. Kemudian kita pasti akan kembali palsu. Segera setelah kami mencapai 10 hal dalam array, kita tidak bisa muat 11, jadi kami kembali salah. Bagaimana jika itu tak terbatas? Ya. Jika Anda tidak dapat memperluas array untuk beberapa alasan. Ya, jadi memori adalah sumber daya yang terbatas, dan akhirnya, jika kita menjaga hal-hal mendorong ke stack berulang-ulang, kita akan mencoba dan mengalokasikan array yang lebih besar untuk menyesuaikan kapasitas yang lebih besar, dan malloc atau apa pun yang kami gunakan akan kembali palsu. Nah, malloc akan mengembalikan null. Ingat, setiap kali Anda pernah menelepon malloc, Anda harus memeriksa untuk melihat apakah itu mengembalikan null atau yang lain yang merupakan pengurangan kebenaran. Karena kita ingin memiliki tumpukan tak terbatas, kasus-satunya kita akan kembali palsu adalah jika kita mencoba untuk meningkatkan kapasitas dan malloc atau apa pun kembali palsu. Kemudian pop tidak membutuhkan argumen, dan mengembalikan string yang ada di atas tumpukan. Apapun yang terakhir didorong pada stack adalah apa pop yang kembali, dan juga menghapusnya dari stack. Dan melihat bahwa ia mengembalikan null jika tidak ada pada stack. Itu selalu mungkin bahwa stack kosong. Di Jawa, jika Anda terbiasa untuk itu, atau bahasa lainnya, mencoba untuk pop dari tumpukan kosong dapat menyebabkan pengecualian atau sesuatu. Tapi di C, null adalah jenis banyak kasus bagaimana kita menangani masalah ini. Kembali nol adalah bagaimana kita akan menandakan bahwa tumpukan itu kosong. Kami telah menyediakan kode yang akan menguji fungsionalitas tumpukan Anda, menerapkan mendorong dan pop. Ini tidak akan banyak kode. Aku akan-sebenarnya, sebelum kita melakukan itu, petunjuk, petunjuk- jika Anda belum melihatnya, malloc bukanlah satu-satunya fungsi yang mengalokasikan memori di heap untuk Anda. Ada keluarga fungsi alokasi. Yang pertama adalah malloc, yang Anda terbiasa. Lalu ada calloc, yang melakukan hal yang sama seperti malloc, tetapi akan nol semuanya untuk Anda. Jika Anda pernah ingin mengatur semuanya untuk null setelah mallocing sesuatu Anda seharusnya hanya menggunakan calloc di tempat pertama alih-alih menulis untuk loop untuk nol seluruh blok memori. Realloc seperti malloc dan memiliki banyak kasus khusus, tetapi pada dasarnya apa yang dilakukan adalah realloc dibutuhkan pointer yang sudah dialokasikan. Realloc adalah fungsi yang ingin memperhatikan sini. Dibutuhkan pointer yang sudah kembali dari malloc. Katakanlah Anda meminta dari malloc pointer dari 10 byte. Lalu kemudian Anda sadar bahwa Anda ingin 20 byte, sehingga Anda sebut realloc pada bahwa pointer dengan 20 byte, dan realloc otomatis akan menyalin atas segala sesuatu untuk Anda. Jika Anda baru saja menelepon malloc lagi, seperti saya memiliki blok 10 byte. Sekarang aku butuh blok 20 byte, jadi jika saya malloc 20 byte, maka saya harus secara manual menyalin selama 10 byte dari hal pertama ke hal kedua dan kemudian bebas hal pertama. Realloc akan menangani untuk Anda. Perhatikan tanda tangan akan menjadi void *, yang hanya kembali pointer ke blok memori, maka void * ptr. Anda dapat menganggap void * sebagai pointer generik. Umumnya, Anda tidak pernah berurusan dengan void *, tapi malloc mengembalikan void *, dan kemudian itu hanya digunakan seperti ini benar-benar akan menjadi char *. The * sebelumnya kekosongan yang telah dikembalikan oleh malloc sekarang akan diteruskan ke realloc, dan kemudian ukuran adalah nomor baru byte Anda ingin mengalokasikan, sehingga kapasitas baru Anda. Saya akan memberi Anda beberapa menit, dan melakukannya di ruang kita. Mulailah dengan Revisi 1. Saya akan menghentikan Anda setelah semoga tentang waktu yang cukup untuk melaksanakan push, dan kemudian saya akan memberi Anda istirahat lain untuk melakukan pop. Tapi itu benar-benar tidak bahwa kode sama sekali. Kode yang paling mungkin adalah hal memperluas, memperluas kapasitas. Oke, tidak ada tekanan harus benar-benar dilakukan, tetapi selama Anda merasa seperti Anda berada di jalan yang benar, itu bagus. Apakah ada yang punya kode mereka merasa nyaman dengan saya menariknya ke atas? Ya, aku akan, tetapi tidak ada yang punya kode saya dapat menarik? Oke, bisa Anda mulai, menyimpannya, apa pun itu? Aku selalu lupa langkah itu. Oke, melihat dorongan, Anda ingin menjelaskan kode Anda? [Mahasiswa] Pertama-tama, saya meningkatkan ukuran. Saya kira mungkin aku harus memiliki-pula, saya meningkatkan ukuran, dan saya melihat apakah itu kurang dari kapasitas. Dan jika itu kurang dari kapasitas, saya tambahkan ke array yang sudah kita miliki. Dan jika tidak, saya melipatgandakan kapasitas dengan 2, dan saya mengalokasikan array string untuk sesuatu dengan ukuran kapasitas yang lebih besar sekarang. Dan kemudian jika itu gagal, saya memberitahu pengguna dan kembali palsu, dan jika tidak apa-apa, maka saya menempatkan string di tempat yang baru. [Rob B.] Juga perhatikan bahwa kita menggunakan operator bitwise bagus di sini kalikan dengan 2. Ingat, pergeseran kiri selalu akan dikalikan dengan 2. Shift kanan dibagi oleh 2 selama Anda ingat bahwa itu berarti membagi dengan 2 seperti dalam integer dibagi dengan 2. Mungkin memotong sebuah 1 sini atau di sana. Tapi pergeseran ditinggalkan oleh 1 selalu akan dikalikan dengan 2, kecuali Anda meluap batas-batas integer, dan kemudian tidak akan. Sebuah komentar samping. Saya ingin melakukan-ini tidak akan mengubah coding cara apapun, tapi saya ingin melakukan sesuatu seperti ini. Ini benar-benar akan membuatnya sedikit lebih panjang. Mungkin ini bukan kasus yang sempurna untuk menunjukkan hal ini, tapi saya ingin segmen itu ke dalam blok- oke, jika ini jika terjadi, maka aku akan melakukan sesuatu, dan kemudian fungsi dilakukan. Saya tidak perlu kemudian gulir mata saya semua jalan ke bawah fungsi untuk melihat apa yang terjadi setelah itu yang lain. Ini jika ini jika terjadi, maka saya hanya kembali. Hal ini juga memiliki manfaat tambahan yang bagus dari segala sesuatu di luar ini kini bergeser ke kiri sekali. Saya tidak perlu lagi-jika Anda pernah dekat ridiculously antrean panjang, maka mereka 4 byte bisa membantu, dan juga sesuatu yang lebih kiri adalah, kurang kewalahan jika Anda merasa seperti-oke, aku harus ingat Aku sedang dalam loop sementara di dalam suatu dalam lain dari untuk loop. Di mana saja Anda dapat melakukan ini segera kembali, aku jenis seperti. Ini benar-benar opsional dan tidak diharapkan dengan cara apapun. [Mahasiswa] Harus ada ukuran - dalam kondisi gagal? Kondisi gagal di sini adalah kita gagal realloc, jadi ya. Perhatikan bagaimana dalam kondisi gagal, mungkin, kecuali kita free stuff kemudian, kami selalu akan gagal tidak peduli berapa kali kita mencoba untuk mendorong sesuatu. Jika kita terus mendorong, kami menjaga ukuran incrementing, meskipun kita tidak menempatkan sesuatu ke stack. Biasanya kita tidak kenaikan ukuran sampai setelah kita telah berhasil meletakkannya di stack. Kami akan melakukannya, katakanlah, baik di sini dan di sini. Dan kemudian bukannya mengatakan s.size kapasitas ≤, itu kurang dari kapasitas, hanya karena kami pindah di mana segala sesuatu. Dan ingat, satu-satunya tempat yang kita mungkin bisa kembali palsu di sini, di mana realloc kembali nol, dan jika Anda kebetulan mengingat standard error, mungkin Anda mungkin menganggap ini kasus di mana Anda ingin mencetak standard error, sehingga fprintf stderr bukan hanya mencetak langsung ke luar standar. Sekali lagi, itu bukan harapan, tapi kalau itu kesalahan, ketik printf, maka Anda mungkin ingin membuatnya mencetak ke standard error bukannya keluar standar. Ada yang punya hal lain yang perlu diperhatikan? Ya. [Siswa] Dapatkah Anda pergi selama [tak terdengar]? [Rob B.] Ya, binariness sebenarnya atau hanya apa itu? [Siswa] Jadi Anda kalikan dengan 2? [Rob B.] Ya, pada dasarnya. Di tanah biner, kita selalu memiliki set kami digit. Pergeseran kiri ini dengan 1 dasarnya sisipan di sini di sisi kanan. Kembali ke ini, hanya mengingat bahwa segala sesuatu dalam biner adalah kekuatan dari 2, jadi ini merupakan 2 ke 0 tersebut, ini 2 ke 1, ini 2 ke 2. Dengan memasukkan 0 ke sisi kanan sekarang, kita hanya menggeser segala sesuatunya. Apa yang digunakan untuk menjadi 2 ke 0 kini 2 ke 1, 2 adalah untuk 2. Sisi kanan yang kita dimasukkan ini tentu akan menjadi 0, yang masuk akal. Jika Anda pernah kalikan jumlah dengan 2, itu tidak akan berakhir aneh, sehingga 2 ke tempat 0 harus 0, dan ini adalah apa yang saya setengah memperingatkan tentang sebelum adalah jika Anda kebetulan bergeser melampaui jumlah bit dalam integer, maka 1 ini akan berakhir pergi. Itulah satu-satunya khawatir jika Anda kebetulan akan berurusan dengan kapasitas benar-benar besar. Tapi pada saat itu, maka Anda sedang berhadapan dengan sebuah array dari miliaran hal, yang tidak mungkin masuk ke dalam memori tetap. Sekarang kita bisa sampai ke pop, yang bahkan lebih mudah. Anda bisa melakukannya seperti jika Anda kebetulan pop sejumlah, dan sekarang kau pada kapasitas setengah lagi. Anda bisa realloc untuk mengecilkan jumlah memori yang Anda miliki, namun Anda tidak perlu khawatir tentang hal itu, sehingga kasus realloc hanya akan menjadi tumbuh memori, tidak pernah menyusut memori, yang akan membuat super pop mudah. Sekarang antrian, yang akan menjadi seperti tumpukan, tetapi agar Anda mengambil hal-hal dibalik. Contoh prototipikal dari antrian adalah garis, jadi saya kira jika Anda orang Inggris, saya akan mengatakan contoh prototipikal dari antrian adalah antrian. Jadi seperti baris, jika Anda adalah orang pertama di garis, Anda berharap untuk menjadi orang pertama yang keluar dari garis. Jika Anda adalah orang terakhir di baris, Anda akan menjadi orang terakhir dilayani. Kami menyebutnya pola FIFO, sedangkan tumpukan adalah LIFO pola. Kata-kata cukup universal. Seperti tumpukan dan tidak seperti array, antrian biasanya tidak mengizinkan akses ke elemen di tengah. Di sini, stack, kita memiliki push dan pop. Di sini, kita kebetulan telah memanggil mereka enqueue dan dequeue. Saya juga mendengar mereka disebut pergeseran dan unshift. Saya pernah mendengar orang mengatakan push dan pop juga berlaku untuk antrian. Aku telah mendengar menyisipkan, menghapus, sehingga mendorong dan pop, jika Anda berbicara tentang tumpukan, Anda mendorong dan muncul. Jika Anda berbicara tentang antrian, Anda bisa memilih kata-kata yang ingin Anda gunakan untuk penyisipan dan penghapusan, dan tidak ada konsensus tentang apa yang harus disebut. Tapi di sini, kita memiliki enqueue dan dequeue. Sekarang, struct terlihat hampir identik dengan struct stack. Tapi kita harus melacak kepala. Saya kira itu mengatakan di sini, tapi mengapa kita perlu kepala? Prototipe pada dasarnya identik dengan mendorong dan pop. Anda dapat menganggapnya sebagai push dan pop. Satu-satunya perbedaan adalah pop yang kembali-bukan yang terakhir, itu kembali yang pertama. 2, 1, 3, 4, atau sesuatu. Dan inilah awal. Antrian kami benar-benar penuh, jadi ada empat unsur di dalamnya. Akhir antrian kami saat ini 2, dan sekarang kita pergi untuk memasukkan sesuatu yang lain. Ketika kita ingin memasukkan sesuatu yang lain, apa yang kita lakukan untuk versi tumpukan adalah kita memperluas kami blok memori. Apa masalah ini? [Siswa] Anda memindahkan 2 tersebut. Apa yang saya katakan sebelumnya tentang akhir antrian, ini tidak masuk akal bahwa kita mulai dari 1, maka kita ingin dequeue 1, kemudian dequeue 3, kemudian dequeue 4, kemudian dequeue 2, kemudian dequeue satu ini. Kita tidak bisa menggunakan realloc sekarang, atau setidaknya, Anda harus menggunakan realloc dengan cara yang berbeda. Tapi mungkin sebaiknya Anda tidak hanya menggunakan realloc. Anda akan harus secara manual menyalin memori Anda. Ada dua fungsi untuk menyalin memori. Ada memcopy dan memmove. Saat ini saya membaca halaman manual untuk melihat mana yang Anda akan ingin menggunakan. Oke, memcopy, perbedaannya adalah bahwa memcopy dan memmove, yang menangani kasus ini dengan benar di mana Anda menyalin ke wilayah yang terjadi tumpang tindih wilayah Anda menyalin dari. Memcopy tidak menanganinya. Memmove tidak. Anda dapat menganggap masalah sebagai- katakanlah saya ingin menyalin orang ini, keempat orang ini ke atas. Pada akhirnya, apa yang array harus seperti setelah salinan tersebut 2, 1, 2, 1, 3, 4, dan kemudian beberapa hal di akhir. Tapi ini tergantung pada urutan di mana kita benar-benar menyalin, karena jika kita tidak mempertimbangkan fakta bahwa wilayah kita menyalin ke tumpang tindih yang kita menyalin dari, maka kita bisa melakukan seperti start di sini, copy 2 ke tempat kita ingin pergi, kemudian memindahkan pointer kita ke depan. Sekarang kita akan berada di sini dan di sini, dan sekarang kami ingin menyalin orang ini atas orang ini dan bergerak pointer kita ke depan. Apa yang kita akan akhirnya mendapatkan adalah 2, 1, 2, 1, 2, 1 bukannya 2 yang sesuai, 1, 2, 1, 3, 4 karena 2, 1 mengesampingkan 3 aslinya, 4. Memmove menangani yang benar. Dalam hal ini, pada dasarnya hanya selalu menggunakan memmove karena menangani dengan benar. Hal ini biasanya tidak melakukan lebih buruk. Idenya adalah bukan mulai dari awal dan menyalin cara ini seperti kita lakukan di sini, itu dimulai dari akhir dan salinan dalam, dan dalam hal ini, Anda tidak pernah memiliki masalah. Ada kinerja tidak hilang. Selalu gunakan memmove. Jangan khawatir tentang memcopy. Dan di sanalah Anda akan harus terpisah memmove bagian-dibungkus sekitar antrian Anda. Jangan khawatir jika tidak benar-benar dilakukan. Ini lebih sulit daripada tumpukan, push pop, dan. Ada yang punya kode yang kami bisa bekerja dengan? Bahkan jika benar-benar tidak lengkap? [Mahasiswa] Ya, itu benar-benar lengkap, meskipun. Benar-benar lengkap baik-baik saja selama kita-bisa Anda menyimpan revisi? Saya lupa bahwa setiap saat. Oke, mengabaikan apa yang terjadi ketika kita perlu mengubah ukuran hal. Sepenuhnya mengabaikan resize. Jelaskan kode ini. Aku memeriksa pertama-tama jika ukurannya kurang dari salinan pertama-tama dan kemudian setelah itu, saya memasukkan-saya mengambil kepala + ukuran, dan saya pastikan membungkus kapasitas array, dan saya memasukkan string baru di posisi itu. Lalu aku meningkatkan ukuran dan kembali benar. [Rob B.] Ini jelas salah satu kasus di mana Anda akan ingin menggunakan mod. Setiap jenis kasus di mana Anda telah membungkus sekitar, jika Anda berpikir membungkus di sekitar, pemikiran yang harus segera diwujudkan mod. Sebagai optimasi cepat / membuat kode Anda satu baris pendek, Anda melihat bahwa garis segera setelah yang satu ini hanya ukuran + +, sehingga Anda menggabungkan itu ke baris ini, ukuran + +. Sekarang di sini, kita memiliki kasus di mana kita tidak memiliki cukup memori, jadi kita meningkatkan kapasitas kita dengan 2. Saya kira Anda bisa memiliki masalah yang sama di sini, tapi kita bisa mengabaikannya sekarang, di mana jika Anda gagal untuk meningkatkan kapasitas Anda, maka Anda akan ingin menurunkan kapasitas Anda dengan 2 lagi. Lain catatan pendek adalah seperti yang dapat Anda lakukan + =, Anda juga dapat melakukan << =. Hampir apa pun bisa pergi sebelum sama, + =, | =, & =, << =. Char * baru blok baru memori. Oh, di sini. Apa yang orang pikirkan tentang jenis blok baru memori? [Mahasiswa] Harus char **. Berpikir kembali ke struct kami di sini, string adalah apa yang kita merealokasi. Kami membuat penyimpanan dinamis keseluruhan baru untuk elemen dalam antrian. Apa yang kita akan menugaskan ke string Anda adalah apa yang kita mallocing sekarang, dan sebagainya baru akan menjadi char **. Ini akan menjadi sebuah array dari string. Lalu apa yang terjadi di mana kita akan kembali palsu? [Mahasiswa] Haruskah kita melakukan char *? [Rob B.] Ya, panggilan yang baik. [Mahasiswa] Apa itu? [Rob B.] Kami ingin melakukan ukuran char * karena kita tidak lagi- ini benar-benar akan menjadi masalah yang sangat besar karena sizeof (char) akan menjadi 1. Sizeof char * akan menjadi 4, sehingga banyak kali ketika Anda sedang berhadapan dengan ints, Anda cenderung untuk pergi dengan itu karena ukuran int dan ukuran * int pada sistem 32-bit akan menjadi hal yang sama. Tapi di sini, sizeof (char) dan sizeof (char *) sekarang akan menjadi hal yang sama. Apa keadaan di mana kita kembali palsu? [Mahasiswa] New adalah null. Ya, jika baru adalah null, kita kembali palsu, dan aku akan melemparkan ke bawah sini- [Mahasiswa] [tak terdengar] [Rob B.] Ya, ini baik-baik saja. Anda juga bisa melakukan 2 kali kapasitas atau pergeseran kapasitas 1 dan kemudian hanya meletakkannya di sini atau apa pun. Kami akan melakukannya yang kita miliki. Kapasitas >> = 1. Dan Anda tidak akan pernah perlu khawatir tentang kehilangan tempat 1 s karena Anda meninggalkan bergeser oleh 1, sehingga tempat 1 adalah selalu 0, sehingga benar bergeser oleh 1, Anda masih akan baik-baik saja. [Siswa] Apakah Anda perlu melakukan itu sebelum kembali? [Rob B.] Ya, ini membuat benar-benar tidak masuk akal. Sekarang asumsikan kita akan berakhir kembali benar sampai akhir. Cara kita akan melakukan hal-memmoves, kita perlu berhati-hati dengan bagaimana kita melakukannya. Apakah ada yang punya saran untuk bagaimana kita melakukannya? Berikut kami mulai. Tak pelak lagi, kami ingin mulai dari awal lagi dan copy hal-hal dari sana, 1, 3, 4, 2. Bagaimana Anda melakukan itu? Pertama, saya harus melihat halaman manual untuk memmove lagi. Memmove, urutan argumen selalu penting. Kami ingin tujuan pertama kami, sumber kedua, ketiga ukuran. Ada banyak fungsi yang membalikkan sumber dan tujuan. Tujuan, sumber cenderung konsisten agak. Pindah, apa itu kembali? Ia mengembalikan pointer ke tujuan, untuk alasan apapun Anda mungkin ingin itu. Aku bisa gambar membacanya, tapi kami ingin pindah ke tujuan kami. Apa yang tujuan kita akan? [Mahasiswa] New. [Rob B.] Ya, dan di mana kita menyalin dari? Hal pertama yang kita menyalin ini 1, 3, 4. Apa-1 ini, 3, 4. Apa alamat ini 1? Apa alamat itu 1? [Mahasiswa] [tak terdengar] [Rob B.] Kepala + alamat dari elemen pertama. Bagaimana kita mendapatkan elemen pertama dalam array? [Siswa] Antrian. [Rob B.] Ya, q.strings. Ingat, di sini, kepala kita adalah 1. Darn it. Saya hanya berpikir itu ajaib- Di sini, kepala kita adalah 1. Aku akan mengubah warna saya juga. Dan di sini adalah string. Ini, kita bisa menulis seperti yang kita lakukan di sini dengan kepala + q.strings. Banyak orang juga menulis & q.strings [kepala]. Hal ini tidak benar-benar ada kurang efisien. Anda mungkin menganggapnya sebagai Anda dereferencing dan kemudian mendapatkan alamat, namun compiler akan menerjemahkannya dengan apa yang kita miliki sebelumnya pula, q.strings + kepala. Entah cara Anda ingin memikirkan hal itu. Dan berapa banyak byte yang kita ingin menyalin? [Mahasiswa] Kapasitas - kepala. Kapasitas - kepala. Dan kemudian Anda selalu bisa menulis contoh untuk mengetahui apakah itu benar. [Mahasiswa] Perlu dibagi 2 kemudian. Ya, jadi saya kira kita bisa menggunakan ukuran. Kami masih memiliki ukuran yang- menggunakan ukuran, kami memiliki ukuran sama dengan 4. Ukuran kami adalah 4. Kepala kami adalah 1. Kami ingin menyalin 3 elemen. Itulah kewarasan memeriksa ukuran itu - kepala dengan benar 3. Dan datang kembali ke sini, seperti yang kita katakan sebelumnya, jika kita menggunakan kemampuan, maka kita harus membagi dengan 2 karena kita sudah tumbuh kemampuan kita, jadi bukan, kita akan menggunakan ukuran. Bahwa salinan bagian itu. Sekarang, kita perlu menyalin bagian lain, bagian yang tersisa dari awal. Itu akan memmove ke posisi apa? [Mahasiswa] Plus ukuran - kepala. Ya, jadi kami telah disalin dalam ukuran - byte kepala, dan jadi di mana kita ingin menyalin byte tersisa yang baru dan kemudian ukuran minus-baik, jumlah byte kita sudah disalin masuk Dan kemudian di mana kita menyalin dari? [Mahasiswa] Q.strings [0]. [Rob B.] Ya, q.strings. Kita juga bisa melakukan & q.strings [0]. Ini secara signifikan kurang umum daripada ini. Jika itu hanya akan menjadi 0, maka Anda akan cenderung melihat q.strings. Di situlah kita menyalin dari. Berapa banyak byte yang kita miliki untuk menyalin? >> [Siswa] 10. Benar. [Mahasiswa] Apakah kita harus kalikan 5 - 10 kali ukuran byte atau sesuatu? Ya, jadi ini adalah di mana-apa sebenarnya yang kita menyalin? [Mahasiswa] [tak terdengar] Apa jenis hal yang kita menyalin? [Mahasiswa] [tak terdengar] Ya, jadi char * s yang kita menyalin, kita tidak tahu di mana mereka berasal. Nah, di mana mereka menunjuk ke, seperti string, kita akhirnya mendorongnya ke antrian atau enqueuing ke antrian. Dimana mereka berasal dari, kita tidak tahu. Kita hanya perlu untuk melacak file * char s sendiri. Kami tidak ingin menyalin ukuran - byte kepala. Kami ingin menyalin ukuran - Kepala char * s, jadi kita akan kalikan ini dengan sizeof (char *). Sama di sini, kepala * sizeof (char *). [Siswa] Bagaimana [tak terdengar]? Ini di sini? [Mahasiswa] Tidak, di bawah itu, ukuran - kepala. [Rob B.] ini di sini? Pointer aritmatika. Bagaimana aritmatika pointer akan bekerja adalah secara otomatis mengalikan oleh ukuran dari jenis yang kita hadapi. Sama seperti di sini, baru + (ukuran - kepala) adalah persis setara dengan & [ukuran - kepala] baru sampai kita berharap bahwa bekerja dengan benar, karena jika kita sedang berhadapan dengan sebuah array int, maka kita tidak indeks oleh int- atau apakah itu dari ukuran 5 dan Anda ingin elemen 4, maka kita indeks ke dalam int array [4]. Anda jangan-[4] * ukuran int. Yang menangani secara otomatis, dan kasus ini secara harfiah setara, sehingga sintaks braket hanya akan dikonversi ini segera setelah Anda mengkompilasi. Itu sesuatu yang Anda harus berhati-hati itu ketika Anda menambahkan ukuran - kepala Anda tidak menambahkan satu byte. Anda menambahkan satu char *, yang dapat menjadi salah satu byte atau apa pun. Pertanyaan lain? Oke, dequeue akan menjadi lebih mudah. Saya akan memberikan satu menit untuk melaksanakan. Oh, dan saya kira ini adalah situasi yang sama di mana apa kasus enqueue, jika kita enqueuing nol, mungkin kita ingin menanganinya, mungkin kita tidak. Kami tidak akan melakukannya lagi di sini, tapi sama seperti kasus tumpukan kami. Jika kita enqueue nol, kita mungkin ingin mengabaikannya. Ada yang punya beberapa kode saya dapat menarik? [Mahasiswa] Saya hanya memiliki dequeue. Versi 2 adalah bahwa-oke. Anda ingin menjelaskan? [Mahasiswa] Pertama, Anda memastikan ada sesuatu dalam antrian dan bahwa ukuran akan turun 1. Anda perlu melakukan itu, dan kemudian Anda kembali kepala dan kemudian menggerakkan kepala ke atas 1. Oke, jadi ada kasus sudut kita harus mempertimbangkan. Ya. [Mahasiswa] Jika kepala Anda adalah pada elemen terakhir, maka Anda tidak ingin kepala ke titik di luar array. Ya, sehingga segera setelah kepala hits akhir array kita, ketika kita dequeue, kepala kita harus modded kembali ke 0. Sayangnya, kita tidak bisa melakukan itu dalam satu langkah. Saya kira cara saya mungkin akan memperbaikinya adalah ini akan menjadi char *, apa yang kita kembali, apapun nama variabel Anda ingin menjadi. Kemudian kita ingin mod kepala oleh kemampuan kita dan kemudian kembali ret. Banyak orang di sini yang mungkin mereka lakukan- ini adalah kasus-Anda akan melihat orang-orang lakukan jika kepala lebih besar dari kapasitas, lakukan kepala - kapasitas. Dan itu hanya bekerja sekitar apa mod ini. Kepala mod = kapasitas jauh lebih bersih dari pembungkus sekitar daripada jika kepala lebih besar daripada kepala kapasitas - kapasitas. Pertanyaan? Oke, hal terakhir yang kita telah meninggalkan adalah linked list kami. Anda mungkin akan digunakan untuk beberapa perilaku linked list jika Anda melakukan terkait daftar dalam tabel hash Anda, jika Anda melakukan tabel hash. Saya sangat merekomendasikan melakukan tabel hash. Anda mungkin sudah melakukan trie, tetapi mencoba lebih sulit. Secara teori, mereka asimtotik lebih baik. Tapi hanya melihat papan besar, dan mencoba tidak pernah berbuat lebih baik, dan mereka mengambil lebih banyak memori. Segala sesuatu tentang mencoba akhirnya menjadi buruk untuk bekerja lebih. Ini adalah apa solusi David Malan selalu adalah adalah dia selalu posting solusi trie, dan mari kita lihat di mana dia saat ini. Apa dia di bawah, David J? Dia # 18, jadi itu tidak terlalu buruk, dan itu akan menjadi salah satu yang terbaik mencoba Anda bisa memikirkan atau salah satu yang terbaik mencoba dari trie. Apakah tidak bahkan solusi aslinya? Saya merasa seperti trie solusi cenderung lebih dalam kisaran penggunaan RAM. Pergi ke bagian paling atas, dan penggunaan RAM dalam satu digit. Turun ke bawah, dan kemudian Anda mulai melihat mencoba di mana Anda mendapatkan penggunaan RAM benar-benar besar, dan mencoba lebih sulit. Tidak sepenuhnya layak tapi pengalaman pendidikan jika Anda melakukan satu. Yang terakhir adalah linked list kami, dan tiga hal, tumpukan, antrian, dan daftar terhubung, setiap hal di masa depan Anda pernah dilakukan di ilmu komputer akan menganggap Anda memiliki keakraban dengan hal-hal ini. Mereka hanya begitu fundamental bagi segala sesuatu. Linked daftar, dan di sini kami telah daftar tunggal terkait akan menjadi implementasi kami. Apa tunggal terkait berarti sebagai lawan ganda terkait? Ya. [Mahasiswa] Ini hanya menunjuk ke pointer berikutnya daripada ke pointer, seperti yang mendahuluinya dan yang setelah itu. Ya, sehingga dalam format gambar, apa yang aku lakukan? Aku punya dua hal. Saya memiliki gambar dan gambar. Dalam format gambar, daftar tunggal kami terkait, pasti, kami memiliki beberapa jenis pointer ke kepala daftar kami, dan kemudian dalam daftar kami, kami hanya memiliki pointer, dan mungkin ini poin ke null. Ini akan menjadi gambar khas dari linked list tunggal. Sebuah daftar ganda terkait, Anda dapat pergi ke belakang. Jika saya memberi Anda setiap node dalam daftar, maka Anda selalu bisa mendapatkan node lain dalam daftar jika itu adalah daftar ganda terkait. Tapi kalau aku mendapatkan simpul ketiga dalam daftar dan itu adalah daftar sendiri-sendiri terkait, ada cara Anda pernah akan sampai ke node pertama dan kedua. Dan ada manfaat dan detriments, dan satu yang jelas adalah Anda mengambil ukuran yang lebih, dan Anda harus melacak di mana hal-hal ini menunjuk sekarang. Tapi kita hanya peduli tunggal terkait. Beberapa hal yang kita akan harus melaksanakan. Anda typedef struct node, int i: struct simpul * berikutnya; simpul. Itu typedef harus dibakar ke dalam pikiran Anda. Kuis 1 harus seperti memberikan typedef dari simpul linked list, dan Anda harus dapat segera menuliskan yang turun bahkan tanpa berpikir tentang hal itu. Saya kira beberapa pertanyaan, mengapa kita perlu struct di sini? Mengapa tidak bisa kita katakan * simpul? [Mahasiswa] [tak terdengar] Ya. Satu-satunya hal yang mendefinisikan node sebagai sesuatu yang adalah typedef itu sendiri. Tapi seperti dari titik ini, ketika kita jenis parsing melalui simpul definisi struct, kami belum selesai typedef kami belum, jadi karena typedef belum selesai, simpul tidak ada. Tapi struct simpul tidak, dan simpul ini di sini, ini juga bisa disebut apa pun. Ini bisa disebut n. Ini bisa disebut simpul linked list. Ini bisa disebut apa-apa. Tapi ini simpul struct perlu disebut hal yang sama seperti ini simpul struct. Apa yang Anda sebut ini harus juga berada di sini, dan sebagainya yang juga menjawab titik kedua dari pertanyaan itulah sebabnya mengapa-banyak kali ketika Anda melihat structs dan typedef struct, Anda akan melihat structs anonim di mana Anda hanya akan melihat struct typedef, pelaksanaan struct, kamus, atau apa pun. Kenapa di sini kita perlu untuk mengatakan simpul? Mengapa tidak bisa itu menjadi struct anonim? Ini hampir jawaban yang sama. [Siswa] Anda perlu menyebutnya dalam struct. Ya, dalam struct, Anda perlu merujuk pada struct itu sendiri. Jika Anda tidak memberikan struct nama, jika itu sebuah struct anonim, Anda tidak bisa menyebutnya. Dan last but not least-ini semua harus agak mudah, dan mereka akan membantu Anda menyadari jika Anda sedang menulis ini turun bahwa Anda sedang melakukan sesuatu yang salah jika macam hal tidak masuk akal. Last but not least, mengapa hal ini harus struct * simpul? Mengapa tidak bisa hanya menjadi struct node berikutnya? [Mahasiswa] Pointer ke struct berikutnya. Itu pasti apa yang kita inginkan. Kenapa bisa tidak pernah menjadi struct node berikutnya? Mengapa harus struct simpul * selanjutnya? Ya. [Siswa] Ini seperti infinite loop. Ya. [Mahasiswa] Itu semua akan berada dalam satu. Ya, hanya berpikir tentang bagaimana kita akan melakukan ukuran atau sesuatu. Ukuran struct pada dasarnya + atau - beberapa pola sini atau di sana. Ini pada dasarnya akan menjadi jumlah ukuran dari hal-hal di struct. Ini di sini, tanpa mengubah apapun, ukuran akan menjadi mudah. Ukuran simpul struct akan menjadi ukuran i ukuran + berikutnya. Ukuran saya akan menjadi 4. Ukuran selanjutnya akan menjadi 4. Ukuran simpul struct akan menjadi 8. Jika kita tidak memiliki *, memikirkan sizeof, maka sizeof (i) akan menjadi 4. Ukuran simpul struct selanjutnya akan menjadi ukuran i + ukuran struct simpul berikutnya + Ukuran + i ukuran node struct berikutnya. Ini akan menjadi rekursi tak terbatas node. Inilah sebabnya mengapa hal ini adalah bagaimana hal-hal yang harus. Sekali lagi, pasti menghafal itu, atau setidaknya mengerti cukup bahwa Anda dapat dapat Alasan melalui apa yang seharusnya terlihat seperti. Hal-hal yang kita akan ingin menerapkan. Jika panjang daftar- Anda bisa menipu dan tetap sekitar global yang panjang atau sesuatu, tapi kami tidak akan melakukan itu. Kita akan menghitung panjang daftar. Kami telah mengandung, sehingga pada dasarnya seperti pencarian, jadi kami memiliki daftar link dari bilangan bulat untuk melihat apakah bilangan bulat ini berada di linked list. Tambahkan akan memasukkan pada awal daftar. Append akan memasukkan di akhir. Insert_sorted akan memasukkan ke dalam posisi yang diurutkan dalam daftar. Jenis Insert_sorted dari mengasumsikan bahwa Anda tidak pernah digunakan tambahkan atau append dengan cara yang buruk. Insert_sorted ketika Anda menerapkan insert_sorted- katakanlah kita memiliki daftar kami terkait. Ini adalah apa yang saat ini tampak seperti, 2, 4, 5. Saya ingin menyisipkan 3, sehingga selama daftar sendiri sudah diurutkan, sangat mudah untuk menemukan di mana 3 milik. Saya mulai 2. Oke, 3 lebih besar dari 2, jadi saya ingin terus berjalan. Oh, 4 terlalu besar, jadi saya tahu 3 akan pergi di antara 2 dan 4, dan saya harus memperbaiki pointer dan segala macamnya. Tetapi jika kita tidak benar-benar menggunakan insert_sorted, seperti katakan saja saya tambahkan 6, maka linked list saya akan menjadi ini. Sekarang tidak masuk akal, sehingga untuk insert_sorted, Anda hanya bisa berasumsi bahwa daftar diurutkan, meskipun ada operasi yang dapat menyebabkan hal itu tidak akan diurutkan, dan hanya itu. Cari membantu insert-sehingga mereka adalah hal utama Anda akan harus melaksanakan. Untuk saat ini, luangkan waktu sebentar untuk melakukan panjang dan berisi, dan mereka harus relatif cepat. Menjelang waktu penutupan, sehingga ada yang punya apa-apa untuk panjang atau berisi? Mereka akan menjadi hampir identik. [Siswa] Panjang. Mari kita lihat, revisi. Oke. Anda ingin menjelaskan? [Mahasiswa] saya hanya membuat simpul pointer dan menginisialisasi pertama, yang merupakan variabel global kami, dan kemudian aku memeriksa untuk melihat apakah itu nol sehingga saya tidak mendapatkan kesalahan seg dan kembali 0 jika itu yang terjadi. Jika tidak, saya loop melalui, mencatat dalam bilangan bulat berapa kali saya telah diakses elemen berikutnya dari daftar dan dalam operasi peningkatan yang sama juga mengakses elemen yang sebenarnya, dan kemudian saya terus menerus melakukan cek untuk melihat apakah itu nol, dan jika itu nol, maka Aborts dan hanya mengembalikan jumlah elemen saya sudah diakses. [Rob B.] Apakah ada yang punya komentar pada apa pun? Hal ini terlihat benar baik bijaksana. [Mahasiswa] Saya tidak berpikir Anda membutuhkan node == null. Ya, jadi jika simpul == 0 kembali nol. Tapi jika node == null maka ini-oh, ada masalah kebenaran. Itu hanya Anda kembali i, tapi tidak dalam lingkup sekarang. Anda hanya perlu int i, sehingga i = 0. Tetapi jika simpul adalah nol, maka saya masih akan menjadi 0, dan kita akan kembali 0, sehingga kasus ini identik. Hal lain yang umum adalah untuk menjaga deklarasi di dalam node untuk loop. Anda bisa mengatakan-oh, tidak. Mari kita tetap seperti ini. Saya mungkin akan menempatkan int i = 0 di sini, maka simpul simpul * = pertama di sini. Dan ini mungkin bagaimana-menyingkirkan ini sekarang. Ini mungkin bagaimana saya akan menulis itu. Anda bisa juga melihat-hal seperti ini. Ini untuk struktur lingkaran di sini harus hampir sama alami untuk Anda sebagai untuk int i = 0 i adalah kurang dari panjang array i + +. Jika itu bagaimana Anda iterate atas array, ini adalah bagaimana Anda iterate atas daftar link. Ini harus menjadi sifat kedua di beberapa titik. Dengan itu dalam pikiran, ini akan menjadi hal yang hampir sama. Anda akan ingin iterate atas daftar link. Jika node-aku tidak tahu apa nilai yang disebut. Node i. Jika nilai pada node yang = i kembali benar, dan hanya itu. Perhatikan bahwa satu-satunya cara kita pernah kembali palsu adalah jika kita iterate atas linked list seluruh dan tidak pernah kembali benar, jadi itulah apa hal ini. Sebagai sisi catatan-kita mungkin tidak akan bisa menambahkan atau tambahkan. Cepat catatan terakhir. Jika Anda melihat kata kunci statis, jadi mari kita katakan static int count = 0, maka kita lakukan count + +, Anda pada dasarnya dapat menganggapnya sebagai variabel global, meskipun saya hanya mengatakan ini adalah bukan bagaimana kita akan mengimplementasikan panjang. Aku melakukan ini di sini, dan kemudian menghitung + +. Setiap cara kita bisa masuk ke dalam simpul linked list kami, kami incrementing hitungan kami. Inti dari ini adalah apa kata kunci statis berarti. Jika saya hanya punya int count = 0 yang akan menjadi variabel global biasa tua. Apa artinya menghitung static int adalah bahwa itu adalah variabel global untuk file ini. Tidak mungkin untuk beberapa file lain, seperti berpikir pset 5, jika Anda sudah mulai. Anda memiliki speller.c baik, dan Anda memiliki dictionary.c, dan jika Anda hanya menyatakan hal yang global, maka apa pun di speller.c dapat diakses dalam dictionary.c dan sebaliknya. Variabel global dapat diakses oleh file c., namun variabel statis hanya dapat diakses dari dalam file itu sendiri, sehingga dalam spell checker atau dalam dictionary.c, ini adalah jenis bagaimana saya akan mendeklarasikan variabel saya untuk ukuran array saya atau ukuran nomor saya dari kata-kata dalam kamus. Karena saya tidak ingin mendeklarasikan variabel global yang telah ada akses ke, Saya benar-benar hanya peduli tentang hal itu untuk tujuan saya sendiri. Hal yang baik tentang ini adalah juga hal-hal nama seluruh tabrakan. Jika beberapa file lain mencoba untuk menggunakan variabel global yang disebut count, hal-hal pergi sangat, sangat salah, jadi ini baik menjaga hal-hal yang aman, dan hanya Anda yang dapat mengaksesnya, dan tidak ada orang lain bisa, dan jika orang lain menyatakan sebuah variabel global yang disebut count, maka tidak akan mengganggu variabel statis Anda disebut count. Itulah yang statis. Ini adalah variabel file global. Pertanyaan pada apa pun? Semua siap. Bye. [CS50.TV]