[Powered by Google Translate] [第5條 - 更舒適]
[羅布·鮑登 - 哈佛大學]
[這是CS50。 - CS50.TV]
>> 就像我在我的電子郵件中說，有很多的東西，你可以使用
其他比設備實際做的習題集。
我們建議你這樣做只是因為它在家電，那麼我們就可以更容易地幫助您
我們知道如何去上班。
但是，作為一個例子，你可以做的事情，如果說，你不能夠訪問
的設備或您要在科學中心地下室 -
其實他們有設備 -
如果你想在任何地方工作。
一個例子是，你看到/聽到的SSH？
SSH是基本上是一樣的東西連接。
其實，現在我SSHed插入設備。
我從來沒有直接在產品中。
這裡是家電，如果你看這裡，你看到這個IP地址。
我從來沒有在設備本身;
我總是iTerm2窗口/終端窗口。
可以SSH到的IP地址，SSH jharvard@192.168.129.128。
我記得這個數字很容易，因為它是一個很好的模式。
但是，這將問我，我的密碼，現在我在家電。
基本上，在這一點上，如果打開了一個終端設備本身的內部，
這個接口，但是你會使用它，是完全一樣的
使用的接口，我在這裡，但現在你SSHed。
你沒有SSH的設備。
我敢肯定，你必須在默認情況下，另一個地方，你可以SSH是一個例子 -
哦。更大。
所有的人都應該有默認情況下，FAS FAS服務器的帳戶。
對於我來說，我會SSH的rbowden@nice.fas.harvard.edu。
它會問你的第一次，和你說的話。
我的密碼，只是將我的FAS密碼。
所以現在，我SSHed漂亮的服務器，和我想在這裡，我可以做任何事情。
很多類，你可能需要像124，有你上傳的東西在這裡
提交您的問題集。
但說你沒有訪問您的設備。
然後你就可以像在這裡做的事情，它會說 -
這僅僅是我們部分的問題。
它會問你做到這一點的設備。
相反，我會做它的服務器上。
我要解壓縮。
這個問題將是你已經習慣了使用的東西，例如gedit
或其他組件內。
你不會的FAS服務器上。
這一切都只是將這個文本界面。
所以，你可以任何一個，努力學習，他們有一個文本編輯器。
他們有納米。
納米通常是很容易使用。
您可以使用箭頭，然後鍵入正常。
因此，並不難。
如果你想獲得真正看中的，你可以使用Emacs，
我也許不應該打開了，因為我什至不知道如何關閉Emacs的。
控制X，控制C？是啊。
或者你也可以使用vim，這是我使用。
所以這些都是你的選擇。
如果你不想這樣做，你也可以，如果你manual.cs50.net -
哦。
在PC上，你可以使用SSH使用PuTTY
你要單獨下載。
在Mac上，你可以在默認情況下使用的終端或你可以下載iTerm2，
這是一個很好的，看中的終端。
如果你去到manual.cs50.net，你會看到一個鏈接到記事本+ +，
這是你可以在PC上使用。
它可以讓你SFTP從記事本+ +，這基本上是SSH。
這是什麼讓你這樣做是在本地編輯您的文件，
然後，每當你想將它們保存，它會保存到nice.fas中，
然後，你可以運行它們。
在Mac上相當於將是TextWrangler。
因此，它可以讓你做同樣的事情。
它可以讓你在本地編輯文件，將它們保存到nice.fas，
然後，你可以運行它們。
所以，如果你遇到難題沒有設備，你有這些選項
還是做你的問題集。
一個問題是，你不會有CS50庫
因為nice.fas默認情況下，不具備這一點。
您可以下載的CS50庫 -
我不認為我需要在這一點上。
你可以下載的的CS50庫和複製到nice.fas，
我認為在這一點上，我們不使用它了呢。
或者，如果我們這樣做，你的時間可以被取代它
反正的CS50庫中的功能的實現。
因此，不應該有那麼多的限制。
就是這樣。
>> 我會回去的設備，現在我們將盡一切設備。
我們的部分問題，在開始的時候，就像我在我的電子郵件中說，
我們要談一個短你應該看。
我們有重定向和管道這三個問題。
>> 在這流功能，如輸出默認情況下寫的？
所以流。什麼是流？
甲流是基本上一樣，只是一些 -
它甚至不是一個源1s和0s。
這裡要求的是標準輸出流。
因此，標準輸出流，當你寫它，
它出現在屏幕上。
標準輸出流，這意味著你只寫1“和”0“到它，
標準輸出的另一端從該流中讀取數據。
這只是一個字符串1s和0s。
你可以寫流，或者你可以從數據流中讀取
根據流實際上是什麼。
其他兩個默認流的標準和標準錯誤。
標準的是每當你的GetString，它正在等待你輸入的東西。
因此，它在等著你，它實際上是在等待標準，
這是真的，你會得到什麼，當你在鍵盤上輸入。
你輸入標準英寸
標準錯誤是基本上等同於標準輸出，
但它的專業，當您打印到標準錯誤，
你應該只打印錯誤消息，該
這樣你就可以區分常規消息打印到屏幕上
對誤差取決於他們是否去到標準輸出和標準錯誤的消息。
文件了。
標準輸出，標準和標準錯誤是特別的流，
但實際上任何文件，當你打開一個文件時，它變成一個字節流
在那裡你可以從該流中讀取。
您，在大多數情況下，只是覺得一個文件的字節流。
所以他們寫什麼流在默認情況下？標準輸出。
>> >和>>之間的區別是什麼？
沒有人事先觀看視頻？好吧。
>將是如何重定向到文件，
>>也將輸出重定向到文件中，
但它的，而不是要追加到文件。
例如，讓我們說，我正好有字典在這裡，
唯一的字典裡面的東西是貓，貓，狗，魚，狗。
一個命令，你必須在命令行是貓，
只是要打印在一個文件中。
所以當我說貓字典，它要打印的貓，貓，狗，魚，狗。這是所有的貓做。
這意味著，貓，貓，狗，魚，狗，它打印到標準輸出。
如果我不是要重定向到一個文件中，我可以使用>將它重定向到任何該文件是。
我會打電話給該文件的文件。
所以，現在如果我LS，我會看到我有一個新的文件名為文件。
如果我打開它，它將會有什麼貓放在命令行。
所以，現在如果我這樣做了，那麼它的輸出重定向到文件，
和我有同樣的事情。
所以，從技術上來說，它完全推翻了我們什麼。
我們會看到，如果我改變了字典，我拿出狗。
現在，如果我們貓詞典到文件中，我們將有新的版本與狗刪除。
因此，它完全覆蓋。
相反，如果我們使用“>>”，這是怎麼回事追加文件。
現在，打開文件，我們可以看到，我們有同樣的事情兩次印刷
有一次，因為它是，那麼我們就追加到原來的。
所以，這就是>和>>。
請問下一個要求 - 它不要求它。
>> 我們有另一種是<，如果標準輸出重定向，
<將被重定向標準英寸
讓我們來看看，如果我們有一個例子。
我可以寫一個真正的快速。
讓我們任何文件hello.c。
相對直截了當文件。
我只是一個字符串，然後打印“Hello”無論我剛剛輸入的字符串是。
因此，請hello，然後。/個招呼。
現在，它提示我輸入的東西，
這意味著它等待的東西，將予訂立標準英寸
因此，進入任何我想要的標準。我們要好好說“你好”，羅布！
然後打印到標準輸出您好，來搶！
如果我這樣做。/ hello，然後重定向，
現在你可以只從一個文件重定向。
所以，如果我把一些文件，TXT，我把羅布，
如果我跑個招呼，然後重定向到的文件文本。/打招呼，它會說“你好”，搶！立即。
當它第一次得到的GetString和它的等待標準，
標準中不再等待鍵盤上的數據，從而得到進入。
相反，我們從文件中讀取TXT重定向標準。
因此，它會讀取TXT的文件，這僅僅是行搶，
那麼它會打印Hello，羅布！
如果我想，我也可以做。/你好TXT
然後指出它的標準印刷，您好，這是來搶！
我可以重定向到它自己的文件。
我只需要調用的文件招呼 - 不，我不會，因為這是可執行文件 - txt2。
現在，，txt2是要輸出/你好<txt文件，這將是您好，羅布！
>> 有問題嗎？
>> 好吧。那麼在這裡，我們有管道。
管道的最後一個單元的重定向。
>> 哦。我想一個單位的重定向，如果不是你2>，
重定向標準錯誤。
因此，如果發生了標準錯誤，它會不會被投入txt2。
但是請注意，如果我這樣做2>，然後它仍然印刷您好，來搶！在命令行
因為我只重定向標準錯誤，我不重定向標準輸出。
標準錯誤和標準輸出是不同的。
如果你想真正寫入到標準錯誤，
然後我可以改變這是fprintf到stderr。
所以，默認情況下，打印輸出到標準輸出。
如果我想手動打印到標準錯誤，那麼我必須使用fprintf
並指定我要打印到的。
相反，如果我做了fprintf標準輸出，那麼這基本上等同於printf的。
，但fprintf標準錯誤。
所以，現在，如果我重定向到txt2，您好，來搶！還是會被印在命令行
，因為它的打印到標準錯誤，我只重定向標準輸出。
如果我現在將標準錯誤重定向，現在也沒有打印出來，和txt2將是你好，搶！
那麼現在，你可以打印你的實際標準錯誤的錯誤
打印您的的常規郵件到標準輸出。
所以當你運行你的程序，你可以運行它。/您好，這類型的2>
讓你的程序將正常運行，
但任何錯誤消息，讓你可以檢查你的錯誤日誌中，
這樣的錯誤，然後看後，你的錯誤，文件中有任何錯誤發生。
>> 有問題嗎？
>> 最後一個是管道，你能想到的，所承擔的標準，從一個命令
和它的標準中的下一個命令。
這裡是一個例子，echo是一個命令行的東西
這只是呼應，我把什麼作為它的參數。我不會把引號。
回音胡說，胡說，胡說，只是要打印等等，等等，等等。
在此之前，當我說，我只好把羅布到一個txt文件
因為我只能重定向txt文件，而不是，/如果我呼應羅布
然後通過管道到/個招呼，這也將做同樣類型的東西。
這是此命令的輸出，迴聲羅布，
並用它作為輸入/個招呼。
你可以認為它是第一個到一個文件重定向迴聲羅布
，然後輸入/你好，文件只是輸出。
但它需要的臨時文件的圖片。
>> 該問題嗎？
>> 接下來的問題是會涉及到這一點。
管道，你可以用它來尋找一個稱為names.txt的文件的唯一名稱是什麼？
，我們將要在這裡使用的命令是唯一的，因此uniq中，然後廁所。
你可以做男人的uniq的實際看是什麼做的，
它只是將篩選相鄰的匹配行從輸入。
男子廁所是要打印的換行，字和字節計數的每個文件。
我們將要使用的是最後一個排序，
這是怎麼回事，只是txt文件的行進行排序。
如果我做一些txt文件，的names.txt，它的羅布，張宇，約瑟夫，張宇，約瑟夫，RJ，羅布，
我想在這裡做什麼的，是在這個文件中找到的唯一名稱。
那麼應該怎樣的答案呢？ >> [學生] 4。 >>呀。
它應該是4，因為羅布，湯米，約瑟夫，RJ是在這個文件中只有唯一的名稱。
第一步，如果我只是做的字數的names.txt，
這實際上是告訴了我一切。
其實，這是印刷 - 讓我們來看看，男人WC - 換行，單詞和字節計數。
如果我只在乎線，然後我就可以做WC-L names.txt。
所以這是第1步。
但我不希望到廁所 - 1 names.txt，因為names.txt只包含了所有的名字，
我要過濾掉任何非唯一的。
所以，如果我做的uniq names.txt，不很給我我想要的
因為重複的名稱仍然存在。
這是為什麼？ uniq的是為什麼不這樣做我想要什麼？
[學生]重複[聽不清] >>呀。
記住的uniq手冊頁說，過濾器相鄰的匹配行。
他們是不相鄰的，所以它不會過濾。
如果我先對它們進行排序，排序names.txt是打算把所有重複的行。
所以，現在排序names.txt是。
我將要使用的uniq的，這是| uniq的輸入。
這給了我約瑟夫，RJ，搶奪，湯米，
我想使用這個輸入到wc-L，
這是要給我4。
喜歡它說，在這裡，你可以使用什麼樣的管道？
你可以做很多的事情，比如使用一系列的命令
在您使用一個命令的輸出作為下一個命令的輸入。
你可以做很多事情，很多聰明的事情。
>> 有問題嗎？
好吧。
這是它的管道和重定向。
>> 現在我們的實際的東西，編碼的東西。
本PDF裡面，你會看到這個命令，
你要運行此命令在您的設備。
wget是命令只是從互聯網上得到的東西，基本上，
所以wget和URL。
如果你到這個URL在瀏覽器中，它會下載該文件。
我只是點擊就可以了，所以對我來說，它下載的文件。
但是，寫的那個東西的wget內的終端
只是要下載到您的終端。
我有section5.zip的，和你要解壓section5.zip的，
這是給你一個文件夾，名為第5章，
這是我們要使用它裡面的所有的文件。
隨著這些項目的文件名稱所暗示的，他們是一個有點缺陷，
所以，你的任務是要弄清楚為什麼使用gdb。
每個人都有他們下載/知道如何讓他們下載
設備到他們的嗎？好吧。
>> 運行./buggy1，它會說分割故障（核心轉儲）
任何時候你得到一個segfault，這是一個不好的事情。
在什麼情況下，你得到一個segfault？
[學生]：取消引用一個空指針。 >>呀。所以這是一個例子。
解引用一個空指針，你會得到一個segfault。
一個segfault手段是你感動的回憶，你不應該接觸。
因此，釋放空指針動人的地址為0，
基本上，現在所有的電腦說，地址為0的內存，你不應該接觸。
所以這就是為什麼一個空指針解引用一個segfault。
當你的事發生在初始化的指針，那麼它有一個垃圾值，
因此，當您嘗試取消引用它，在所有的可能性你感動的回憶
這是在中間的地方。
如果你碰巧很幸運，垃圾的價值
發生點在堆棧上或東西的地方，
那麼當你解引用指針，你還沒有初始化，
什麼都不會出問題。
但是，如果它指向的棧和堆之間的某個地方，說，
它指向只是到別的地方，沒有被使用你的程序，
那麼你感動的回憶，你不應該接觸和你的段錯誤。
當你寫一個遞歸函數，遞歸太多次
堆棧的增長過大，堆棧碰撞到的東西
它不應該被碰撞，你感動的回憶，你不應該接觸，
因此你段錯誤。
這是一個segfault。
>> 這是同樣的道理，如果你有這樣的字符串 -
讓我們回到前面的程序。
在hello.c的，我只是要別的東西。
的char * s =“世界你好！”;
如果我使用的東西或S * S = [0] ='X';
所以一定要打招呼，/你好，為什麼是段錯誤？
為什麼這個段錯誤呢？
你會想到什麼事情發生呢？
如果我做了printf的（“％s \ n”）;你會想到要打印的嗎？
[學生] X打招呼。 >>呀。
現在的問題是，當你聲明一個這樣的字符串，
s是一個指針，要在棧上，
什麼s指向的是這個字符串包含在只讀存儲器。
因此，只要名稱，只讀存儲器，你應該得到的想法
如果你試圖改變什麼只讀存儲器，
你正在做的事情你不應該做的內存和段錯誤。
這實際上是一個很大的區別的char *和char []。
所以個char []，現在這個字符串將被放在堆棧中，
且堆棧無法讀取，這意味著，這應該工作完全正常。
它。
請記住，當我這樣做的char * s =“世界你好！”，S本身是在棧上
但s指向其他地方，其他地方恰好是只讀。
但個char []是在棧上的東西。
所以這是一個segfault發生的另一個例子。
>> ，我們看到./buggy1導致一個segfault。
從理論上講，你不應該看buggy1.c立即。
相反，我們將看看它通過gdb的。
請注意，當你得到分割故障（核心轉儲），
你得到這個文件，這裡所說的核心。
如果我們的ls-l，我們可以看到，核心通常是一個相當大的文件。
這是該文件的字節數，所以它看起來像它的250歲的千字節為單位。
這樣做的原因是什麼實際上是核心轉儲
是當你的程序崩潰時，你的程序的內存狀態
剛剛被複製，並粘貼到該文件中。
它被傾倒到該文件中。
這個程序，運行時，正巧有一個約250千字節的內存使用情況，
所以這是什麼得到了傾入這個文件。
現在，你可以看一下該文件，如果我們做GDB buggy1核心。
我們可以做gdb的buggy1，將只啟動gdb的定期，
使用buggy1作為它的輸入文件。
但是，如果你GDB buggy1的核心，那麼它明確要啟動GDB
看，核心文件。
你說buggy1手段gdb的都知道，該核心文件來從buggy1程序，。
GDB buggy1核心是要立即給我們帶來
的地方發生的程序終止。
我們在這裡看到的信號，分割故障終止程序。
我們碰巧看到的組裝線，這可能是非常有幫助的。
但是，如果你鍵入BT或回溯，這將是功能
這樣，就為我們提供了我們當前的堆棧幀的列表。
所以回溯。它看起來像我們只有兩個堆棧幀。
首先是我們的主要的堆棧幀，
第二個是，我們正好是在這個函數的堆棧幀，
看起來我們只需要的彙編代碼。
所以，讓我們回到我們的主要功能，
做到這一點，我們可以做的第1幀，我覺得我們也可以做下來，
但我幾乎從來沒有辦下來 - 或上升。是啊。
向上和向下。最多給你帶來一個堆棧幀，同比下降給你帶來了一個堆棧幀。
我傾向於從來沒有使用它。
我只是具體說，這是去的幀標記為1的第1幀。
第1幀，將要帶給我們的到主堆棧幀，
在這裡，它說發生在我們的代碼行。
如果我們想要一對夫婦更行代碼列表，我們可以說，
而這會給我們周圍所有的代碼行。
我們segfaulted該生產線為6：
（STRCMP（“CS50石頭”，ARGV [1]）== 0）。
如果沒有明顯的是，你可以得到它直接從這裡只是想，為什麼segfaulted。
但是，我們可以把它一步，說，“我為什麼要ARGV [1]段錯誤呢？”
讓我們打印的argv [1]，它看起來像它的0x0，這是空指針。
我們strcmping CS50石塊和空，所以會出現段錯誤。
又為什麼是argv [1]為空？
[學生]：因為我們沒有給它任何命令行參數。
是啊。我們沒有給它任何命令行參數。
所以./buggy1的argv [0]是./buggy1。
它不會有一個argv [1]，因此，會出現段錯誤。
但是，如果不是，我做的只是CS50，它會說你得到D
，因為這是它應該做的。
在buggy1.c看，它應該打印“你得到一個D” -
如果argv [1]，而不是“CS50岩石”，“你得到了D”，否則，你會得到一個A！“
因此，如果我們要一個一個，我們需要的比較結果為真，
這意味著，它比較為0。
的argv [1]因此，需要將“CS50岩石”。
如果你在命令行上要做到這一點，你需要使用\逃跑的空間。
因此，CS50 \岩石，你會得到一個A！
如果你不這樣做的反斜杠，為什麼不工作？
[學生]：這是兩個不同的參數。 >>呀。
的argv [1]將是CS50，和argv [2]將是岩石。好吧。
>> 現在./buggy2是再次向段錯誤。
，其核心文件，而不用打開它，我們就打開了buggy2直接，
所以GDB buggy2。
現在，如果我們運行我們的程序，那麼它會說程序收到信號SIGSEGV，
這是段錯誤的信號，這是它發生在發生。
我們回溯看，我們看到我們在功能oh_no，
這是所謂的由函數極小，這是所謂的由函數binky，
被稱為主。
我們也可以看到這些功能的參數。
極小和賓基的參數為1。
如果我們列出的功能oh_no，我們看到，oh_no，只是做的char * s = NULL;
* s =“BOOM”;
為什麼會失敗呢？
[學生]無法取消引用空指針？ >>呀。
這只是說s是NULL，無論如果出現這種情況，是一個char **，
這取決於你如何解釋它，它可能是一個指向一個指針，指向一個字符串的指針
或一個字符串數組。
s為null，* S是一個空指針解引用，
所以這是要崩潰。
這是一個最快捷的方法，你可以可能出現段錯誤。
這只是宣布一個空指針，並立即段錯誤。
這是什麼oh_no。
如果我們去了一個框架，然後，我們將要進入的功能，稱為oh_no。
我需要做下來​​。
如果你不輸入命令，你只要再次按下Enter鍵，
它只是重複前面的命令，你跑了。
我們在第1幀。
上市這一框架內，我們在這裡看到的是我們的功能。
你可以打列表，或者你可以做的清單2​​0，它會列出。
該函數的極小的說，如果我是1，然後去的oh_no功能，
其他緊身的功能。
我們知道，我是1，因為我們在這裡碰巧看到
被稱為參數1，極小的。
或者你也可以不打印我，它會說我是1。
目前，我們正在極小，如果我們去了另一個框架，我們知道我們將最終在賓基。
最多。現在，我們在binky。
列出這個功能 - 在上半場結束前把我的清單 -
它開始了，如果我是0，然後，我們將調用它oh_no，否則打電話極小。
我們知道，我是1，因此它被稱為極小的。
，現在我們在主，主要是int i =蘭特（）％3;
這僅僅是給你一個隨機數是0，1或2。
這將調用binky與數字，它會返回0。
見到這種情景，
步行通過的程序不運行它立即，手動
在主，你可以設置一個破發點，這意味著當我們運行程序
你的程序運行，直到它擊中了一個破發點。
因此，運行程序，它會運行，然後它會為主打功能，並停止運行。
現在，我們的主要內，步驟或未來將會給我們帶來的下一行代碼。
你可以做的步驟或未來。
單擊Next，現在我已經設置的rand（）％3，這樣我們就可以打印i的值，
它會說我是1。
現在它無論我們使用下一個或步驟。
我想它在上一個重要的，但我們希望下次使用。
如果我們使用步驟，我們進入的功能，這意味著在實際的東西看
內發生的事情的binky。
如果我們用下，那麼就意味著在功能
只是去我們的主函數中的代碼的下一行。
在這條線就在這裡，我是在它說的rand（）％3;
如果我這樣做的一步，將進入實施蘭特
並期待在那裡發生了什麼事，我可以通過rand函數的步驟。
但我不關心rand函數。
我只想去到下一行代碼的主，所以我用下。
但我現在關心的binky功能，所以我想步入。
現在，我在binky。
的第一行代碼是怎麼說的（我== 0），我走了一步，
我們可以看到，我們結束了在極小的。
如果我們列出的東西，我們可以看到，它檢查是i = 0。
我是不等於0，所以去的其他條件，
要調用極小的（I）。
你可能會感到困惑。
如果你只是直接看這些線，你可能會認為，如果（我== 0）
好，那我走了一步，現在我在極小的（I），
你可能會認為一定意味著i = 0或東西。
它只是意味著它知道它可以直接粘到線極小的（I）。
由於i是不為0時，下一個步驟是不會結束的else。
Else是不是要停在一條線。
它只是要去到下一行，它實際上可以執行，這是極小的（I）。
步入極小的（I），我們可以看到，如果（我== 1）。
我們知道I = 1，所以當我們一步，我們知道我們要在oh_no
因為I = 1調用函數oh_no，你可以進入，
這是要設置的char * s = NULL，並立即“BOOM”。
然後尋找在實施buggy2，
這一點，我只是得到一個隨機數 - 0，1或2 - 呼叫賓基，
如果我是0它要求oh_no的，否則它會調用極小，來了這裡。
如果i是1，呼叫oh_no，否則打電話緊身，這即將在這裡，
如果是2，調用oh_no。
我什至不認為有一種方法 -
有沒有人看到這是一個程序，不會出現段錯誤的一種方式嗎？
因為除非我失去了一些東西，如果我是0，你馬上就會出現段錯誤，
否則你去一個函數，如果我是你段錯誤，
否則，你去給一個函數，如果我是2段錯誤。
所以無論你做什麼，你段錯誤。
>> 我想修復它，而不是做的char * s = NULL的方式之一，
你可以MALLOC該字符串的空間。
我們可以做的malloc（大小） - 大小是什麼？
[學生]（字符）* 5？ “這似乎不是嗎？
我假定這將工作，如果我真的跑了，但它不是我在尋找什麼。
看看s的類型。讓我們增加對int *，所以int * X。
我會做的malloc（sizeof（int）的的）。
或者，如果我想要一個數組5，我會做（如sizeof（int）* 5）;
如果我有一個int **嗎？
那我的malloc嗎？
[學生]大小的指針。 >>呀。 （如sizeof（int *））;
同樣的事情在這裡。
我想（如sizeof（char *）的）;
這是怎麼回事“轟”的指針，該指針指向分配空間。
我並不需要分配空間的“BOOM”
因為這基本上是我在說什麼之前
對char * x =“BOOM”。
“BOOM”已經存在。它發生在存在內存中的只讀區域。
但它已經存在，這意味著這行代碼，如果s是一個char **，
* S是一個char *，你設置這個char *到指向“BOOM”。
如果我想複製到s的“BOOM”，那我就需要為s分配空間。
* S =我會做的malloc（sizeof（字符）* 5）的;
為什麼？
為什麼不是4？它看起來像“BOOM”是4個字符。 >> [學生] NULL字符。
是啊。需要空字符的字符串。
現在，我可以做類似的strcat - 複製一個字符串的功能是什麼？
[學生]京華山一？ “STRCPY。
男人的strcpy。
因此，STRCPY或strncpy（）函數。
strncpy（）函數是一個比較安全的，因為你可以指定到底有多少個字符，
但在這裡並不重要，因為我們知道。
因此，strcpy和尋找的參數。
第一個參數是我們的目標。
第二個參數是我們的源代碼。
我們要複製到我們的目的地* S的指針“BOOM”。
你為什麼要做到這一點，而不是正是我們之前用的strcpy
* S =“BOOM”？
是有原因的，你可能想這樣做，但是那是什麼原因呢？
[學生]如果你想改變一些東西在“BOOM”。 >>呀。
現在，我可以做一些事情，比如s [0] ='X';
，因為點的堆的堆，空間，s是指向
是一個指針，更在堆上的空間，這是存儲“BOOM”。
因此，這“轟”的副本被存儲在堆中。
“BOOM”在我們的計劃在技術上是有兩個副本。
這只是這個“BOOM”字符串常量的第一個，
和“嘭”的第二個副本，，STRCPY創建“嘭”的副本。
但是，“嘭”的副本存儲在堆中，堆，你是自由的改變。
堆是只讀的，因此這意味著，S [0]
是打算讓你改變了價值的“BOOM”。
這將讓你改變這些字符。
>> 有問題嗎？
好吧。
>> 到buggy3，讓GDB buggy3。
我們只要運行它，我們可以看到，我們得到一個segfault。
如果我們回溯，有只有兩個函數。
如果我們進入到我們的主函數中，我們看到，我們segfaulted在這條線。
因此，只要在這條線，（線= 0; FGETS這東西不等於NULL;
線+ +）。
我們的前一幀被稱為_IO_fgets的。
你會看到有很多內置的C函數，
當你得到段錯誤，會有非常神秘的功能名稱
像這個_IO_fgets。
但是，這是怎麼回事涉及到這FGETS通話。
內的某處在這裡，我們是段錯誤。
如果我們對fgets的觀點看，我們可以打印緩衝區。
讓我們打印 - 哦，不。
打印不完全一樣，我希望它去上班。
讓我們來看看在實際的程序。
緩衝區是一個字符數組。這是一個128個字符的字符數組。
所以，當我說，打印緩衝區，它要打印的這128個字符，
我的猜測是期望是什麼。
我一直在尋找的是打印緩衝區的地址，
但是，這並不真正告訴了我很多。
所以，當我碰巧在這裡說×緩衝液，它讓我看到0xbffff090，
其中，如果你還記得從早期的一些點，Oxbffff往往是一個堆棧上下的區域。
該協議棧往往只是根據0xc000開始的地方。
看到這個地址，我知道該緩衝區在堆棧上正在發生的事情。
重新啟動我的程序運行起來，緩衝，我們看到的是這個字符序列
幾乎是毫無意義的。
然後打印文件，這是什麼文件是什麼樣子？
[學生] NULL。 >>呀。
文件是一個的類型FILE *，所以它是一個指針，
該指針的值是空的。
所以FGETS會嘗試讀取該指針以間接的方式，
但為了訪問該指針，它有取消對它的引用。
或者，為了訪問它應該被人指指點點，解引用它。
因此，它釋放空指針，它的segfaults。
我可以重新啟動它。
如果我們打破我們的重點和運行，
第一行代碼是char *文件名=“nonexistent.txt”;
這應該給一個相當大的提示，這個計劃失敗的原因。
鍵入下，我到下一行，我打開這個文件，
然後我立刻進入我們的產品線，其中一次我打了未來，它會出現段錯誤。
有沒有人想拋出一個原因，我們可能會段錯誤？
[學生]文件不存在。 >>呀。
這應該是一個提示
每當你打開一個文件時，你需要檢查文件是否存在。
所以在這裡，“nonexistent.txt”;
當我們閱讀FOPEN文件名，我們就需要說
（文件== NULL）說printf（“請文件不存在！”
- 更好 - 文件名）;返回1;
所以，現在我們要檢查是否為NULL
之前，實際上繼續，並試圖讀取該文件。
我們可以重新創建它，只是看到這樣的作品。
我打算包括一個新的生產線。
所以，現在nonexistent.txt不存在。
這樣的事情，您應經常檢查。
您應經常檢查，看看FOPEN返回NULL。
您應經常檢查，以確定的malloc不返回NULL，
否則，你段錯誤。
>> 現在buggy4.c。
運行。我猜這是等待輸入或可能無限循環。
是的，它是無限循環。
所以buggy4。它看起來像我們的無限循環。
我們可以突破，主要運行我們的程序。
在gdb，只要你使用的縮寫是明確的
或者，他們會為您提供特別的縮寫，
那麼你就可以使用n下次使用，而不必輸入下所有的方式。
現在，我已經打了N一次，我可以只按下回車鍵繼續下
而不是打n輸入n輸入，n輸入。
它看起來像我在某種循環的設置陣列[i]為0。
它看起來像我從來沒有打破這循環中。
如果我打印我，所以我是2的話，我會去下。
我要打印我，我是3，然後我會去下。
我要打印我和我的3。下一步，打印我，我是4。
實際上，打印sizeof（陣列）的，所以陣列的大小是20。
但它看起來像有一些特殊的gdb命令下去，直到事情發生。
這就像設置條件變量的值。但我不記得它是什麼。
因此，如果我們繼續下去 -
你剛才說什麼？你帶來了什麼呢？
[學生]不顯示我添加 - “”是啊。因此，顯示我可以幫忙。
如果我們只是顯示我會把這裡i的值是什麼
所以我沒有把它打印出來，每次。
如果我們只是繼續下一個，我們看到0，1，2，3，4，5，0，1，2，3，4，5，0，1，2，3，4，5。
有些事情正在發生可怕的錯誤，而我正在被重置為0。
在buggy4.c，我們看到的情況是int數組[5];
（i = 0; <= sizeof（數組）的，我+ +）
陣列[i] = 0;
這是錯在這裡，我們看到了什麼？
作為一個提示，當我在做gdb的buggy4 - 讓我們將主要的運行 -
我也只看到打印sizeof（數組）的條件是什麼，我終於爆發。
我在哪裡？我跑了嗎？
我沒有申報。
因此，打印大小（數組）和20，
這是意料之中的，因為我的數組的大小是5，它是由5個整數，
所以，整個事情應該是5 * sizeof（int）的的字節，其中的sizeof（int）往往是4。
因此，大小（陣列）是20。
應該是什麼內容呢？
[學生]將是sizeof（int）。 “是啊，/是sizeof（int）。
它看起來像有一個問題在這裡。我想這應該是<
因為它幾乎總是<永不<=。
現在，讓我們來想想這是為什麼居然斷。
沒有任何人有猜測為什麼我重置為0到每個迭代循環嗎？
內這裡發生的事情是，唯一陣列[i]被設置為0。
不知何故，這行代碼導致我們的詮釋，我將其設置為0。
[學生]難道是我這部分的記憶，因為它的首要
當它認為它的下一個元素的數組？ >> [鮑登]是的。
當我們超越我們的陣列，
不知何故，我們覆蓋的空間，是壓倒一切的我的價值。
所以，如果我們看一下為buggy4，打破主體，運行，
讓我們打印i的地址。
看起來就像是bffff124。
現在，讓我們打印的地址的數組[0]。 110。
怎麼樣[1]？ 114。
[2]，118。
11c中，120。陣列[5] bfff124。
因此，陣列[5]，因為我，這意味著該數組[5]我有相同的地址。
如果他們有相同的地址，他們是同樣的事情。
所以，當我們陣列[5]為0，我們正在設置i為0。
如果您認為有關這方面的堆棧，
詮釋我首先聲明，這意味著我得到了一些堆棧空間。
陣列[5]，20個字節被分配在棧上分配。
所以，我首先被分配，那麼這20個字節被分配。
所以，我前陣發生，
因為，就像我上週表示，在技術堆棧向下增長的，
當你對數組的索引，我們也能保證這個數組中的第0個位置
總是發生之前，數組中的第一個位置。
這是我畫了上週的種。
請注意，在底部我們的地址為0，並在頂部，我們有地址最大。
該協議棧始終是越來越大了下來。
比方說，我們分配給我。
我們分配整數i，這意味著我們只能說，這裡整數，我被分配。
然後我們分配了5個整數組成的數組，這意味著底下的，
由於堆棧的增長，這5個整數如何分配。
但是，由於陣列是如何工作的，我們保證在數組中的第一個位置
總是有的地址小於數組中的第二件事情。
因此，數組中的位置始終為0，首先發生在內存中，
而數組中的位置發生後，
數組中的位置2具有發生之後，
這意味著，數組中的位置0將發生的地方，在這裡，
數組中的位置會發生以上，
因為移動意味著更高的地址以來的最高地址是在這裡。
所以數組[0]在這裡，數組[1]起來這裡，陣列[2]起來這裡，陣列[3]在這裡。
請注意之前，我們如何分配的整數，我在這裡，
隨著我們進一步到我們的數組，我們正在越來越接近我們的整數i。
碰巧的是該數組[5]，這是超出了我們的數組中的一個位置，
正是在那裡我正好是整數分配。
所以，這點，我們碰巧被擊中的堆棧空間
被分配的整數i，我們設置為0。
>> 這是如何工作的。有問題嗎？是啊。
[學生]不要介意。好吧。
[學生]：你如何避免這些類型的錯誤呢？
這些排序的錯誤？不要使用C語言作為編程語言。
使用一種語言，數組邊界檢查。
只要你小心，你只需要你的數組的邊界，以避免過去。
[學生]所以，在這裡，當我們走過你的數組的邊界 -
鮑登這就是事情開始出錯。 >> [學生]：哦，好吧。
只要你留在分配的內存為您的陣列，你的罰款。
但是C沒有錯誤檢查。如果我這樣做陣列[1000]，它會很高興地只需要修改無論發生什麼事 -
它進入陣列的開頭，然後它進入1000位置後，將其設置為0。
它沒有做任何檢查，哦，這不居然有1000的東西在裡面。
1000是遠遠超出我應該改變什麼，
而Java或什麼的，你會得到數組的界限指標
或指數範圍異常。
這就是為什麼有很多的高級語言有這些東西
如果你超越了數組界限，你失敗了
所以，你不能改變的東西從下面你
事情就遠不如剛剛得到一個異常
他說，你去結束之後的數組。
[學生]因此，我們應該只是改變了<=只是<？ >> [鮑登]是啊。
它應該是“大小（數組）/ sizeof（廉政）;
大小（數組）是20，但我們只希望5。 >> [學生]。
還有問題嗎？好吧。
>> [學生]：我有一個問題。 >>呀。
[學生]：什麼是實際的數組變量？
[鮑登]究竟什麼是數組嗎？
數組本身是一個符號。
這僅僅是我們所引用的20個字節的開始地址。
你可以認為它是一個指針，但它是一個常量指針。
只要東西被編譯，變量數組不存在了。
[學生]那麼，它是如何找到數組的大小嗎？
數組的大小是指，該塊的大小，符號是指。
當我做的東西像printf（“％p \ n”，陣列）;
讓我們來運行它。
我剛剛做了什麼錯了嗎？
陣列的陣列“在這裡聲明。
哦，在這裡。
鐺是聰明的，和它發生，請注意，我宣布5個元素的數組作為
但我索引到位置1000。
它可以這樣做，因為這些都只是常量。
它只能走這麼遠，我注意到，超出了數組界限。
但是請注意，當我們有我是不正確的，
，它可能無法確定我能承擔多少值，
所以也不能確定，我打算結束之後的數組。
這只是鐺聰明的。
>> 但現在buggy4。那麼，還有什麼我做錯了什麼？
庫函數printf的'隱式聲明。
我想＃包括的。
好吧。現在運行buggy4。
打印值的數組像我在這裡做的，打印出來作為一個指針
打印出一些東西，看起來像這樣 - bfb8805c - 這是一些地址
這是在堆棧上下的區域。
數組本身是這樣一個指針，但它不是一個實際的指針，
因為常規的指針，我們可以改變的。
陣列僅僅是一些常數。 20塊的開始在地址0xbfb8805c的內存。
所以bfb8805c通過這個地址+20或我猜-20 -
這個數組分配的內存。
數組，變量本身不存儲任何地方。
當你在編譯時，編譯器 - 手一揮 -
但編譯器將只使用它知道數組是。
它知道該數組的開始，
，因此它可以做的事情在一定的偏移量從這個開始。
它並不需要一個變量本身代表陣列。
但是，當我做一些事情，如int * p =陣列，p是一個指針，它指向該數組，
現在p實際上不存在在棧上。
我將p。我可以做p = malloc的。
因此，它最初指向陣列，現在它指向的堆一些空間。
我不能這樣做陣列= malloc的。
如果鐺是聰明的，它會衝我喊了蝙蝠的權利。
其實，我敢肯定，海灣合作委員會將做到這一點。
因此，數組類型為int [5]“是不可轉讓的。
您無法分配到一個數組類型的東西
因為數組是一個常數。
這是一個符號引用這20個字節。我不能改變它。
>> [學生]數組的大小是存儲在哪裡？
鮑登這不是存儲在任何位置。這時候，它的編譯。
那麼，是存儲數組的大小？
您可以使用sizeof（數組）的函數，數組聲明本身的內部。
所以，如果我做了一些功能，foo和我這樣做（int數組[]）
輸出（“％d \ n”，sizeof（數組）的）;
然後，我在這裡調用foo（數組）;
裡面的這個功能 - 讓我們來運行它。
這是再聰明的鏗鏘。
它告訴我的sizeof數組函數參數
將返回了'int *'的大小。
這將是一個錯誤，如果它不是我希望發生的。
關閉Werror。
警告。警告罰款。
它仍然會編譯，只要它有一個警告。
。/ a.out的打印4。
生成的警告，是一個明確的指標，出了什麼問題。
int數組只是要打印的大小（*）。
即使我把陣列[5]在這裡，它仍然只是要打印的大小（*）。
因此，只要你把它傳遞到一個函數，數組和指針的區別
是不存在的。
這恰好是一個數組，在堆棧上聲明，
但只要我們把這個值，0xbf胡說，胡說，胡說到這個函數，
那麼這個指針指向該數組在堆棧中。
因此，這意味著，大小只適用於被宣布的陣列的功能，
這意味著，當你在編譯此功能，
鐺“時，通過這個功能，它認為數組是一個int數組大小為5。
那麼它看到的大小（數組）。嗯，這是20。
這實際上是大小基本上幾乎所有的情況下。
sizeof是一個函數，它是一個運營商。
你不調用sizeof函數。
如sizeof（int），編譯器會翻譯到4。
明白了嗎？好吧。
>> [學生]那麼，什麼是大小（陣列）之間的區別主要在富？
這是因為我們說，這是int *類型的sizeof（數組）的，
而數組在這裡是不是int *類型，它是一個int數組。
>> [學生]所以，如果你有參數的數組[]，而不是int *數組，
這意味著，你仍然可以改變，因為現在它是一個指針數組嗎？
鮑登]像這樣嗎？ >> [學生]是啊。你可以改變數組內的功能呢？
鮑登在這兩種情況下，你可以改變陣列。
在這兩種情況下，你是說數組[4] = 0。
[學生]但你可以使陣列點別的東西嗎？
鮑登哦。是啊。在這兩種情況下 - >> [學生]是啊。
鮑登]數組[]和int *數組之間的區別，是沒有的。
在這裡，您還可以得到一些多維數組
一些方便的語法，但它仍然只是一個指針。
這意味著，我可以自由地做陣列的malloc（如sizeof（int））;現在指向別的地方。
但就像是如何工作的，永遠總是，
改變這種陣列，使其指向其他的東西
不改變這個數組，在這裡，因為它是一個副本的說法，
它不是一個指針，這樣的說法。
而實際上，隨著越來越多的跡象表明，它是完全一樣的 -
我們已經看到了印刷陣列打印 -
如果我們打印的地址數組的數組的地址或地址
無論是那些？
讓我們忽略這一項。
好吧。這是罰款。現在，運行。/ a.out的。
印刷陣列，然後打印該數組的地址，同樣的事情。
陣列根本就不存在。
它知道，當你打印數組，你要打印的符號，指的是那些20個字節。
好，打印的地址的數組，數組的操作是不存在的。
它不會有一個地址，所以它只是打印這20個字節的地址。
只要你編譯，想在你的編譯buggy4。/ a.out格式，
數組是不存在的。
指針存在。數組沒有。
代表該數組的內存塊仍然存在，
但該類型的變量數組和變量不存在。
這些都是像數組和指針之間的主要區別
只要你調用函數，沒有任何區別。
但裡面被聲明為數組本身的功能，大小不同的方式工作
因為你打印的類型的大小，而不是塊的大小，
你不能改變它，因為它是一個符號。
打印的東西打印的東西和地址同樣的事情。
而這幾乎是它。
[學生]你能說更多的時間嗎？
我可能錯過了一些東西。
印刷的數組的數組和地址打印同樣的事情，
而如果你打印的指針與指針的地址，
打印一件事你指向的地址，
其他打印的指針在棧上的地址。
你可以改變一個指針，你不能改變數組的象徵。
和sizeof指針要打印該指針類型的大小。
所以int * p的大小（P），打印4張，
但int數組[5]打印sizeof（數組）的打印20。
[學生] int數組[5]將打印20？ “是的。
這就是為什麼內的buggy4的時候，它使用的是大小（陣列）
這是我做<20，這是不是我們想要的。
我們希望I <5。 >> [學生]好吧。
[鮑登然後，一旦你開始傳遞的功能，
如果我們這樣做* P =陣列;
這個函數裡面，我們基本上可以使用p和陣列完全相同的方式，
除了的sizeof問題和不斷變化的問題。
但是p [0] = 1;說陣列[0] = 1是相同的;
只要我們說富（數組）或者foo（P）;
裡面的函數foo，這是兩次相同的呼叫。
這兩個調用之間沒有任何區別。
>> 每個人都好？好吧。
我們有10分鐘。
>> 我們將嘗試拿到通過這個黑客打字員程序，
本網站，去年或什麼的就出來了。
這只是應該像你輸入隨機它打印出來 -
無論它發生在已加載的文件是什麼，它看起來像你打字。
它看起來像某種操作系統代碼。
這就是我們要實現的。
你應該有一個二進制可執行文件hacker_typer
是發生在一個單一的參數，“黑客類型的文件。”
運行可執行程序，應清除屏幕
然後打印出傳入的文件，每次用戶按下一個鍵一個字符。
所以，你按什麼鍵，它應該扔掉，而不是從文件打印字符
這是參數。
我幾乎會告訴你，我們需要知道的東西是什麼。
但是，我們要檢查的termios庫。
在我的整個生活，我從來沒有使用這個庫，所以它具有非常小的目的。
但是，這將是圖書館內，我們可以用它來扔掉你打的字符
當你輸入到標準英寸
所以hacker_typer.c，我們會想包括的。
的手冊頁的termios的 - 我猜測它的終端OS或東西 -
我不知道如何讀它。
在此，它說，包括這2個文件，所以我們將做到這一點。
>> 第一件事，第一，我們要在一個單一的說法，這是我們要打開的文件。
那麼，我該怎麼辦？我該如何檢查，看看我有一個參數呢？
[學生]，如果argc等於它。 >> [鮑登]是啊。
所以，如果（ARGC = 2）輸出（“用法：％s [文件打開]”）。
所以，現在如果我沒有提供第二個參數 - 哦，我需要新的生產線 -
你會看到它說，使用/ hacker_typer，
第二個參數應該是我要打開的文件。
現在我該怎麼辦？
我想從這個文件中讀取。我如何從文件中讀取嗎？
[學生]：你先打開它。 >>呀。
所以FOPEN。 FOPEN看是什麼樣的？
[學生]文件名。 >> [鮑登] filename是要ARGV [1]。
[學生]，然後你想用它做什麼，所以 - >> [鮑登]是啊。
所以，如果你不記得，你可能只是做男人FOPEN，
它的將是一個const char * path的路徑是文件名，
為const char *模式。
如果你碰巧不記得是什麼模式，那麼你可以看看模式。
裡面的手冊頁，斜線字符是什麼，你可以用它來搜索東西。
所以，我鍵入搜索模式/模式。
N和N是什麼，你可以用它來通過搜索匹配週期。
在這裡，它說，指向一個字符串的參數模式
開始與下列序列之一。
所以，R，打開文本文件進行讀取。這就是我們想要做的。
對於閱讀，我要存儲。
這件事是怎麼回事，是一個FILE *。現在我想要做的是什麼呢？
給了我第二次​​。
好吧。現在我想要做的是什麼呢？
[學生]檢查它是否為NULL。 >> [鮑登]是啊。
任何時候你打開一個文件時，請確保你能夠成功打開它。
>> 現在我想做的事，termios的東西，我想先讀我的當前設置
並保存到的東西，那麼我想改變我的設置
扔掉我鍵入任何字符，
然後我想更新這些設置。
然後在程序結束時，我想改回我原來的設置。
結構類型termios的，我會想這些。
第一個是是我的current_settings，
然後，他們將是我的hacker_settings。
首先，我要保存我的當前設置，
然後我會要更新hacker_settings，
然後結束時，我的計劃，我想恢復到當前設置。
所以保存當前設置的方式工作，我們的人termios的。
我們看到，我們有這樣的詮釋tcsetattr，詮釋tcgetattr。
我通過一個termios結構由它的指針。
這看起來是 - 我已經忘記了調用該函數。
複製和粘貼。
因此，tcgetattr，然後我保存的信息，我想通過在結構中​​，
這是怎麼回事是current_settings，
而第一個參數是文件描述符的事情，我要保存的屬性。
任何時候你打開一個文件的文件描述符是，它得到一個文件描述符。
當我FOPEN的argv [1]，它得到了你所引用的文件描述符
每當你要讀取或寫入到它。
這不是我想在這裡使用的文件描述符。
默認情況下，你有三個文件描述符，
這是標準輸入，標準輸出和標準錯誤。
默認情況下，我認為它的標準是0，標準輸出為1，標準誤差為2。
那麼，我要更改的設置嗎？
我想改變的設置，每當我打了一個字符，
我希望它拋出的字符，而不是打印到屏幕上。
流 - 標準，標準輸出和標準錯誤 -
響應的事情，當我在鍵盤上鍵入？ >> [學生]標準英寸>>呀。
所以我可以做0或者我可以做標準輸入。
我得到了current_settings標準中。
>> 現在，我想更新這些設置，
所以，我首先複製到hacker_settings我的current_settings的。
結構如何工作，它只會複製。
這會將所有的領域，如你所期望的。
>> 現在，我要更新的一些字段。
在termios的，你就必須讀了很多這方面
只是看你要尋找的，
但標誌，你會想看看有回音，
所以echo回顯輸入的字符。
首先，我想設置 - 從來就已經被遺忘的領域是什麼。
這是結構看起來像什麼。
所以輸入模式，我覺得我們要改變。
我們來看看解決方案，以確保這正是我們想要改變。
我們要改變lflag，以防止需要通過所有這些。
我們要改變本地模式。
你將不得不讀通過這整個事情了解的一切都屬於
我們要改變。
但是它裡面的本地模式，我們要去的地方，要改變這種狀況。
因此，hacker_settings.cc_lmode是它叫什麼。
c_lflag。
這是我們進入按位運算符。
我們種出來的時候，但我們會通過它真正的快速。
這是我們進入按位運算符，
在那裡我覺得我說的很久以前，每當你開始處理標誌，
你將要使用按位運算符有很多。
標誌中的每個位對應於某種行為。
所以在這裡，這個標誌有一堆不同的東西，所有的人意味著不同的東西。
但我想要做的是關閉位，對應於ECHO。
因此，要打開關閉我做＆=¬ECHO。
其實，我認為這是如TECHO什麼。我只是要再次檢查。
我可以termios的。這只是迴聲。
ECHO將是一個單比特。
，ECHO將意味著所有位都設置為1，這意味著所有的標誌都設置為true
除了的ECHO位。
結束我的本地標誌，這意味著目前所有標誌設置為true，
將仍然被設置為true。
如果我的ECHO標誌設置為true，那麼這是必然的ECHO標誌設置為false。
所以，這行代碼只是關閉ECHO標誌。
行代碼，我就複製他們的利益的時間，然後加以解釋。
在該解決方案中，他說0。
明確地說，標準輸入，它可能會更好。
>> 請注意，我也做ECHO ICANON。
ICANON是指一些獨立的，這意味著典型的模式。
典型模式是指的是當你鍵入的命令行，
標準不處理任何事情，直到你擊中換行。
所以當你的GetString，你鍵入了一堆東西，然後你打換行。
這時候，它的發送到標準中。
這是默認的。
當我關閉典型模式，你按現在每一個字符
是被處理，這通常是有種不好的，因為它是緩慢的處理這些事情，
這就是為什麼它是很好的緩衝到整行。
但我想每個字符處理
因為我不希望它等待我打換行
前處理所有的字符，我一直打字。
關閉標準模式。
這東西只是意味著當實際處理字符。
這意味著，他們立即處理;盡快，因為我​​打字，處理它們。
這是更新的功能，我的設置標準，
和TCSA手段做是正確的。
其他選項等待，，直到流上的一切，這是目前處理。
這其實並不重要。
現在改變我的設置，無論是目前在hacker_typer_settings的。
我想我把它叫做hacker_settings，讓我們改變它。
改變一切hacker_settings。
>> 現在，在我們的計劃，我們將要恢復
什麼是目前的normal_settings內，
這是怎麼回事，只是看起來像及normal_settings。
請注意，我並沒有改變任何，我normal_settings，因為最初得到它。
然後就改回來，我通過他們在最後。
這是更新。好吧。
>> 內，在這裡我就解釋中的代碼的利益。
這是沒有那麼多的代碼。
我們看到，我們從文件中讀取一個字符。我們稱它f。
現在，您可以男人fgetc函數，fgetc去上班
只是它會返回你剛才讀的字符或EOF，
其對應的端部的文件或一些錯誤發生。
我們循環，繼續從文件中讀取一個字符，
直到我們已經用完了要讀取的字符。
而我們這樣做，我們等待的單個字符標準英寸
每一次你在命令行中鍵入一些東西，
閱讀一個字符從標準中。
隨後的putchar只是打算把在這裡，我們讀到了從文件到標準輸出的字符。
男人的putchar，但它只是把輸出到標準輸出，它的打印字符。
你也可以做輸出（“％C”，C）;同樣的想法。
這是怎麼回事，做大量的工作。
>> 我們想要做的最後一件事是只是FCLOSE我們的文件。
如果你不FCLOSE，這是一個內存洩漏。
我們要FCLOSE我們最初打開的文件，我認為這是它的。
如果我們達到這個目標，我已經有問題。
讓我們來看看。
那有什麼抱怨嗎？
預計'詮釋'，但實參的類型結構_IO_FILE *“。
我們可以看到，如果這樣的作品。
只允許在C99。 Augh。好吧，讓hacker_typer。
現在，我們得到更多有用的描述。
因此，使用未聲明的標識符“normal_settings”。
我沒有把它normal_settings。我稱為它current_settings。
因此，讓我們改變這一切。
現在傳遞參數。
現在，我會讓0。
好吧。 / hacker_typer cp.c.
我也並沒有明確的開始屏幕上。
但是你可以回頭看的最後一個問題集，就看你如何清除屏幕。
這就是打印一些字符
雖然這是做我想做的事情。
好吧。
思考為什麼這個需要，而不是標準輸入為0，
應＃定義0，
這是抱怨 -
以前我說的文件描述符，但你也有你的FILE *，
一個文件描述符只是一個單一的整數，
而一個FILE *有一大堆的東西，與它相關聯的。
究其原因，我們需要說0，而不是標準輸入
的是，stdin是一個FILE *，它指向的東西被引用文件描述符0。
因此，即使在這裡，當我做FOPEN（ARGV [1]，我得到一個FILE *。
但是，在該文件中*是對應於該文件的文件描述符的事情。
如果你看看在開放的手冊頁，所以我認為你必須做的人3個開放式的 - 都能跟得上 -
男子2個開放 - 是啊。
如果你看一下在頁面的開放，開放是像一個較低的水平FOPEN，
它返回的實際文件描述符。
的FOPEN做了一堆東西之上的開放，
而不是只是返回的文件描述符FILE *指針返回一個整
裡面，這是我們的小文件描述符。
所以標準是指FILE *的事情，
而0指的是剛才的文件描述標準本身。
>> 有問題嗎？
[笑]吹過。
好的。我們就大功告成了。 [笑]
>> [CS50.TV]