[Powered by Google Translate] [BAGIAN 5: KURANG NYAMAN]
[Nate Hardison, Universitas Harvard]
[Ini adalah CS50.] [CS50.TV]
Jadi selamat datang kembali, guys.
Selamat datang ke bagian 5.
Pada titik ini, setelah menyelesaikan kuis 0 dan setelah melihat bagaimana Anda lakukan,
mudah-mudahan Anda merasa benar-benar baik karena saya sangat terkesan dengan nilai di bagian ini.
Untuk pemirsa online kami, kami telah memiliki beberapa pertanyaan
tentang dua masalah terakhir di sejumlah masalah - atau kuis, bukan.
Jadi kita akan pergi ke orang-orang benar-benar cepat sehingga semua orang melihat apa yang terjadi
dan bagaimana untuk pergi melalui solusi yang sebenarnya bukan hanya melihat solusi itu sendiri.
Kita akan pergi selama beberapa masalah sangat cepat, 32 dan 33.
Hanya, sekali lagi, sehingga pemirsa online dapat melihat ini.
>> Jika Anda beralih ke masalah, Anda 32 yang pada halaman 13,
13 dari 16, 32 masalah adalah semua tentang swap.
Itu semua tentang swapping dua bilangan bulat.
Ini adalah masalah yang kita pergi selama beberapa kali dalam kuliah.
Dan di sini, apa yang kita minta Anda lakukan adalah jejak memori cepat.
Untuk mengisi nilai dari variabel karena mereka di stack
sebagai kode berjalan melalui fungsi swap.
Secara khusus, apa yang kita sedang melihat - saya akan menempatkan iPad ini turun -
khususnya, apa yang kita lihat adalah baris ini berjumlah 6 di sini.
Dan itu nomor 6 hanya kedekatan dengan masalah sebelumnya.
Apa yang ingin kita lakukan adalah menampilkan label atau keadaan memori
karena pada saat kita menjalankan ini nomor baris 6,
yang efektif kembali dari fungsi swap kita di sini.
Jika kita scroll ke bawah sini, kita melihat bahwa alamat dari segala sesuatu dalam memori yang disediakan bagi kita.
Ini sangat penting, kami akan kembali ke sana hanya dalam beberapa saat.
Dan kemudian di sini di bagian bawah, kami memiliki diagram memori kecil yang kita akan lihat.
Saya telah benar-benar melakukan hal ini di iPad saya.
Jadi aku akan bergantian bolak-balik antara iPad dan kode ini hanya untuk referensi.
>> Mari kita mulai. Pertama, mari kita fokus pada beberapa pertama baris utama di sini.
Untuk memulai, kita akan menginisialisasi x ke 1 dan ke 2 y.
Jadi kita memiliki dua variabel integer, mereka berdua akan ditempatkan di stack.
Kita akan menempatkan 1 dan 2 di dalamnya.
Jadi jika saya flip ke iPad saya, mudah-mudahan, mari kita lihat -
Apple TV mirroring, dan di sana kami pergi. Oke.
Jadi jika saya flip ke iPad saya,
Saya ingin menginisialisasi x ke 1 dan ke 2 y.
Kami melakukan itu cukup hanya dengan menulis di kotak 1 x ditandai
dan 2 di kotak bertanda y. Cukup sederhana.
Jadi sekarang mari kita kembali ke laptop, melihat apa yang terjadi selanjutnya.
Jadi ini baris berikutnya adalah di mana segala sesuatunya menjadi rumit.
Kami melewati alamat x dan alamat y sebagai parameter a dan b untuk fungsi swap.
Alamat dari x dan alamat y hal-hal yang kita tidak dapat menghitung
tanpa mengacu pada peluru tersebut menunjukkan sampai di sini.
Dan untungnya, dua yang pertama poin-poin memberitahu kita apa jawaban.
Alamat x dalam memori adalah 10, dan alamat y dalam memori adalah 14.
Jadi mereka adalah nilai-nilai yang bisa lulus sebagai a dan b bagian atas dalam fungsi swap kita.
Jadi sekali lagi, beralih kembali ke diagram kita, saya bisa menulis 10 dalam
dan 14 di b.
Sekarang, saat ini adalah di mana kita lanjutkan dengan swap.
Jadi membalik kembali ke laptop lagi,
kita melihat bahwa cara swap kerjanya adalah I dereference pertama dan toko menghasilkan tmp.
Jadi operator dereference mengatakan, "Hei. Perlakukan isi dari variabel sebagai alamat.
Pergi ke apa pun yang disimpan di alamat itu, dan beban itu. "
Apa yang Anda beban keluar dari variabel akan disimpan ke dalam variabel tmp kami.
Membalik kembali ke iPad.
Jika kita pergi ke alamat 10, kita tahu bahwa alamat 10 adalah x varible
karena kami diberitahu oleh poin-poin kami bahwa alamat dari x dalam memori adalah 10.
Jadi kita bisa pergi ke sana, mendapatkan nilai dari itu, yaitu 1, seperti yang kita lihat di iPad kami,
dan beban itu ke tmp.
Sekali lagi, ini bukan isi akhir.
Kita akan berjalan melalui dan kami akan sampai ke keadaan akhir kami program di akhir.
Tapi sekarang, kita memiliki nilai 1 yang disimpan dalam tmp.
>> Dan ada pertanyaan singkat di sini.
[Alexander] Apakah operator dereference - itu hanya tepat di depan bintang variabel?
>> Ya. Jadi operator dereference, seperti yang kita flip kembali ke laptop kita sekali lagi,
adalah bintang ini tepat di depan.
Dalam hal ini, itu adalah - Anda kontras dengan operator perkalian
yang membutuhkan dua hal, operator dereference adalah operator unary.
Hanya diterapkan pada satu nilai yang bertentangan dengan operator biner,
di mana Anda berlaku untuk dua nilai yang berbeda.
Jadi itulah yang terjadi di baris ini.
Kami dimuat nilai 1 dan disimpan ke dalam variabel sementara bilangan bulat kami.
Baris berikutnya, kita menyimpan isi b ke -
atau, lebih tepatnya, kita menyimpan isi yang b menunjuk ke ke tempat di mana menunjuk ke.
Jika kita menganalisis ini dari kanan ke kiri, kita akan b dereference,
kita akan membahas 14, kita akan ambil integer yang ada,
dan kemudian kami akan pergi ke alamat 10,
dan kita akan membuang hasil dereference kami b ke ruang itu.
Membalik kembali ke iPad kita, di mana kita dapat membuat ini sedikit lebih konkrit,
mungkin membantu jika saya menulis angka-angka pada semua alamat di sini.
Jadi kita tahu bahwa pada y, kita berada di alamat 14, x adalah di alamat 10.
Ketika kita mulai b, kita dereference b, kita akan ambil nilai 2.
Kami akan ambil nilai ini karena itu adalah nilai yang hidup di alamat 14.
Dan kita akan memasukkannya ke dalam variabel yang tinggal di alamat 10,
yang di sana, sesuai dengan variabel x kami.
Jadi kita bisa melakukan sedikit Timpa sini
di mana kita menyingkirkan 1 kami dan sebaliknya kita menulis 2.
Jadi semua yang baik dan bagus di dunia, meskipun kita sudah x ditimpa sekarang.
Kami telah menyimpan nilai lama x dalam variabel tmp kami.
Jadi kita dapat menyelesaikan swap dengan baris berikutnya.
Membalik kembali ke laptop kita.
Sekarang yang tersisa adalah untuk mengambil isi dari variabel sementara bilangan bulat kami
dan menyimpannya ke dalam variabel yang tinggal di alamat yang b memegang.
Jadi kita akan efektif b dereference untuk mendapatkan akses ke variabel
yang berada di alamat yang b memegang di dalamnya,
dan kita akan hal-hal nilai yang tmp memegang ke dalamnya.
Membalik kembali ke iPad sekali lagi.
Saya dapat menghapus nilai ini di sini, 2,
dan sebaliknya kita akan menyalin hak 1 ke dalamnya.
Kemudian baris berikutnya yang mengeksekusi, tentu saja -
jika kita flip kembali ke laptop - ini 6 poin,
yang merupakan titik di mana kami ingin memiliki diagram kita benar-benar diisi.
Jadi membalik kembali ke iPad sekali lagi, hanya sehingga Anda dapat melihat diagram selesai,
Anda dapat melihat bahwa kita memiliki 10 dalam, 14 di b, 1 dalam tmp, 2 di x, dan 1 di y.
Apakah ada pertanyaan tentang hal ini?
Apakah ini masuk akal, setelah berjalan melalui itu?
Membuat logika yang lebih sedikit? Mudah-mudahan tidak. Oke.
>> Pointer adalah topik yang sangat rumit.
Salah satu dari orang-orang kami bekerja dengan memiliki pepatah yang sangat umum:
"Untuk memahami pointer, Anda harus terlebih dahulu memahami petunjuk."
Yang saya pikir sangat benar. Ini tidak mengambil beberapa saat untuk mendapatkan digunakan untuk itu.
Menggambar banyak gambar, menggambar diagram banyak memori seperti ini sangat membantu,
dan setelah Anda berjalan melalui contoh setelah contoh demi contoh,
itu akan mulai masuk akal sedikit lebih dan rasa sedikit lebih dan arti yang lebih sedikit.
Akhirnya, suatu hari, Anda akan memiliki semua itu benar-benar menguasainya.
Ada pertanyaan sebelum kita beralih ke masalah berikutnya? Baiklah.
Jadi flip kembali ke laptop.
Masalah berikutnya yang kita miliki adalah masalah nomor 33 pada file I / O.
Memperbesar ini sedikit.
Soal 33 - Ya?
>> [Daniel] Saya hanya punya pertanyaan singkat. Bintang ini, atau tanda bintang,
itu disebut dereferencing ketika Anda menggunakan tanda bintang sebelum.
Apa itu disebut ketika Anda menggunakan ampersand sebelum?
>> Ampersand ini sebelumnya adalah alamat-operator.
Jadi mari kita gulir kembali.
Ups. Saya dalam mode zoom jadi saya tidak bisa benar-benar gulir.
Jika kita melihat kode ini benar-benar cepat di sini,
lagi, hal yang sama terjadi.
Jika kita melihat kode ini di sini, pada baris ini di mana kita membuat panggilan untuk swap,
ampersand ini hanya mengatakan "mendapatkan alamat di mana kehidupan variabel x."
Ketika Anda mengkompilasi compiler kode Anda,
itu untuk benar-benar secara fisik menandai tempat di memori untuk semua variabel Anda untuk hidup.
Dan jadi apa compiler kemudian dapat lakukan setelah itu dikompilasi segalanya,
ia tahu, "Oh, saya menempatkan x di alamat 10 Aku meletakkan y di alamat 14.."
Hal ini kemudian dapat mengisi nilai-nilai untuk Anda.
Jadi Anda kemudian dapat - dapat kemudian lulus ini dalam dan lulus & y dalam juga.
Orang-orang ini mendapatkan alamat, tetapi mereka juga, ketika Anda melewati mereka ke fungsi swap,
ini jenis informasi, ini * int di sini, memberitahu compiler,
"Oke, kita akan menafsirkan alamat ini sebagai alamat dari sebuah variabel integer."
Sebagai alamat int, yang berbeda dari alamat dari variabel karakter
karena int membutuhkan, pada mesin 32-bit, mengambil 4 byte ruang,
sedangkan karakter hanya membutuhkan 1 byte ruang.
Jadi penting untuk mengetahui juga apa - apa hidup, apa jenis nilai
yang tinggal di alamat yang mendapat berlalu masuk
Atau alamat yang Anda hadapi.
Dengan begitu, Anda tahu berapa banyak byte informasi untuk benar-benar beban keluar dari RAM Anda.
Dan kemudian, ya, ini operator dereference, seperti Anda bertanya,
pergi dan mengakses informasi pada alamat tertentu.
Jadi itu mengatakan, dengan variabel di sini, mengobati isi sebagai alamat,
pergi ke alamat tersebut, dan menarik keluar, load ke prosesor, beban ke register
sebenarnya nilai-nilai atau isi yang tinggal di alamat itu.
Ada pertanyaan lain? Ini adalah pertanyaan yang baik.
Ini banyak istilah baru juga.
Ini juga agak funky, melihat & dan * di tempat yang berbeda.
>> Baiklah.
Jadi kembali ke masalah 33, file I / O.
Ini adalah salah satu masalah yang saya pikir beberapa hal terjadi.
Satu, itu adalah topik yang cukup baru.
Itu disajikan segera sebelum kuis,
dan kemudian saya pikir itu agak seperti salah satu kata dalam masalah matematika
di mana mereka memberi Anda banyak informasi, tetapi Anda benar-benar tidak berakhir harus menggunakan ton itu.
Bagian pertama dari masalah ini adalah menggambarkan apa file CSV.
Sekarang, file CSV, menurut deskripsi, adalah comma-separated values ​​file.
Alasan ini sama sekali menarik, dan alasan Anda pernah menggunakannya,
adalah, karena, berapa banyak dari Anda pernah menggunakan hal-hal seperti Excel?
Gambar sebagian besar dari Anda telah, mungkin, atau akan menggunakan di beberapa titik dalam hidup Anda.
Anda akan menggunakan sesuatu seperti Excel.
Dalam rangka untuk mendapatkan data dari sebuah spreadsheet Excel atau melakukan apapun pengolahan dengan itu,
jika Anda ingin menulis sebuah program C atau program Python, program Java,
untuk menangani data yang telah disimpan di sana,
salah satu cara yang paling umum untuk mendapatkannya keluar dalam sebuah file CSV.
Dan Anda dapat membuka Excel dan ketika Anda pergi ke 'Save As' dialog,
Anda bisa keluar file CSV yang sebenarnya.
>> Berguna untuk mengetahui bagaimana menangani hal-hal ini.
Cara kerjanya adalah bahwa hal itu mirip dengan - Maksudku, itu pada dasarnya meniru spreadsheet,
di mana, seperti yang kita lihat di sini, di bagian yang sangat kiri-paling,
kita memiliki semua nama terakhir.
Jadi kita memiliki Malan, maka Hardison, dan kemudian Bowden, MacWilliam, dan kemudian Chan.
Semua nama terakhir. Dan kemudian koma memisahkan nama terakhir dari nama pertama.
David, Nate, Rob, Tommy, dan Zamyla.
Saya selalu mencampur Robby dan Tom.
Dan kemudian, akhirnya, kolom ketiga adalah alamat email.
Setelah Anda memahami bahwa, sisa dari program ini adalah cukup mudah untuk melaksanakan.
Apa yang kami lakukan dalam rangka untuk meniru struktur yang sama dalam program C kita
adalah kita telah menggunakan struktur.
Kami akan mulai bermain dengan sedikit lebih juga.
Kami melihat mereka untuk sedikit pertama di set, masalah 3 ketika kami berhadapan dengan kamus.
Tapi ini struct staf menyimpan nama belakang, nama pertama, dan email.
Sama seperti file CSV kami menyimpan.
Jadi ini hanya mengkonversi dari satu format yang lain.
Kita harus mengkonversi, dalam hal ini, sebuah struct staf ke garis,
garis dipisahkan koma, begitu saja.
Apakah itu masuk akal? Kalian semua telah mengambil kuis,
jadi saya bayangkan Anda memiliki setidaknya memiliki beberapa waktu untuk berpikir tentang hal ini.
>> Dalam fungsi menyewa, masalah meminta kita untuk mengambil di - zoom in pada Kita akan ini sedikit -
mengambil dalam struktur staf, struct staf, dengan nama s,
dan menambahkan isinya ke file staff.csv kami.
Ternyata ini cukup mudah untuk digunakan.
Kami akan jenis bermain-main dengan fungsi-fungsi sedikit lebih hari ini.
Tapi dalam kasus ini, fungsi fprintf benar-benar kunci.
Jadi dengan fprintf, kita dapat mencetak, seperti kalian telah menggunakan printf istilah keseluruhan.
Anda dapat printf baris ke file.
Jadi bukan hanya membuat panggilan printf biasa di mana Anda memberikan format string
dan kemudian Anda mengganti semua variabel dengan argumen berikut,
dengan fprintf, argumen pertama Anda adalah bukan file yang Anda ingin menulis ke.
Jika kita melihat ini dalam alat, misalnya, pria fprintf,
kita bisa melihat perbedaan antara printf dan fprintf.
Saya akan tampilannya di sini sedikit.
Jadi dengan printf, kami memberikan format string, dan kemudian argumen berikutnya
semua variabel untuk penggantian atau substitusi ke dalam format string kami.
Sedangkan dengan fprintf, argumen pertama memang ini * file bernama sungai.
>> Pindah kembali ke sini untuk kami menyewa,
kita sudah punya file streaming * kami membuka bagi kita.
Itulah yang ini baris pertama tidak, melainkan membuka file staff.csv,
itu membuka dalam modus append, dan semua yang tersisa untuk kita lakukan adalah
menulis struktur staf untuk file.
Dan, mari kita lihat, apakah saya ingin menggunakan iPad?
Saya akan menggunakan iPad. Kami memiliki kekosongan - mari kita menempatkan ini di atas meja sehingga aku bisa menulis sedikit lebih baik -
membatalkan menyewa dan dibutuhkan dalam satu argumen, struktur staf yang disebut s.
Punya kawat gigi kita, kita punya file * kami disebut file,
kami memiliki lini fopen kami diberikan kepada kita,
dan aku hanya akan menuliskannya sebagai titik karena itu sudah di pedia tersebut.
Dan kemudian pada baris berikutnya kita, kita akan membuat panggilan ke fprintf
dan kita akan lulus dalam file yang kita ingin mencetak ke,
dan kemudian kami format string, yang -
Aku akan membiarkan kalian ceritakan seperti apa.
Bagaimana dengan Anda, Stella? Apakah Anda tahu apa bagian pertama dari format string seperti?
[Stella] Saya tidak yakin. >> Jangan ragu untuk bertanya Jimmy.
Apakah Anda tahu, Jimmy?
[Jimmy] Apakah itu hanya menjadi yang terakhir? Saya tidak tahu. Saya tidak sepenuhnya yakin.
Oke >>. Bagaimana, apakah ada yang mendapatkan ini benar pada ujian?
Tidak Baiklah.
Ternyata bahwa di sini yang harus kita lakukan adalah kita ingin setiap bagian dari struktur staf kami
yang akan dicetak sebagai string ke dalam file kami.
Kami hanya menggunakan karakter penempatan string tiga waktu yang berbeda karena kami memiliki nama belakang
diikuti dengan koma, maka nama pertama diikuti dengan koma,
dan akhirnya alamat email yang diikuti - yang tidak
pas di layar saya - tapi itu diikuti oleh karakter baris baru.
Jadi aku akan menulis hanya di sana.
Dan kemudian mengikuti format string kami,
kita hanya memiliki substitusi, yang kita mengakses menggunakan notasi dot
yang kami lihat di sejumlah masalah 3.
Kita dapat menggunakan s.last, s.first, dan s.email
untuk menggantikan di tiga nilai-nilai ke format string kami.
Jadi bagaimana itu pergi? Masuk akal?
Ya? Tidak ada? Mungkin? Oke.
>> Hal terakhir yang kita lakukan setelah kita dicetak dan setelah kita membuka file kami:
setiap kali kita membuka file, kita harus selalu ingat untuk menutupnya.
Karena kalau tidak kita akan berakhir bocor memori,
menggunakan up file deskriptor.
Jadi untuk menutupnya, yang fungsinya yang kita gunakan? Daniel?
[Daniel] fclose? >> Fclose, tepatnya.
Jadi bagian terakhir dari masalah ini adalah untuk benar menutup file, menggunakan fungsi fclose,
yang hanya terlihat seperti itu.
Tidak terlalu gila.
Cool.
Jadi itulah masalahnya 33 pada kuis.
Kami akan memiliki file pasti lebih I / O datang.
Kami akan melakukan sedikit lebih dalam kuliah ini, atau di bagian hari ini,
karena itulah apa yang akan membentuk sebagian besar dari ini pset mendatang.
Mari kita beralih dari kuis pada saat ini. Ya?
>> [Charlotte]] Mengapa fclose (file) bukan fclose (staff.csv)?
>> Ah. Karena ternyata - jadi pertanyaan, yang adalah salah besar,
adalah mengapa, ketika kita menulis fclose, kita menulis fclose (file) variabel Bintang
sebagai lawan dari nama file, staff.csv? Apakah itu benar? Ya.
Jadi mari kita lihat. Jika saya beralih kembali ke laptop saya,
dan mari kita lihat fungsi fclose.
Jadi fungsi fclose menutup sungai dan dibutuhkan dalam pointer ke sungai yang kita ingin menutup,
yang bertentangan dengan nama file yang sebenarnya yang ingin kita tutup.
Dan ini adalah karena di balik layar, ketika Anda membuat panggilan ke fopen,
ketika Anda membuka file, Anda benar-benar mengalokasikan memori untuk menyimpan informasi tentang file.
Jadi Anda memiliki pointer file yang memiliki informasi tentang file tersebut,
seperti itu terbuka, ukurannya, di mana Anda berada saat ini dalam file,
sehingga Anda dapat membuat membaca dan menulis panggilan ke tempat tertentu dalam file.
Anda akhirnya menutup pointer bukan menutup nama file.
>> Ya? [Daniel] Jadi untuk menggunakan menyewa, akan Anda katakan - bagaimana cara mendapatkan input pengguna?
Apakah fprintf bertindak seperti GetString dalam arti bahwa hal itu hanya akan menunggu input pengguna
dan meminta Anda untuk mengetik ini - atau menunggu bagi Anda untuk mengetik tiga hal dalam?
Atau apakah Anda harus menggunakan sesuatu untuk melaksanakan menyewa?
>> Ya. Jadi kita tidak - pertanyaan itu, bagaimana kita mendapatkan input pengguna
dalam rangka melaksanakan menyewa? Dan apa yang kita miliki di sini adalah pemanggil menyewa,
lulus dalam struct staf dengan semua data yang tersimpan dalam struct sudah.
Jadi fprintf mampu hanya menulis bahwa data langsung ke file.
Tidak ada menunggu input pengguna.
Pengguna sudah diberikan input dengan benar memasukkannya dalam struct staf.
Dan hal, tentu saja, akan pecah jika salah satu dari mereka pointer adalah null,
jadi kita gulir kembali ke sini dan kami melihat struct kami.
Kami memiliki string terakhir, string pertama, email string.
Kita sekarang tahu bahwa semua orang benar-benar, di bawah tenda, adalah variabel char *.
Yang mungkin atau tidak mungkin menunjuk ke null.
Mereka mungkin menunjuk ke memori di heap,
mungkin memori pada stack.
Kami tidak benar-benar tahu, tetapi jika salah satu pointer adalah null, atau tidak valid,
bahwa yang pasti akan kecelakaan fungsi kami menyewa.
Itu adalah sesuatu yang agak luar cakupan ujian.
Kami tidak khawatir tentang hal itu.
Besar. Oke. Jadi pindah dari kuis.
>> Mari kita tutup pria ini, dan kita akan melihat pset 4.
Jadi jika kalian melihat spec pset, setelah Anda dapat mengaksesnya, cs50.net/quizzes,
kita akan pergi melalui beberapa masalah saat bagian.
Aku bergulir ke bawah - bagian pertanyaan dimulai pada halaman ketiga dari spec pset.
Dan bagian pertama meminta Anda untuk pergi dan menonton pendek pada mengarahkan dan pipa.
Yang agak pendek dingin, menunjukkan beberapa, trik baru baris perintah yang keren yang dapat Anda gunakan.
Dan kemudian kita punya beberapa pertanyaan untuk Anda juga.
Ini pertanyaan pertama tentang aliran, yang printf menulis secara default,
kami jenis menyentuh hanya sedikit beberapa saat yang lalu.
Ini fprintf bahwa kita hanya membahas berlangsung dalam aliran * file sebagai argumen.
fclose mengambil dalam aliran * file juga,
dan nilai kembali dari fopen memberikan aliran * file juga.
Alasan kami belum melihat mereka sebelumnya ketika kita sudah berurusan dengan printf
karena printf memiliki aliran standar.
Dan aliran default yang menulis
Anda akan mengetahui dalam jangka pendek.
Jadi jelas kita lihat itu.
>> Pada bagian hari ini, kita akan berbicara sedikit tentang GDB,
sejak lebih akrab Anda dengan itu, praktik yang Anda dapatkan dengan itu,
yang lebih mampu Anda akan benar-benar memburu bug dalam kode Anda sendiri.
Hal ini mempercepat proses debugging dengan dahsyat.
Jadi dengan menggunakan printf, setiap kali Anda melakukan itu Anda harus mengkompilasi ulang kode Anda,
Anda harus menjalankan lagi, kadang-kadang Anda harus memindahkan panggilan printf sekitar,
komentar keluar kode, itu hanya membutuhkan beberapa saat.
Tujuan kami adalah untuk mencoba dan meyakinkan Anda bahwa dengan GDB, Anda pada dasarnya dapat
printf apapun pada setiap titik dalam kode Anda dan Anda tidak perlu mengkompilasi ulang.
Anda tidak perlu untuk memulai dan terus menebak-nebak mana printf berikutnya.
Hal pertama yang harus dilakukan adalah untuk menyalin baris ini dan mendapatkan kode bagian off dari web.
Saya menyalin baris kode yang mengatakan, "http://cdn.cs50.net wget".
Aku akan menyalinnya.
Aku akan pergi ke alat saya, zoom out sehingga Anda dapat melihat apa yang saya lakukan,
paste di sana, dan ketika saya tekan Enter, perintah ini wget harfiah adalah web mendapatkan.
Ini akan pull down file ini dari Internet,
dan itu akan menyimpannya ke direktori saat ini.
Sekarang jika saya daftar direktori saat ini saya Anda dapat melihat bahwa aku punya file ini section5.zip tepat di sana.
Cara untuk berurusan dengan pria itu adalah untuk unzip,
yang dapat Anda lakukan pada command line, seperti ini.
Section5.zip.
Itu akan unzip, membuat folder untuk saya,
mengembang semua isi, menempatkan mereka di sana.
Jadi sekarang saya bisa masuk ke direktori 5 bagian saya menggunakan perintah cd.
Bersihkan layar dengan menggunakan jelas. Jadi jelas layar.
Sekarang saya punya terminal bersih yang bagus untuk menangani.
>> Sekarang jika saya daftar semua file yang saya lihat di direktori ini,
Anda melihat bahwa aku punya empat file: buggy1, buggy2, buggy3, dan buggy4.
Saya juga punya file yang sesuai. Mereka c.
Kita tidak akan melihat file c. Untuk saat ini.
Sebaliknya, kita akan menggunakannya ketika kita membuka GDB.
Kami telah membuat mereka sekitar sehingga kita memiliki akses ke kode sumber yang sebenarnya ketika kita menggunakan GDB,
tetapi tujuan ini bagian dari bagian ini adalah untuk bermain-main-main dengan GDB
dan melihat bagaimana kita dapat menggunakannya untuk mencari tahu apa yang salah dengan masing-masing dari keempat program kereta.
Jadi kita hanya akan sekitar ruangan sangat cepat,
dan aku akan meminta seseorang untuk menjalankan salah satu program kereta,
dan kemudian kami akan pergi sebagai kelompok melalui GDB, dan kita akan melihat apa yang bisa kita lakukan untuk memperbaiki program ini,
atau setidaknya mengidentifikasi apa yang salah di masing-masing dari mereka.
Mari kita mulai di sini dengan Daniel. Apakah Anda menjalankan buggy1? Mari kita lihat apa yang terjadi.
[Daniel] Ia mengatakan ada sebuah kesalahan aplikasi. >> Ya. Tepat.
Jadi jika saya menjalankan buggy1, saya mendapatkan kesalahan seg.
Pada titik ini, saya bisa pergi dan membuka buggy1.c,
mencoba dan mencari tahu apa yang salah,
tapi salah satu hal yang paling menjengkelkan tentang kesalahan kesalahan seg
adalah bahwa hal itu tidak memberitahu Anda tentang apa baris hal program yang benar-benar pergi salah dan pecah.
Anda semacam harus melihat kode
dan mencari tahu menggunakan menebak dan memeriksa atau printf untuk melihat apa yang salah.
Salah satu hal keren tentang GDB adalah bahwa itu benar-benar, benar-benar mudah
untuk mengetahui garis di mana crash program anda.
Ini benar-benar layak untuk menggunakannya, bahkan jika hanya untuk itu.
Jadi untuk boot GDB, saya ketik GDB, dan kemudian saya memberikan path ke executable yang saya ingin menjalankan.
Di sini saya sedang mengetik gdb ./buggy1.
Tekan Enter. Memberi saya semua informasi hak cipta,
dan di sini Anda akan melihat baris ini yang mengatakan, "simbol Membaca dari / home /
jharvard/section5/buggy1. "
Dan jika semuanya berjalan dengan baik, Anda akan melihatnya mencetak pesan yang terlihat seperti ini.
Ini akan membaca simbol, itu akan mengatakan "Saya membaca simbol dari file eksekusi,"
dan kemudian akan memiliki "dilakukan" pesan di sini.
Jika Anda melihat beberapa variasi lain dari ini, atau Anda melihatnya tidak bisa menemukan simbol
atau sesuatu seperti itu, apa artinya adalah bahwa Anda hanya belum dikompilasi executable Anda dengan benar.
Ketika kita mengkompilasi program untuk digunakan dengan GDB, kita harus menggunakan bendera khusus-g,
dan itu dilakukan secara default jika Anda mengkompilasi program Anda, hanya dengan mengetik membuat
atau membuat kereta atau membuat sembuh, salah satu dari mereka.
Tetapi jika Anda kompilasi secara manual dengan dentang, maka Anda akan harus pergi dalam dan termasuk bahwa-g bendera.
>> Pada titik ini, sekarang bahwa kami telah kami GDB prompt,
itu cukup sederhana untuk menjalankan program.
Kita bisa mengetik lari, atau kita hanya bisa mengetik r.
Perintah GDB Kebanyakan bisa disingkat.
Biasanya hanya satu atau beberapa surat, yang cukup bagus.
Jadi Saad, jika Anda ketik r dan tekan Enter, apa yang terjadi?
[Saad] aku SIGSEGV, kesalahan segmentasi, dan kemudian semua omong kosong ini.
>> Ya.
Seperti yang kita lihat pada layar sekarang, dan seperti Saad mengatakan,
ketika kita mengetik run atau r dan tekan Enter, kita masih mendapatkan kesalahan yang sama seg.
Jadi menggunakan GDB tidak memecahkan masalah kita.
Tapi itu memberi kita sulit dipahami beberapa, dan ternyata sulit dipahami ini
sebenarnya memberitahu kita di mana hal itu terjadi.
Untuk mengurai ini sedikit, ini sedikit pertama adalah fungsi di mana segala sesuatu yang salah.
Ada ini __ strcmp_sse4_2, dan memberitahu kita bahwa itu terjadi di file ini
disebut sysdeps/i386, semua ini, sekali lagi, agak berantakan - tapi garis 254.
Itu agak sulit untuk mengurai. Biasanya ketika Anda melihat hal-hal seperti ini,
yang berarti bahwa itu seg faulting di salah satu perpustakaan sistem.
Jadi ada hubungannya dengan strcmp. Kalian telah melihat strcmp sebelumnya.
Tidak terlalu gila, tapi apakah ini berarti bahwa strcmp rusak atau ada masalah dengan strcmp?
Apa yang Anda pikirkan, Alexander?
[Alexander] Apakah itu - adalah 254 baris? Dan - tidak biner, tapi tidak langit-langit mereka,
dan kemudian ada bahasa lain untuk setiap fungsi. Apakah itu 254 dalam fungsi itu, atau -?
>> Ini baris 254. Sepertinya dalam file ini s., Sehingga itu perakitan kode mungkin.
>> Tapi, saya kira hal yang lebih mendesak adalah, karena kita sudah kesalahan seg,
dan sepertinya itu datang dari fungsi strcmp,
hal ini menyiratkan, maka, strcmp yang rusak?
Ini tidak boleh, mudah-mudahan. Jadi hanya karena Anda memiliki kesalahan segmentasi
di salah satu fungsi sistem, biasanya itu berarti bahwa Anda hanya belum menyebutnya dengan benar.
Hal tercepat yang harus dilakukan untuk mencari tahu apa yang sebenarnya terjadi
ketika Anda melihat sesuatu yang gila seperti ini, setiap kali Anda melihat kesalahan seg,
terutama jika Anda memiliki program yang menggunakan lebih dari sekedar main,
adalah dengan menggunakan backtrace.
Saya menyingkat Backtrace dengan menulis bt, sebagai lawan dari kata backtrace penuh.
Tapi Charlotte, apa yang terjadi ketika Anda mengetik bt dan tekan Enter?
[Charlotte] Ini menunjukkan saya dua baris, baris 0 dan baris 1.
>> Ya. Jadi baris 0 dan baris 1.
Ini adalah frame tumpukan aktual yang saat ini dalam bermain ketika program anda jatuh.
Mulai dari frame paling atas, frame 0, dan pergi ke paling bawah, yaitu frame 1.
Bingkai paling atas kami adalah bingkai strcmp.
Anda dapat menganggap ini sebagai mirip dengan masalah kami hanya lakukan pada kuis dengan pointer,
di mana kami telah bertukar stack frame di atas stack frame utama,
dan kami memiliki variabel yang menggunakan swap di atas variabel yang utama menggunakan.
Di sini kami kecelakaan terjadi dalam fungsi strcmp kami, yang dipanggil oleh fungsi utama kami,
dan backtrace memberikan kita tidak hanya fungsi di mana hal-hal yang gagal,
tapi itu juga memberitahu kita di mana semuanya dipanggil dari.
Jadi jika saya gulir lebih sedikit lebih ke kanan,
kita dapat melihat bahwa ya, kami berada di jalur 254 dari file ini strcmp-sse4.s.
Tapi panggilan itu dibuat di buggy1.c, baris 6.
Jadi itu berarti bisa kita lakukan - adalah kita hanya bisa pergi memeriksa dan melihat apa yang sedang terjadi
di buggy1.c, baris 6.
Sekali lagi, ada beberapa cara untuk melakukan hal ini. Salah satunya adalah untuk keluar dari GDB
atau memiliki kode Anda terbuka di jendela lain dan referensi silang.
Bahwa, dalam dan dari dirinya sendiri, cukup berguna karena sekarang jika Anda berada di jam kantor
dan Anda punya kesalahan seg dan TF Anda bertanya-tanya di mana semuanya melanggar,
Anda hanya bisa mengatakan, "Oh, baris 6. Aku tidak tahu apa yang terjadi,
tapi sesuatu tentang jalur 6 yang menyebabkan program saya untuk istirahat. "
Cara lain untuk melakukannya adalah Anda dapat menggunakan perintah ini disebut daftar di GDB.
Anda juga dapat menyingkatnya dengan l.
Jadi jika kita memukul l, apa yang kita dapatkan di sini?
Kami mendapatkan sejumlah besar hal-hal aneh.
Ini adalah kode assembly aktual
yang ada di strcmp_sse4_2.
Hal ini terlihat agak funky,
dan alasan kita mendapatkan ini karena sekarang,
GDB memiliki kita di frame 0.
>> Jadi kapan saja kita melihat variabel, setiap kali kita melihat kode sumber,
kita sedang melihat kode sumber yang berhubungan dengan stack frame kita saat ini masuk
Jadi untuk mendapatkan sesuatu yang berarti, kita harus
pindah ke stack frame yang lebih masuk akal.
Dalam hal ini, stack frame utama akan masuk akal sedikit lebih,
karena itu benar-benar kode yang kita tulis.
Bukan kode strcmp.
Cara Anda dapat bergerak di antara frame, dalam hal ini, karena kita memiliki dua,
kita memiliki 0 dan 1,
Anda melakukannya dengan atas dan bawah perintah.
Jika saya naik satu frame,
sekarang aku di stack frame utama.
Aku bisa bergerak turun untuk kembali ke tempat saya,
naik lagi, turun lagi, dan naik lagi.
Jika Anda pernah melakukan program Anda di GDB, Anda mendapatkan kecelakaan, Anda mendapatkan backtrace,
dan Anda melihat bahwa itu dalam beberapa file yang Anda tidak tahu apa yang terjadi.
Anda mencoba daftar, kode tidak tampak akrab bagi Anda,
lihatlah frame Anda dan mencari tahu di mana Anda berada.
Kau mungkin di stack frame yang salah.
Atau setidaknya Anda berada dalam stack frame yang tidak salah satu yang Anda benar-benar dapat men-debug.
Sekarang kita berada di stack frame yang tepat, kita berada di utama,
sekarang kita dapat menggunakan perintah list untuk mencari tahu apa jalur ini.
Dan Anda bisa melihatnya, itu dicetak untuk kami di sini.
Tapi kita dapat menekan daftar semua sama, dan daftar ini memberi kita printout bagus
dari kode sumber yang sebenarnya yang terjadi di sini.
>> Secara khusus, kita dapat melihat pada baris 6.
Kita bisa melihat apa yang terjadi di sini.
Dan sepertinya kita sedang membuat perbandingan string
antara string "CS50 batu" dan argv [1].
Sesuatu tentang hal ini menerjang.
Jadi Missy, apakah Anda memiliki pemikiran tentang apa yang mungkin terjadi di sini?
[Missy] Saya tidak tahu mengapa hal itu menerjang. >> Anda tidak tahu mengapa hal itu menerjang?
Jimmy, setiap pikiran?
[Jimmy] Saya tidak sepenuhnya yakin, tapi terakhir kali kami menggunakan tali membandingkan,
atau strcmp, kami punya seperti tiga kasus yang berbeda di bawahnya.
Kami tidak memiliki ==, saya tidak berpikir, itu tepat di baris pertama.
Sebaliknya itu dipisahkan menjadi tiga, dan satu adalah == 0,
salah satu adalah <0, saya pikir, dan satu> 0.
Jadi mungkin sesuatu seperti itu? >> Ya. Jadi ada masalah ini
dari kita melakukan perbandingan dengan benar?
Stella? Setiap pikiran?
[Stella] Saya tidak yakin. >> Tidak yakin. Daniel? Pikiran? Oke.
Ternyata apa yang terjadi di sini adalah ketika kami berlari program
dan kami mendapat kesalahan seg, ketika Anda menjalankan program untuk pertama kalinya, Daniel,
kau memberikan argumen baris perintah apapun?
[Daniel] No >> No Dalam hal ini, berapakah nilai dari argv [1]?
>> Ada nilai tidak ada. >> Kanan.
Nah, tidak ada nilai string yang sesuai.
Tapi ada beberapa nilai. Apa nilai yang akan disimpan di sana?
>> Sebuah nilai sampah? >> Ini baik nilai sampah atau, dalam hal ini,
akhir dari array argv selalu diakhiri dengan null.
Jadi apa yang benar-benar mendapat disimpan di sana adalah nol.
Cara lain untuk memecahkan masalah ini, daripada berpikir melalui,
adalah untuk mencoba mencetak keluar.
Di sinilah saya katakan bahwa menggunakan GDB besar,
karena Anda bisa mencetak semua variabel, semua nilai-nilai yang Anda inginkan
menggunakan perintah ini berguna dandy-p.
Jadi jika saya ketik p dan kemudian saya ketik nilai dari suatu variabel atau nama variabel,
mengatakan, argc, saya melihat bahwa argc adalah 1.
Jika saya ingin mencetak argv [0], saya bisa melakukannya begitu saja.
Dan seperti yang kita lihat, argv [0] selalu nama program Anda,
selalu nama executable.
Disini anda melihat itu punya nama path lengkap.
Saya juga dapat mencetak argv [1] dan lihat apa yang terjadi.
>> Di sini kami mendapat semacam ini nilai mistis.
Kami punya 0x0 ini.
Ingat pada awal istilah ketika kita berbicara tentang angka heksadesimal?
Atau bahwa sedikit pertanyaan pada akhir pset 0 tentang bagaimana untuk mewakili 50 di hex?
Cara kita menulis angka hex di CS, hanya untuk tidak membingungkan diri kita sendiri
dengan angka desimal, adalah kita selalu awalan mereka dengan 0x.
Jadi ini awalan 0x selalu hanya berarti menafsirkan nomor berikut sebagai angka heksadesimal,
bukan sebagai string, bukan sebagai angka desimal, bukan sebagai bilangan biner.
Karena jumlah 5-0 adalah angka yang benar dalam heksadesimal.
Dan itu adalah nomor dalam desimal, 50.
Jadi ini hanya bagaimana kita disambiguate.
Jadi 0x0 berarti 0 heksadesimal, yang juga desimal 0, biner 0.
Hanya saja nilai 0.
Ternyata bahwa ini adalah apa yang null adalah, sebenarnya, dalam memori.
Null hanya 0.
Di sini, elemen disimpan di argv [1] adalah null.
Jadi kita mencoba untuk membandingkan kami "batu CS50" string ke string null.
Jadi dereferencing null, mencoba untuk mengakses hal-hal di nol,
mereka biasanya akan menyebabkan beberapa jenis kesalahan segmentasi atau hal-hal buruk lainnya terjadi.
Dan ternyata strcmp tidak memeriksa untuk melihat
apakah Anda telah lulus dalam nilai yang null.
Sebaliknya, ia hanya berjalan ke depan, mencoba untuk melakukan hal tersebut,
dan jika seg kesalahan, itu seg kesalahan, dan itu masalah Anda. Anda harus pergi memperbaikinya.
Benar-benar cepat, bagaimana mungkin kita memperbaiki masalah ini? Charlotte?
[Charlotte] Anda dapat memeriksa menggunakan jika.
Jadi jika argv [1] adalah null, == 0, kemudian kembali 1, atau sesuatu [dipahami].
>> Ya. Jadi itu salah satu cara yang bagus untuk melakukannya, karena kita dapat memeriksa untuk melihat,
nilai kita akan masuk ke strcmp, argv [1], apakah nol?
Jika nol itu, maka kita dapat mengatakan apa-apa, batalkan.
>> Sebuah cara yang lebih umum untuk melakukan ini adalah dengan menggunakan nilai argc.
Anda dapat melihat di sini pada awal main,
kita menghilangkan bahwa tes pertama yang kita lakukan ketika kita biasanya menggunakan argumen baris perintah,
yaitu untuk menguji apakah atau tidak nilai argc kita adalah apa yang kita harapkan.
Dalam kasus ini, kami mengharapkan setidaknya dua argumen,
nama program ditambah satu lainnya.
Karena kita akan menggunakan argumen kedua di sini.
Jadi memiliki beberapa jenis tes terlebih dahulu, sebelum panggilan strcmp kami
bahwa tes apakah atau tidak argv setidaknya 2, juga akan melakukan hal yang sama.
Kita bisa melihat apakah yang bekerja dengan menjalankan program lagi.
Anda selalu dapat me-restart program anda dalam GDB, yang benar-benar bagus.
Anda dapat menjalankan, dan ketika Anda lulus dalam argumen untuk program anda,
Anda melewati mereka di saat Anda menelepon dijalankan, bukan ketika anda boot up GDB.
Dengan cara itu Anda dapat menyimpan invoking program anda dengan argumen yang berbeda setiap kali.
Jadi jalankan, atau lagi, saya bisa mengetik r, dan mari kita lihat apa yang terjadi jika kita ketik "halo".
Ini akan selalu menanyakan apakah Anda ingin memulainya dari awal lagi.
Biasanya, Anda ingin memulainya dari awal lagi.
Dan pada titik ini, restart lagi, ia akan mencetak
program yang kita jalankan, buggy1, dengan argumen halo,
dan mencetak ini keluar standar, ia mengatakan, "Anda mendapatkan D," wajah sedih.
Tapi kita tidak seg kesalahan. Dikatakan proses yang keluar normal.
Sehingga terlihat cukup bagus.
Tidak ada kesalahan yang lebih seg, kami berhasil melewati,
sehingga terlihat seperti itu memang bug kesalahan seg bahwa kita mendapatkan.
Sayangnya, ia memberitahu kita bahwa kita mendapatkan D.
>> Kita bisa kembali dan melihat kode dan melihat apa yang terjadi di sana
untuk mencari tahu apa itu - mengapa hal itu mengatakan kepada kita bahwa kita mendapat D.
Mari kita lihat, di sini adalah ini printf mengatakan bahwa Anda mendapat D.
Jika kita ketik daftar, Anda tetap daftar mengetik, itu terus iterasi turun melalui program anda,
sehingga akan menunjukkan beberapa baris pertama dari program Anda.
Kemudian akan menunjukkan beberapa baris berikutnya, dan berikutnya dan potongan potongan berikutnya.
Dan itu akan terus mencoba untuk turun.
Dan sekarang kita akan sampai ke "garis nomor 16 adalah di luar jangkauan."
Karena hanya memiliki 15 baris.
Jika Anda sampai ke titik ini dan Anda bertanya-tanya, "Apa yang harus saya lakukan?" Anda dapat menggunakan perintah bantuan.
Gunakan bantuan dan kemudian memberikan nama perintah.
Dan Anda melihat GDB memberi kita semua hal semacam ini.
Ia mengatakan, "Dengan tidak ada argumen, daftar sepuluh baris lagi setelah atau sekitar listing sebelumnya.
Daftar - daftar sepuluh baris sebelum - "
Jadi mari kita coba gunakan dikurangi daftar.
Dan itu daftar 10 baris sebelumnya, Anda dapat bermain-main dengan daftar sedikit.
Anda dapat melakukan daftar, daftar -, Anda bahkan dapat memberikan daftar nomor, seperti daftar 8,
dan itu akan mencantumkan 10 baris sekitar baris 8.
Dan Anda dapat melihat apa yang terjadi di sini adalah Anda punya sederhana jika yang lain.
Jika Anda mengetik CS50 batu, ia akan mencetak "Anda mendapatkan nilai A."
Kalau tidak mencetak "Anda mendapatkan D."
Nyebelin kota. Baiklah. Ya?
>> [Daniel] Jadi ketika saya mencoba melakukan CS50 batu tanpa tanda kutip,
ia mengatakan "Anda mendapatkan D."
Aku butuh tanda kutip untuk mendapatkannya bekerja, kenapa begitu?
>> Ya. Ternyata bahwa ketika - ini merupakan berita gembira kecil yang menyenangkan -
ketika Anda menjalankan program, jika kita menjalankannya dan kita ketik di CS50 batu,
seperti Daniel mengatakan dia lakukan, dan Anda tekan Enter,
masih mengatakan kita mendapatkan D.
Dan pertanyaannya adalah, mengapa ini?
Dan ternyata bahwa baik terminal dan GDB mengurai ini sebagai dua argumen yang terpisah.
Karena ketika ada ruang, yang menyiratkan
argumen pertama berakhir, argumen berikutnya akan dimulai.
Cara untuk menggabungkan mereka menjadi dua, atau maaf, menjadi satu argumen,
adalah dengan menggunakan tanda kutip.
Jadi sekarang, jika kita memasukkannya ke dalam tanda kutip dan menjalankannya lagi, kita mendapatkan nilai A.
Jadi hanya untuk rekap, tanpa tanda kutip, CS50 dan batu diurai sebagai dua argumen yang terpisah.
Dengan tanda kutip, itu diuraikan sebagai satu argumen sama sekali.
>> Kita bisa melihat ini dengan breakpoint.
Sejauh ini kita sudah menjalankan program kami, dan itu sudah berjalan
sampai baik itu seg kesalahan atau hits kesalahan
atau sampai telah keluar dan semua telah benar-benar baik-baik saja.
Ini tidak selalu hal yang paling membantu, karena kadang-kadang
Anda memiliki kesalahan dalam program Anda, tapi itu tidak menyebabkan kesalahan segmentasi.
Ini tidak menyebabkan program Anda untuk berhenti atau sesuatu seperti itu.
Cara untuk mendapatkan GDB untuk menghentikan program Anda pada titik tertentu
adalah untuk mengatur breakpoint.
Anda dapat melakukan ini dengan menetapkan breakpoint pada nama fungsi
atau Anda dapat mengatur breakpoint pada baris tertentu dari kode.
Saya ingin mengatur breakpoint pada nama fungsi, karena - mudah diingat,
dan jika Anda benar-benar masuk dan mengubah kode sumber Anda naik sedikit,
maka breakpoint Anda benar-benar akan tinggal di tempat yang sama dalam kode Anda.
Sedangkan jika Anda menggunakan nomor baris, dan nomor baris berubah
karena Anda menambahkan atau menghapus beberapa kode, maka breakpoints Anda semua benar-benar kacau.
Salah satu hal yang paling umum yang saya lakukan adalah mengatur breakpoint pada fungsi utama.
Sering saya akan boot GDB, saya akan ketik b utama, tekan Enter, dan itu akan mengatur breakpoint
pada fungsi utama yang hanya mengatakan, "Jeda program segera setelah Anda mulai berjalan,"
dan dengan cara itu, ketika saya menjalankan program saya dengan, katakanlah, CS50 batu sebagai dua argumen
dan tekan Enter, sampai ke fungsi utama dan berhenti tepat di baris pertama,
tepat sebelum mengevaluasi fungsi strcmp.
>> Karena aku berhenti, sekarang saya bisa mulai penyia-nyiaan waktu dan melihat apa yang terjadi
dengan semua variabel yang berbeda yang masuk ke program saya.
Di sini saya bisa mencetak argc dan melihat apa yang terjadi.
Lihat bahwa argc adalah 3, karena itu punya 3 nilai yang berbeda di dalamnya.
Itu punya nama program, itu punya argumen pertama dan argumen kedua.
Kami dapat mencetak mereka keluar dengan melihat argv [0], argv [1], dan argv [2].
Jadi sekarang Anda juga dapat melihat mengapa ini panggilan strcmp akan gagal,
karena Anda melihat bahwa hal itu berpisah CS50 dan batu-batu menjadi dua argumen terpisah.
Pada titik ini, setelah Anda menekan breakpoint, Anda dapat terus melangkah melalui program anda
baris demi baris, sebagai lawan memulai program Anda lagi.
Jadi jika Anda tidak ingin untuk memulai program Anda lagi dan hanya melanjutkan dari sini,
Anda dapat menggunakan perintah berlanjut dan terus akan menjalankan program sampai akhir.
Sama seperti itu di sini.
Namun, jika saya restart program, CS50 batu, hits breakpoint saya lagi,
dan kali ini, jika saya tidak ingin hanya pergi semua jalan melalui sisa program,
Saya dapat menggunakan perintah selanjutnya, yang saya juga menyingkat dengan n.
Dan ini akan melangkah melalui program baris demi baris.
Sehingga Anda dapat menonton sebagai hal-hal mengeksekusi, sebagai perubahan variabel, sebagai hal-hal bisa diperbarui.
Yang cukup bagus.
Hal menarik lainnya adalah daripada mengulangi perintah yang sama berulang-ulang,
jika Anda hanya tekan Enter - jadi di sini Anda melihat saya tidak diketik dalam segala hal -
jika saya hanya tekan Enter, maka akan mengulang perintah sebelumnya,
atau perintah GDB sebelumnya yang saya hanya menaruh masuk
Aku bisa terus menekan Enter dan akan terus melangkah melalui baris kode saya demi baris.
Saya akan mendorong kalian untuk pergi memeriksa program kereta lain juga.
Kami tidak punya waktu untuk melewati semua dari mereka hari ini di bagian.
Kode sumber yang ada, sehingga Anda dapat melihat jenis apa yang terjadi
di balik layar jika Anda benar-benar terjebak,
tapi setidaknya, hanya berlatih boot up GDB,
menjalankan program sampai rusak pada Anda,
mendapatkan backtrace, mencari tahu apa fungsi kecelakaan itu di,
apa garis itu pada, mencetak beberapa nilai variabel,
hanya sehingga Anda bisa merasakan hal itu, karena itu benar-benar akan membantu Anda maju.
Pada titik ini, kita akan berhenti keluar dari GDB, yang Anda lakukan dengan menggunakan berhenti atau hanya q.
Jika program Anda adalah di tengah-tengah berjalan masih, dan belum keluar,
selalu akan meminta Anda, "Apakah Anda yakin Anda benar-benar ingin berhenti?"
Anda hanya dapat menekan yes.
>> Sekarang kita akan melihat masalah berikutnya yang kita miliki, yang merupakan program kucing.
Jika Anda menonton pendek pada mengarahkan dan pipa, Anda akan melihat bahwa Tommy menggunakan program ini
yang pada dasarnya mencetak semua output dari file ke layar.
Jadi jika saya menjalankan kucing, ini sebenarnya adalah sebuah program built-in untuk alat,
dan jika Anda memiliki Mac Anda dapat melakukan ini pada Mac Anda juga, jika Anda membuka terminal.
Dan kita - kucing, katakanlah, cp.c, dan tekan Enter.
Apa ini lakukan, jika kita gulir ke atas sedikit dan melihat di mana kita berlari garis,
atau di mana kita menjalankan perintah cat, itu benar-benar hanya dicetak isi cp.c ke layar kami.
Kita bisa menjalankannya lagi dan Anda dapat dimasukkan ke dalam beberapa file bersama-sama.
Sehingga Anda dapat melakukan cp.c kucing, dan kemudian kita juga dapat menggabungkan file cat.c,
yang merupakan program kita akan menulis,
dan itu akan mencetak kedua file kembali untuk kembali ke layar kami.
Jadi jika kita gulir ke atas sedikit, kita melihat bahwa ketika kita berlari ini cp.c kucing, cat.c,
pertama dicetak file cp, dan kemudian di bawahnya, itu dicetak file cat.c sampai di sini.
Kita akan menggunakan ini untuk hanya mendapatkan kaki kami basah.
Bermain-main dengan pencetakan sederhana untuk terminal, melihat bagaimana yang bekerja.
Jika kalian membuka dengan gedit cat.c, tekan Enter,
Anda dapat melihat program yang kita akan menulis.
Kami telah menyertakan ini piring boiler yang bagus, sehingga kita tidak perlu menghabiskan waktu mengetik semua bahwa.
Kami juga memeriksa jumlah argumen berlalu masuk
Kami mencetak pesan penggunaan yang bagus.
>> Ini adalah semacam hal yang, sekali lagi, seperti yang telah kita bicarakan,
itu hampir seperti memori otot.
Tapi ingatlah untuk terus melakukan jenis yang sama hal-hal
dan selalu mencetak semacam pesan membantu
sehingga orang tahu bagaimana untuk menjalankan program Anda.
Dengan kucing, itu cukup sederhana, kita hanya akan pergi melalui semua argumen yang berbeda
yang dikirimkan ke program kami, dan kami akan mencetak
mereka isinya keluar ke layar satu per satu.
Dalam rangka untuk mencetak file ke layar, kita akan melakukan sesuatu yang sangat mirip
dengan apa yang kita lakukan pada akhir kuis.
Pada akhir kuis, yang mempekerjakan program, kami harus membuka file,
dan kemudian kami harus mencetak.
Dalam kasus ini, kita akan membuka file, dan kita akan membaca dari itu sebagai gantinya.
Kemudian kita akan mencetak, bukan ke file, kita akan mencetak ke layar.
Jadi mencetak ke layar Anda semua telah dilakukan sebelumnya dengan printf.
Sehingga tidak terlalu gila.
Tapi membaca file agak aneh.
Kita akan pergi melalui sedikit pada suatu waktu.
Jika kalian kembali ke masalah terakhir pada kuis Anda, masalah 33,
baris pertama yang akan kita lakukan di sini, membuka file, sangat mirip dengan apa yang kita lakukan di sana.
Jadi Stella, apa yang terlihat baris seperti, ketika kita membuka file?
[Stella] Capital FILE *, file - >> Oke. >> - Sama dengan fopen. >> Yup.
Yang dalam hal ini? Ada dalam komentar.
>> Ada dalam komentar? argv [i] dan r?
>> Tepat. Tepat. Jadi Stella yang benar-benar benar.
Ini adalah apa yang akan tampak seperti ini.
Kita akan mendapatkan variabel file stream, menyimpannya dalam sebuah * FILE, sehingga semua topi,
FILE, *, dan nama variabel ini akan menjadi file.
Kita bisa menyebutnya apa saja yang kita sukai. Kita bisa menyebutnya first_file, atau file_i, apa pun yang kita ingin.
Dan kemudian nama file disahkan dalam pada baris perintah untuk program ini.
Jadi itu disimpan di argv [i,] dan kemudian kita akan membuka file ini dalam mode baca.
Sekarang kami telah membuka file tersebut, apa hal yang kita harus selalu ingat untuk melakukan
setiap kali kita telah membuka file? Menutupnya.
Jadi Missy, bagaimana kita menutup file?
[Missy] fclose (file) >> fclose (file). Tepat.
Besar. Oke. Jika kita melihat ini untuk melakukan komentar di sini,
ia mengatakan, "Buka argv [i] dan mencetak isinya ke stdout."
>> Keluar standar adalah nama yang aneh. Stdout hanyalah cara kami mengatakan
kita ingin mencetak ke terminal, kami ingin mencetak ke output stream standar.
Kami benar-benar bisa menyingkirkan komentar ini di sini.
Aku akan menyalinnya dan tempel karena itulah apa yang kami lakukan.
Pada titik ini, sekarang kita harus membaca bit file dengan bit.
Kami telah membahas beberapa cara membaca file.
Mana yang favorit Anda sejauh ini?
Yang cara yang telah Anda lihat atau apakah Anda ingat, untuk membaca file?
[Daniel] fread? >> Fread? Jadi fread adalah satu. Jimmy, kau tahu orang lain?
[Jimmy] No >> Oke. Nope. Charlotte? Alexander? Setiap orang lain? Oke.
Jadi yang lain fgetc, adalah salah satu yang akan kita gunakan banyak.
Ada juga fscanf, kalian melihat pola di sini?
Mereka semua dimulai dengan f. Ada hubungannya dengan file.
Ada fread, fgetc, fscanf. Ini adalah semua fungsi membaca.
Untuk menulis kita memiliki fwrite, kita memiliki fputc bukan fgetc.
Kami juga telah fprintf seperti kita lihat pada kuis.
Karena ini adalah masalah yang melibatkan membaca dari sebuah file,
kita akan menggunakan salah satu dari tiga fungsi.
Kami tidak akan menggunakan fungsi-fungsi di sini.
Fungsi-fungsi ini yang ditemukan di perpustakaan I / O standar.
Jadi jika Anda melihat di bagian atas program ini,
Anda dapat melihat bahwa kita sudah termasuk file header untuk perpustakaan I / O standar.
Jika kita ingin mencari tahu mana yang kita ingin gunakan,
kita selalu dapat membuka halaman manual.
Jadi kita bisa mengetik stdio man
dan membaca semua tentang input dan output fungsi stdio di C.
Dan kita sudah bisa melihat oh, lihat. Ini menyebutkan fgetc, itu menyebutkan fputc.
Jadi, Anda dapat menelusuri sedikit dan melihat, katakanlah, fgetc
dan melihat halaman manual.
Anda dapat melihat bahwa ia pergi bersama dengan sejumlah fungsi lainnya:
fgetc, fgets, getc, getchar, mendapat, ungetc, dan input karakter dan string.
Jadi ini adalah bagaimana kita membaca dalam karakter dan string dari file dari input standar,
yang pada dasarnya dari pengguna.
Dan ini adalah bagaimana kita melakukannya di C. aktual
Jadi ini tidak menggunakan GetString dan fungsi getchar
yang kita gunakan dari perpustakaan CS50.
Kami akan melakukan masalah ini dalam beberapa cara
sehingga Anda dapat melihat dua cara yang berbeda untuk melakukannya.
Kedua fungsi fread bahwa Daniel disebutkan dan fgetc adalah cara yang baik untuk melakukannya.
Saya pikir fgetc adalah sedikit lebih mudah, karena hanya memiliki, seperti yang Anda lihat,
satu argumen, satu * FILE yang kita mencoba membaca karakter dari,
dan nilai kembalinya adalah int.
Dan ini adalah sedikit membingungkan, bukan?
>> Karena kita sedang mendapatkan karakter, jadi mengapa tidak kembali ini char?
Kalian punya ide tentang mengapa hal ini tidak mungkin kembali char?
[Missy jawaban, tidak dapat dipahami] >> Ya. Jadi Missy yang benar-benar benar.
Jika itu ASCII, maka bilangan bulat ini dapat dipetakan ke sebuah char yang sebenarnya.
Bisa jadi karakter ASCII, dan itu benar.
Itulah apa yang terjadi.
Kami menggunakan int hanya karena memiliki lebih banyak bit.
Ini lebih besar dari char, Char kami hanya memiliki 8 bit, bahwa 1 byte pada 32-bit mesin kami.
Dan int memiliki nilai semua 4 byte 'ruang.
Dan ternyata jalan fgetc bekerja,
jika kita scroll ke bawah dalam sinopsis kami di halaman manual sedikit,
gulir semua jalan ke bawah. Ternyata bahwa mereka menggunakan nilai khusus yang disebut EOF.
Ini adalah konstanta khusus sebagai nilai kembali dari fungsi fgetc
setiap kali anda menekan akhir file atau jika Anda mendapatkan pesan kesalahan.
Dan ternyata untuk melakukan perbandingan ini dengan EOF benar,
Anda ingin memiliki jumlah tambahan informasi yang Anda miliki dalam sebuah int
sebagai lawan menggunakan variabel char.
Meskipun fgetc secara efektif mendapatkan karakter dari sebuah file,
Anda ingin mengingat bahwa itu adalah kembali sesuatu yang bertipe int untuk Anda.
Yang mengatakan, itu cukup mudah digunakan.
Ini akan memberi kita sebuah karakter, maka yang harus kita lakukan adalah terus bertanya file,
"Berikan karakter berikutnya, memberi saya karakter berikutnya, memberi saya karakter berikutnya,"
sampai kita sampai ke akhir file.
Dan itu akan menarik salah satu karakter pada satu waktu dari file kami,
dan kemudian kita bisa melakukan apapun yang kita suka dengan itu.
Kita bisa menyimpannya, kita dapat menambahkannya ke string, kita bisa mencetaknya.
Melakukan semua itu.
>> Zooming kembali dan akan kembali ke program cat.c kami,
jika kita akan menggunakan fgetc,
bagaimana mungkin kita mendekati baris berikutnya kode?
Kita akan menggunakan - fread akan melakukan sesuatu yang sedikit berbeda.
Dan kali ini, kita hanya akan menggunakan fgetc untuk mendapatkan satu karakter pada satu waktu.
Untuk memproses seluruh file, apa yang mungkin harus kita lakukan?
Berapa banyak karakter yang ada di file?
Ada banyak. Jadi Anda mungkin ingin mendapatkan satu
dan kemudian mendapatkan lain dan mendapatkan lain dan mendapatkan lain.
Apa jenis algoritma yang Anda pikir kita mungkin harus menggunakan di sini?
Apa jenis -? [Alexander] A untuk loop? >> Tepat.
Beberapa jenis loop.
Sebuah untuk loop sebenarnya besar, dalam kasus ini.
Dan seperti yang Anda katakan, kedengarannya seperti Anda ingin loop atas seluruh file,
mendapatkan karakter pada satu waktu.
Ada saran tentang apa yang mungkin terlihat seperti?
[Alexander, tidak dapat dipahami]
>> Oke, katakan saja padaku dalam bahasa Inggris apa yang Anda coba lakukan? [Alexander, tidak dapat dipahami]
Jadi dalam hal ini, kedengarannya seperti kami hanya mencoba untuk loop atas seluruh file.
[Alexander] Jadi i > Ukuran -?
Saya kira ukuran file, kan? Ukuran - kami hanya menulis seperti ini.
Ukuran file untuk saat ini, i + +.
Jadi ternyata bahwa cara Anda melakukan hal ini menggunakan fgetc, dan ini baru,
adalah bahwa tidak ada cara mudah untuk hanya mendapatkan ukuran file
dengan tipe "sizeof" dari membangun yang telah Anda lihat sebelumnya.
Ketika kita menggunakan fungsi fgetc, kami memperkenalkan beberapa jenis
baru sintaks, funky ini untuk loop, di mana bukan hanya menggunakan counter dasar
untuk pergi karakter demi karakter, kita akan menarik salah satu karakter pada satu waktu,
satu karakter pada satu waktu, dan cara kita tahu bahwa kita berada di akhir
tidak ketika kita telah menghitung sejumlah karakter,
tetapi ketika karakter kita tarik keluar adalah bahwa akhir khusus karakter file.
Jadi kita bisa melakukan ini dengan - saya sebut ch ini, dan kita akan menginisialisasi
dengan panggilan pertama kami untuk mendapatkan karakter pertama dari file tersebut.
Jadi bagian ini di sini, ini akan mendapatkan karakter keluar dari file
dan menyimpannya ke dalam variabel ch.
Kita akan terus melakukan hal ini sampai kita sampai ke akhir file,
yang kita lakukan dengan tes karakter tidak menjadi sama dengan karakter EOF khusus.
Dan kemudian bukannya melakukan ch + +, yang hanya akan kenaikan nilai,
jadi jika kita membaca keluar Sebuah file, modal A, katakanlah,
ch + + akan memberi kita b, dan kemudian kita akan mendapatkan c dan kemudian d.
Itu jelas bukan apa yang kita inginkan. Apa yang kita inginkan di sini
dalam bit terakhir ini kita ingin mendapatkan karakter berikutnya dari file tersebut.
>> Jadi bagaimana mungkin kita mendapatkan karakter berikutnya dari file tersebut?
Bagaimana kita mendapatkan karakter pertama dari file tersebut?
[Mahasiswa] fgetfile? >> Fgetc, atau, maaf, kau benar-benar benar.
Saya salah eja itu di sana. Jadi ya.
Di sini bukannya melakukan ch + +,
kami hanya akan memanggil fgetc (file) lagi
dan menyimpan hasilnya dalam variabel ch yang sama kami.
[Pertanyaan Mahasiswa, dipahami]
>> Sinilah orang FILE * ini adalah khusus.
Cara mereka bekerja adalah mereka - ketika Anda pertama kali membuka - ketika Anda pertama kali membuat panggilan fopen,
* FILE yang efektif berfungsi sebagai pointer ke awal file.
Dan kemudian setiap kali Anda menelepon fgetc, bergerak satu karakter melalui file.
Jadi setiap kali Anda menyebutnya, Anda incrementing pointer file dengan satu karakter.
Dan ketika Anda fgetc lagi, Anda bergerak karakter lain
dan lain karakter dan karakter lain dan karakter lain.
[Pertanyaan Mahasiswa, dipahami] >> Dan ltu - ya.
Ini semacam sihir ini di bawah tenda.
Anda hanya terus incrementing melalui.
Pada titik ini, Anda dapat benar-benar bekerja dengan karakter.
Jadi bagaimana mungkin kita mencetak ini ke layar, sekarang?
Kita dapat menggunakan hal printf sama yang kita gunakan sebelumnya.
Bahwa kita telah menggunakan semua semester.
Kita dapat memanggil printf,
dan kita bisa lulus dalam karakter seperti itu.
Cara lain untuk melakukannya adalah daripada menggunakan printf dan harus melakukan hal ini format string,
kita juga dapat menggunakan salah satu fungsi lainnya.
Kita dapat menggunakan fputc, yang mencetak karakter ke layar,
kecuali jika kita melihat fputc - biarkan aku tampilannya keluar sedikit.
Kami melihat apa yang baik adalah yang dibutuhkan dalam karakter yang kita baca dengan menggunakan fgetc,
tapi kemudian kita harus memberikan aliran untuk mencetak ke.
Kita juga bisa menggunakan fungsi putchar, yang akan dimasukkan langsung ke luar standar.
Jadi ada sejumlah pilihan yang berbeda yang dapat kita gunakan untuk mencetak.
Mereka semua di perpustakaan I / O standar.
Setiap kali Anda ingin mencetak - sehingga printf, secara default, akan mencetak dengan standar khusus keluar sungai,
yang stdout itu.
Jadi kita hanya bisa menyebutnya sebagai semacam ini nilai sihir, stdout di sini.
Ups. Menempatkan koma luar.
>> Ini adalah banyak yang baru, informasi yang funky di sini.
Banyak ini sangat idiomatic, dalam arti bahwa ini adalah kode
yang ditulis dengan cara ini hanya karena bersih untuk membaca, mudah dibaca.
Ada banyak cara yang berbeda untuk melakukannya, fungsi yang berbeda yang dapat Anda gunakan,
tetapi kita cenderung hanya mengikuti pola-pola yang sama berulang-ulang.
Jadi jangan heran jika Anda melihat kode seperti ini datang lagi dan lagi.
Baiklah. Pada titik ini, kita perlu istirahat untuk hari.
Terima kasih untuk datang. Terima kasih untuk menonton jika Anda sedang online. Dan kita akan melihat Anda minggu depan.
[CS50.TV]