[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是要輸出/你好, 重定向標準錯誤。 因此,如果發生了標準錯誤,它會不會被投入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]