[Powered by Google Translate] [CS50 Perpustakaan]
[Nate Hardison] [Universiti Harvard]
[Ini adalah CS50. CS50.TV]
Perpustakaan CS50 adalah alat yang berguna yang kita telah dipasang pada perkakas
untuk membuat ia lebih mudah bagi anda untuk menulis program yang pengguna segera untuk input.
Dalam video ini, kita akan tarik balik tirai dan melihat apa yang sebenarnya adalah di perpustakaan CS50.
>> Dalam video di perpustakaan C, kita bercakap tentang bagaimana anda # include pengepala fail
perpustakaan dalam kod sumber anda,
dan kemudian anda dihubungkan dengan fail perpustakaan binari semasa fasa yang menghubungkan
proses penyusunan.
Fail-fail header menentukan antara muka perpustakaan.
Iaitu, mereka terperinci semua sumber bahawa perpustakaan mempunyai tersedia untuk anda gunakan,
seperti pengisytiharan fungsi, pemalar, dan jenis data.
Fail perpustakaan binari mengandungi pelaksanaan perpustakaan,
yang disusun dari fail header perpustakaan dan perpustakaan. c kod fail sumber.
>> Fail perpustakaan binari tidak sangat menarik untuk melihat kerana ia adalah, baik, dalam perduaan.
Jadi, mari kita lihat pada fail header untuk perpustakaan dan bukannya.
Dalam kes ini, hanya terdapat satu fail header dipanggil cs50.h.
Kami telah dipasang dalam pengguna termasuk direktori
bersama-sama dengan fail header perpustakaan sistem lain '.
>> Salah satu perkara pertama yang anda akan notis adalah bahawa cs50.h # termasuk fail header dari perpustakaan lain -
apungan, had, standard bool, dan lib standard.
Sekali lagi, berikutan prinsip tidak Reinventing roda,
kami telah membina perpustakaan CS0 menggunakan alat yang lain yang disediakan untuk kita.
>> Perkara seterusnya yang anda akan melihat di perpustakaan adalah bahawa kita menentukan jenis baru yang dipanggil "tali."
Keturunan ini benar-benar hanya mewujudkan alias untuk jenis * char,
supaya ia tidak ajaib pengajaran jenis rentetan baru dengan sifat-sifat
sering dikaitkan dengan objek rentetan dalam bahasa-bahasa lain,
seperti panjang.
Sebab kita telah melakukan ini adalah untuk melindungi pengaturcara baru dari butiran ngeri
petunjuk sehingga mereka sudah bersedia.
>> Bahagian seterusnya fail header adalah pengisytiharan fungsi
bahawa perpustakaan CS50 menyediakan bersama-sama dengan dokumentasi.
Notis tahap terperinci dalam komen-komen di sini.
Ini adalah sangat penting supaya orang tahu bagaimana untuk menggunakan fungsi ini.
Kami mengaku, pada gilirannya, berfungsi untuk segera turun dan aksara pulangan, beregu, pelampung, ints,
panjang Roh meronta-ronta, dan tali, menggunakan jenis tali kita sendiri.
Berikutan prinsip menyembunyikan maklumat,
kami telah meletakkan definisi kami dalam fail berasingan pelaksanaan c - cs50.c -
terletak dalam direktori sumber pengguna.
Kami telah menyediakan fail tersebut supaya anda boleh mengambil melihat pada ia,
belajar daripadanya, dan susun semula pada mesin yang berbeza jika anda mahu,
walaupun kita fikir ia adalah lebih baik untuk bekerja pada perkakas untuk kelas ini.
Bagaimanapun, mari kita melihat pada ia sekarang.
>> Fungsi GetChar, GetDouble, GetFloat, GetInt, dan GetLongLong
semua dibina di atas fungsi GetString.
Ia ternyata bahawa mereka semua mengikuti dasarnya corak yang sama.
Mereka menggunakan gelung sementara untuk segera turun satu baris input.
Mereka kembali nilai istimewa jika pengguna input satu baris kosong.
Mereka cuba untuk menghuraikan input pengguna sebagai jenis yang sesuai,
char, dua, apungan, dan lain-lain
Dan kemudian mereka sama ada memulangkan hasilnya jika input telah berjaya dipecah
atau mereka reprompt pengguna.
>> Pada tahap yang tinggi, tidak ada yang benar-benar sukar di sini.
Anda mungkin telah ditulis kod sama berstruktur diri anda pada masa lalu.
Mungkin bahagian yang paling samar-cari adalah panggilan sscanf yang mem-parsing input pengguna.
Sscanf adalah sebahagian daripada keluarga input penukaran format.
Ia tinggal di io.h standard, dan tugasnya adalah untuk menghuraikan rentetan C,
mengikut format tertentu, menyimpan keputusan menghuraikan dalam pembolehubah
disediakan oleh pemanggil.
Sejak fungsi input penukaran format yang sangat berguna, digunakan secara meluas fungsi
yang tidak intuitif super pada mulanya,
kami akan pergi lebih bagaimana sscanf berfungsi.
>> Hujah pertama ke sscanf adalah * char - penunjuk kepada watak.
Bagi fungsi untuk berfungsi dengan betul,
watak yang harus menjadi watak pertama rentetan C,
ditamatkan dengan nol \ watak 0.
Ini adalah rentetan untuk menghuraikan
Hujah kedua ke sscanf adalah rentetan format,
biasanya diluluskan sebagai pemalar rentetan,
dan anda mungkin telah melihat rentetan seperti sebelum ini apabila menggunakan printf.
Satu tanda peratus dalam rentetan format menunjukkan specifier penukaran.
Watak sejurus selepas tanda peratus,
menunjukkan jenis C yang kita mahu sscanf untuk menukar.
Di GetInt itu, anda lihat bahawa terdapat% d dan c%.
Ini bermakna bahawa sscanf akan cuba untuk perpuluhan int - d% - dan char - c%.
Untuk specifier penukaran setiap satu dalam rentetan format,
sscanf menjangka hujah yang sepadan kemudian dalam senarai hujah.
Hujah bahawa mesti menunjukkan lokasi yang sesuai ditaip
di mana untuk menyimpan hasil penukaran.
>> Cara biasa untuk melakukan ini adalah untuk mewujudkan pemboleh ubah pada timbunan sebelum panggilan sscanf
bagi setiap item yang anda mahu untuk menghuraikan daripada rentetan
dan kemudian gunakan pengendali alamat - #: glib - untuk lulus petunjuk
kepada pembolehubah panggilan sscanf.
Anda boleh melihat bahawa dalam GetInt kita lakukan betul-betul ini.
Hak sebelum panggilan sscanf, kita mengisytiharkan int dipanggil n dan c panggilan char pada timbunan,
dan kita lulus petunjuk untuk mereka ke panggilan sscanf.
Meletakkan pembolehubah pada timbunan digemari berbanding menggunakan ruang yang diperuntukkan
pada timbunan dengan malloc, kerana anda mengelakkan overhed panggilan malloc,
dan anda tidak perlu bimbang tentang bocor memori.
Aksara tidak awalan tanda peratus tidak meminta penukaran.
Sebaliknya mereka hanya menambah spesifikasi format.
>> Sebagai contoh, jika rentetan format di GetInt% d sebaliknya,
sscanf akan mencari surat yang diikuti oleh int,
dan manakala ia akan cuba untuk menukar int, ia tidak akan berbuat apa-apa lagi dengan.
Satunya pengecualian kepada ini adalah ruang kosong.
Aksara ruang putih dalam rentetan format sepadan dengan mana-mana jumlah ruang kosong -
walaupun tiada pada semua.
Jadi, itulah mengapa komen menyebut mungkin dengan membawa dan / atau ketinggalan ruang kosong.
Jadi, pada ketika ini ia kelihatan seperti panggilan sscanf kami akan cuba untuk menghuraikan rentetan input pengguna
dengan memeriksa mungkin ruangputih putih terkemuka,
diikuti oleh int yang akan ditukar dan disimpan dalam pembolehubah int n
diikuti oleh beberapa jumlah ruang kosong, dan diikuti oleh watak
disimpan dalam c ubah char.
>> Bagaimana tentang nilai pulangan?
Sscanf akan menghuraikan baris input dari awal hingga akhir,
berhenti apabila ia sampai akhir atau apabila watak dalam input
tidak sepadan dengan watak format atau apabila ia tidak boleh membuat penukaran.
Nilai pulangan Ia digunakan untuk satu apabila ia berhenti.
Jika ia berhenti, kerana ia sampai ke penghujung tali input
sebelum membuat apa-apa penukaran dan sebelum gagal untuk memadankan sebahagian rentetan format,
maka EOF berterusan khas dikembalikan.
Jika tidak, ia akan mengembalikan bilangan penukaran yang berjaya,
yang boleh menjadi 0, 1, atau 2, kerana kami telah diminta untuk dua penukaran.
Dalam kes kami, kami ingin memastikan bahawa pengguna ditaip dalam int dan hanya int.
>> Jadi, kita mahu sscanf untuk kembali 1. Lihat mengapa?
Jika sscanf kembali 0, maka tiada penukaran telah dibuat,
jadi pengguna menaip sesuatu yang lain daripada int pada permulaan input.
Jika sscanf kembali 2, maka pengguna tidak betul taip dalam pada permulaan input,
tetapi mereka kemudian ditaip dalam watak beberapa bukan ruang putih selepas itu
sejak% c penukaran berjaya.
Wow, itu penjelasan yang agak panjang untuk satu fungsi panggilan.
Bagaimanapun, jika anda mahu maklumat lanjut pada sscanf dan adik-beradik,
menyemak muka surat manusia, Google, atau kedua-duanya.
Terdapat banyak pilihan rentetan format,
dan ini boleh menjimatkan banyak buruh manual apabila cuba untuk menghuraikan rentetan di C.
>> Fungsi akhir di perpustakaan untuk melihat adalah GetString.
Ia ternyata bahawa GetString adalah fungsi yang sukar untuk menulis dengan betul,
walaupun ia seolah-olah seperti satu tugas yang mudah, biasa.
Mengapa kes ini?
Nah, mari kita berfikir tentang bagaimana kita akan menyimpan baris yang pengguna jenis masuk
Sejak rentetan adalah satu urutan aksara,
kita mungkin mahu untuk menyimpan ia dalam pelbagai pada timbunan,
tetapi kita perlu tahu berapa lama array akan menjadi apabila kita mengisytiharkan ia.
Begitu juga, jika kita mahu meletakkan ia pada timbunan,
kita perlu lulus malloc bilangan bait yang kita mahu untuk menempah,
tetapi ini adalah mustahil.
Kami tidak mempunyai idea berapa banyak aksara pengguna akan menaip
sebelum pengguna sebenarnya tidak menaip mereka.
>> Naif Satu penyelesaian kepada masalah ini adalah untuk hanya menempah sebahagian besar ruang, berkata,
blok 1000 aksara bagi input pengguna,
menganggap bahawa pengguna tidak akan menaip dalam rentetan yang lama.
Ini adalah idea yang buruk kerana dua sebab.
Pertama, andaian yang pengguna biasanya tidak menaip dalam rentetan yang panjang,
anda boleh membazirkan banyak memori.
Pada mesin moden, ini mungkin tidak menjadi isu jika anda melakukan ini
dalam satu atau dua keadaan terpencil,
tetapi jika anda mengambil input pengguna dalam gelung dan menyimpan untuk kegunaan kemudian,
anda dengan cepat boleh menghisap sehingga satu tan ingatan.
Selain itu, jika program yang anda menulis adalah untuk komputer yang lebih kecil -
peranti seperti telefon pintar atau sesuatu yang lain dengan memori yang terhad -
penyelesaian ini akan menyebabkan masalah yang banyak lebih cepat.
Kedua, sebab yang lebih serius untuk tidak melakukan ini adalah bahawa ia meninggalkan program anda terdedah
apa yang dipanggil serangan penampan limpahan.
Dalam pengaturcaraan, penampan adalah memori yang digunakan untuk menyimpan data input atau output sementara,
yang dalam kes ini adalah blok 1000-char kami.
A buffer overflow berlaku apabila data ditulis lepas akhir blok.
>> Sebagai contoh, jika seorang pengguna sebenarnya tidak taip lebih daripada 1000 aksara.
Anda mungkin telah mengalami ini sengaja apabila pengaturcaraan dengan tatasusunan.
Jika anda mempunyai pelbagai sebanyak 10 ints, tiada apa yang menghalang anda daripada cuba untuk membaca atau menulis
int 15.
Tiada amaran pengkompil atau kesilapan.
Program ini hanya kesilapan lurus ke hadapan dan mengakses memori
jika difikirkannya int 15 akan menjadi, dan ini boleh menimpa pembolehubah lain anda.
Dalam kes terburuk, anda boleh overwrite beberapa program anda dalaman
mekanisme kawalan, menyebabkan program anda untuk benar-benar melaksanakan arahan yang berbeza
daripada anda yang dimaksudkan.
>> Kini, ia bukan perkara biasa untuk melakukan ini sengaja,
tetapi ini adalah teknik yang agak biasa bahawa lelaki buruk gunakan untuk memecahkan program
dan meletakkan kod berniat jahat pada komputer orang lain.
Oleh itu, kita tidak boleh hanya menggunakan penyelesaian naif kami.
Kita perlu satu cara untuk menghalang program kami daripada menjadi terdedah
kepada serangan buffer overflow.
Untuk melakukan ini, kita perlu memastikan bahawa penampan kami boleh berkembang seperti yang kita baca
input lebih dari pengguna.
Penyelesaiannya? Kami menggunakan penampan timbunan diperuntukkan.
Sejak kita boleh mengubah saiz ia menggunakan saiz semula fungsi realloc,
dan kami menjejaki dua nombor - indeks slot yang kosong akan datang dalam buffer
dan panjang atau kapasiti penimbal.
Kita membaca dalam aksara dari satu pengguna pada masa menggunakan fungsi fgetc.
Hujah fungsi fgetc mengambil - stdin - adalah rujukan kepada rentetan input standard,
yang merupakan saluran input preconnected yang digunakan untuk memindahkan input pengguna
dari terminal untuk program ini.
>> Apabila pengguna jenis dalam watak baru, kita memeriksa untuk melihat jika indeks
slot bebas akan datang ditambah 1 adalah lebih besar daripada kapasiti penampan.
1 datang dalam kerana jika indeks percuma seterusnya adalah 5,
maka panjang penampan kita mesti 6 terima kasih kepada 0 pengindeksan.
Jika kita telah kehabisan ruang dalam buffer, maka kita cuba untuk mengubah saiz,
menggandakan ia supaya kita mengurangkan bilangan kali bahawa kita mengubah saiz
jika pengguna menaip rentetan benar-benar panjang.
Jika tali itu telah mendapat terlalu lama atau jika kita kehabisan memori timbunan,
kita membebaskan penampan dan batal pulangan.
>> Akhirnya, kami melampirkan char buffer.
Setelah hits pengguna memasuki atau kembali, isyarat baris baru,
atau khas char - kawalan d - yang menandakan akhir input,
kita melakukan pemeriksaan untuk melihat jika pengguna sebenarnya ditaip dalam apa-apa pada semua.
Jika tidak, kita kembali null.
Jika tidak, kerana penampan kita mungkin lebih besar daripada kita perlu,
dalam kes terburuk, ia adalah hampir dua kali ganda besar seperti yang kita perlukan
kerana kita menggandakan setiap kali kita mengubah saiz,
kita membuat salinan baru rentetan menggunakan hanya jumlah ruang yang kita perlukan.
Kami menambah 1 tambahan kepada panggilan malloc,
supaya ada ruang untuk watak terminator khas null - \ 0,
yang kita melampirkan pada tali sekali kita menyalin di seluruh watak-watak,
menggunakan strncpy bukannya strcpy
supaya kita dapat menentukan dengan tepat berapa banyak aksara yang kita mahu untuk menyalin.
Strcpy salinan sehingga ia mencecah \ 0.
Kemudian kita membebaskan penampan kami dan kembalikan salinan kepada pemanggil.
>> Siapa tahu apa-apa fungsi yang mudah seolah-olah boleh begitu rumit?
Sekarang anda tahu apa yang masuk ke dalam perpustakaan CS50.
>> Nama saya adalah Nate Hardison, dan ini adalah CS50.
[CS50.TV]