[Powered by Google Translate] [4]週
[戴維·J·馬蘭] [哈佛大學]
這是CS50。[CS50.TV]
>> 好吧，這是CS50，這是第4週開始，
這是最慢的可能的排序算法之一。
哪一個是，我們只能眼睜睜的看著嗎？
這是冒泡排序，以大O（N ^ 2）+總和，
而事實上，我們是不是唯一的，在這個世界上似乎知道
什麼是冒泡排序，或它的運行時間。
事實上，這是與谷歌的埃里克·施密特（Eric Sc​​hmidt）接受記者採訪時
和前參議員巴拉克·奧巴馬只不過幾年前。
>> 現在，參議員，你在谷歌，
面試的，我喜歡把總統。
現在，它是很難得到一份工作作為總統，你現在正在經歷的嚴峻考驗。
它也很難在谷歌找到一份工作。
我們有問題，我們要求我們的候選人的問題，
而這一次是從拉里·施維默。
你們覺得我在開玩笑嗎？就在這裡。
排序一百萬的32位整數的最有效的方法是什麼？
[笑聲]
良好
對不起。>>不，不，不，不。
我認為，冒泡排序是錯誤的方式去。
>> 來吧，告訴他這？
上週還記得我們休息了一下，從代碼中，至少一天，
並開始專注於一些更高層次的想法和​​解決問題的更一般的
的上下文中搜索和排序，
我們介紹的東西，我們沒有一巴掌這個名字在上週，
但漸近符號，大O，大歐米茄，
有時大的θ符號，而這些人根本方法
描述的算法的運行時間，
需要多少時間的一種算法來運行。
>> 你可能還記得，你談到的運行時間的大​​小
的投入，我們一般稱之為N，什麼問題可能是，
其中，n是多少人在房間裡，
在電話簿的頁面的數量，我們開始寫東西了
像O（N ^ 2）或O（n）或O（n日誌n），
即使在數學沒有相當的工作如此完美
為² - N / 2或類似的東西
相反，我們會扔掉一些低階，
和動機是我們真的想要一個
客觀地評估排序
程序的性能或算法的性能
在一天結束的時候有沒有做的，例如，
今天你的電腦速度。
>> 例如，如果實現冒泡排序，
或者你在今天的計算機上，實現合併排序或選擇排序，
在2 GHz計算機，並運行它，
需要一定的秒數，明年有一個3 GHz
4 GHz的電腦，你可能會然後聲稱：“哇，我的算法
是現在的兩倍快，“在現實中顯然不是這樣。
這只是在硬件變得更快，但你的電腦
並沒有，所以我們真的要扔掉的東西一樣
乘2或3的倍數，當涉及到描述
的速度有多快或慢的算法是真的只是集中
在n或某些因素，
其一些功率中的種類的情況下，從上週。
回想一下，歸併排序的幫助
我們能夠這樣做大大優於冒泡排序，選擇排序
甚至插入排序。
>> 我們得到了n日誌n，並再次，
記得，日誌n一般是指生長
更慢則n，所以n日誌n迄今還是不錯的
因為它是比n²少。
但要實現n日誌n歸併排序
什麼是基本的想法，我們必須充分利用胚芽
我們還利用在0週嗎？
我們是怎麼解決的排序問題，巧妙地與歸併排序？
什麼是重要的見解，也許？
任何人在所有。
好吧，讓我們退後一步。
你自己的話描述歸併排序。
它是如何工作的？
好了，我們將排回0週。
好吧，是的。
[聽不見的學生]
好了，好了，所以我們的數字數組劃分成2個。
我們整理的那件，然後我們合併，
我們已經看到了這個想法之前，這個大的問題
和切碎成一個問題，這個大，這個大。
>> 調出電話簿例如。
回想一下自我計數算法從數週前，
這裡總結了這個偽所以合併排序。
當你給定的n個元素，首先是仔細檢查。
如果N <2，沒有做任何事情在所有
因為如果n <2，那麼顯然，n是0或1，
因此，如果是0或1，沒有什麼排序。
你就大功告成了。
您的列表是平凡的排序。
否則，如果你有2個或更多的元素，然後再劃分
分為兩半，左邊和右邊。
排序每個這些半部，然後合併排序條件半部。
但這裡的問題是，乍看之下，這感覺就像我們撐船。
如果我問你，這n個元素進行排序，這是一個循環的定義
你告訴我，“好吧，好吧，我們將那些N / 2和那些N / 2個元素進行排序，”
然後我的下一個問題將是：“好，你是怎麼排序的n / 2個元素？”
>> 但是，由於這項計劃的結構，
因為有這個基礎的情況下，可以這麼說，
這種特殊情況下，如果n <2回一些固定的值，如立即說。
不回應與相同的圓形的答案。
這個過程中，這種週期性終將結束。
如果我問你“排序n個元素，”和你說，“好吧，整理這些N / 2”
然後你說，“很好，排序這些N / 4，N / 8，N/16，”
最終你會除以一個足夠大的數
，你將有只有1元左，在這一點，你可以說，
“這裡，這裡是一個有序的單個元素。”
然後該算法的輝煌在這裡是從這一事實派生
一旦你把所有這些單獨排序的列表，
所有這一切都是大小為1，這似乎是無用的，
一旦你開始把它們合併，將它們合併
建立終於搶在視頻的最後排序的名單。
>> 但這樣的想法遠遠超出了排序。
有這種想法，在這個程序稱為遞歸嵌入，
是一個程序，讓你的想法，
解決一些問題，你叫你自己，
或把你是一個函數的編程語言的上下文中，
為了解決一個問題，你的函數調用自己
一而再，再而三，但你的功能
不能稱自己為無限多次。
最終，你必須走出谷底，可以這麼說，
並有一些硬編碼的基本條件，
在這一點上停止這樣要求自己，整個過程
其實最終停止。
這究竟是什麼意思，遞歸？
>> 讓我們來看看，如果我們可以做一個簡單的，簡單的例子，比方說，
3人，在這裡我在舞台上，如果有人很舒服。
1，來時，2和3上。
如果你要來這裡。
如果你想站在旁邊，我在這裡行，假設手頭上的問題
是非常平凡的人誰是這裡數一數。
但坦率地說，我累了，所有這些計數的例子。
這將需要一些時間，1，2，點，點，點。
這是怎麼回事採取永遠。
我寧願只平底船這個問題的幫助下，你叫什麼名字？
>>薩拉，薩拉。所有權利。
凱利。>>凱利？
>> >>威利，莎拉，凱莉和威利，威利。
現在，我一直在問的問題，有人
有多少人在這個舞台上，我不知道。
這是一個很長的列表，所以不是我會做這一招。
我要問旁邊的人給我做的大部分工作，
有一次她做的大部分工作
我會做最少的工作，只需添加1
她的回答是，所以在這裡我們去。
我一直在問有多少人在舞台上演出。
有多少人在舞台上你左邊的嗎？
我的左邊？>>好吧，但不要欺騙。
這是很好的，這是正確的，但如果我們要繼續這樣的邏輯
讓我們假設你同樣希望能撐船你左邊的這個問題，
因此，而不是答案直接去前進，只是推卸責任。
哦，很多人都為我的左邊嗎？
有多少人是左邊？
1。
[笑聲]
好了，所以0，所以現在什麼威利已完成
你回到你的答案這方向說0。
現在，你應該怎麼辦？>> 1。
好了，你是1，所以你說，“好吧，我要加1
威利的計數，“1 + 0。
您現在所以你正確的答案是現在，
1。“和我的是2。
好，所以你會覺得前面的回答1，
加入少量的工作，你想要做的，這是+1。
您現在有2個，然後把我哪個值？
3，我的意思是，很抱歉，2。
好。
>> 好了，我們擁有0到左邊。
然後我們有1，然後再加2，
現在你遞過來的2號，
所以我說，沒關係，+1，3。
確實有3人，站在我旁邊的這個舞台上，
因此，我們可以很明顯這樣做非常線性，
非常顯而易見的方式，但我們真的什麼呢？
我們採取了一個大小為3最初的問題。
然後，我們把它弄壞了一個問題分解成大小為2，
然後一個問題大小為1，然後在最後的基本情況
是真的，哦，還有一個人也沒有，
在這一點威利有效地返回一個硬編碼的答案了幾次，
第二個，然後向上冒泡，冒泡，冒泡，
然後以增加一個額外的1在這
我們已經實現了這個遞歸的基本思想。
>> 現在，在這種情況下，它並沒有真正解決的一個問題
任何更有效地發揮作用，那麼我們迄今為止見過的。
但仔細想想，我們所做的舞台上迄今為止的算法。
我們有8個紙寫在黑板上，
視頻時，肖恩一直在尋找的7號，他真的什麼？
，他沒有做任何形式的鴻溝和征服。
他沒有做任何形式的遞歸。
相反，他只是做這個線性算法。
但是，當我們的思想介紹舞台上的排序數字生活上週
然後我們有這種本能的中間，
在這一點，我們有一個小的列表大小為4或另一個列表的大小為4，
然後我們有相同的問題，所以我們重複，重複，重複。
換句話說，我們遞歸。
非常感謝您給我們的3名志願者在這裡展示我們的遞歸。
>> 讓我們來看看如果我們不能更具體一點，
解決問題了，我們可以很輕鬆地做，
但我們將使用它作為實現這一基本思路的墊腳石。
如果我想的一串數字來計算的總和，
例如，如果你通過在3號，
我想給你3西格瑪的價值，
所以總和3 + 2 + 1 + 0。
我想要得到的答案6
讓我們來實現這個sigma函數，這個求和函數
，再次取入輸入，然後返回求和
這一數字一直下降到0。
我們可以做到這一點非常簡單，對不對？
我們能做到這一點，一些種循環結構，
所以，讓我繼續前進，趕快開始。
>> 包括stdio.h中。
讓我讓我自己到這裡主要工作。
讓我們拯救為sigma.c。
然後，我要在這裡，我要聲明的廉政n，
我要做到以下幾點，而用戶不配合。
當用戶還沒有給我一個正數
讓我繼續前進，促使他們為n =調用getInt，
並讓我給他們一些指示做什麼，
因此我們知道printf（“請正整數”）。
只是像這樣簡單的東西比較的時候，我們打了14行
現在，我們有可能在n為正整數。
>> 現在，讓我們用它做什麼。
讓我繼續和計算的總和，所以int總和=Σ（N）。
Sigma是求和，所以我只是寫愛好者。
我們只把它西格瑪有。
的總和，現在我要打印出來的結果，
printf（“請的總和為％d \ n”，總結）。
然後我就返回0的良好措施。
除了有趣的部分，我們所做的一切，這個程序需要，
這實際上是實施六西格瑪的功能。
>> 讓我走在這裡的底部，並讓我申報功能標準差。
它採取了一個整數類型的變量，
和什麼樣的數據類型，我想大概是從Σ返回嗎？
詮釋，因為我想它符合我的期望，第15行。
在這裡，讓我繼續前進，實現這
一個非常簡單的方法。
>> 讓我們繼續前進，並說int總和= 0，
現在我要在這兒有一個小的循環
會說這樣的事情，
（INT I = 0; I <=數字，我+ +）之和+ =。
然後我將返回總和。
我可以在任何數量的方式實現這個。
我可以使用一個while循環。
我可以跳過的總和變量，如果我真的想，
但在短期，我們只需要一個函數，如果我不混日子聲明總和為0。
然後，它會遍歷並貫穿數，從0
在每次迭代補充說，目前的價值總和，然後返回總和。
>> 現在，有輕微優化了。
這可能是一個死不瞑目，但就這樣吧。這就是現在的罰款。
我們至少徹底和投0中一路就到了。
並不難，很簡單，
但事實證明，我們的sigma函數有同樣的機會
我們在這裡所做過的舞台上。
在舞台上，我們就只能有多少人在我旁邊，
而如果我們想數一數3 + 2 + 1
同樣，我們可以下降到0平底船的功能
相反，我會形容為遞歸。
下面讓我們做一個快速的完整性檢查，確保我沒有混日子。
>> 我知道有這個程序，至少有一件事我沒有做錯。
當我按下回車鍵，我會得到什麼樣的罵我嗎？
我該怎麼大叫：約？
是啊，我忘了原型，所以我用西格瑪第15行調用的函數，
但它沒有宣布，直到第22行，所以我最好主動去這裡
聲明原型，我會說：INTΣ（整型數），就是這樣。
它的實施在底部。
>> 或者我可以解決這個問題的另一種方式，
我可以移動的功能在那裡，這是不壞，
但至少當你的程序開始長，坦率地說，
我覺得有一定的價值，總是有主的頂部
讓你的讀者可以打開該文件，然後立即看到
什麼是程序做，而不必通過搜索
尋找，主要功能。
讓我們深入到我的終端窗口，在這裡，試圖使SIGMA西格瑪，
我搞砸了。
隱式聲明的函數調用getInt我忘了做什麼？
[聽不見的學生]
好，顯然是一個常見的錯誤，讓我們把這個在這裡，
cs50.h，現在讓我們回到我的終端窗口。
>> 我會清除屏幕，我會重新運行西格瑪。
它似乎已編譯的。讓我跑去標準差。
我會輸入數字3，我沒得到6，所以不是嚴格的檢查，
但它至少乍一看似乎是工作，但現在讓我們撕裂它除了，
讓我們再次，利用遞歸的想法，
在一個非常簡單的背景，所以，在幾個星期的時間
當我們開始探索愛好者的數據結構陣列
我們有另一個工具箱中的工具，用以
操作這些數據結構，正如我們將看到的。
這是迭代的方法，基於循環的方法。
>> 讓我，而不是現在這樣做。
讓我可以這樣說，數字的總和
下降到0真的是同樣的事情，
數+Σ（數量 - 1）。
換句話說，就像在舞台上，我踢了我旁邊的人，
而他們又不停地踢，直到我們終於走出谷底，威利，
返回一個硬編碼的答案，如0。
現在，我們同樣踢西格瑪
最初被稱為相同的功能，但這裡的關鍵洞察力
是我們，而不是調用標準差相同。
我們不及格的n。
我們清楚地傳遞 - 1，
所以一個略小的問題，稍小的問題。
>> 不幸的是，這是不完全的解決方案，但和之前我們解決
什麼可能會跳出你們中的一些明顯
讓我繼續前進，重新運行使。
它似乎是編譯好的。
讓我重新運行西格瑪6。
哎呀，讓我重新運行西格瑪6。
這之前我們已經看到，儘管偶然一次為好。
為什麼我得到這個神秘的分割故障？是啊。
[聽不見的學生]
有沒有鹼的情況下，更具體地，可能發生的事情嗎？
這是一個症狀，什麼樣的行為呢？
說大聲一點。
[聽不見的學生]
這是一個無限循環，有效地無限循環的問題
當它們涉及在這種情況下，一個函數遞歸調用自身，
每次你調用一個函數，會發生什麼？
好了，回想起我們提出了如何在一台電腦的內存。
我們說，有這樣的內存塊，叫做堆棧的底部，
每次你調用一個函數多一點的內存被放
這個所謂的堆棧，其中包含該函數的局部變量或參數，
因此，如果SIGMA調用SIGMA西格瑪來電要求西格瑪
要求SIGMA這個故事的結束？
>> 那麼，它最終超支總額
，你必須提供給您的計算機的內存。
您溢出的部分，你應該留在，
你得到這個分割故障，核心轉儲，
什麼是核心轉儲的意思是，我現在有一個文件名為核心
這是一個文件，包含零和一
實際上在未來將是有用診斷。
如果這不是很明顯，你在哪裡，你的錯誤是
實際上，你可以做一些取證分析，可以這麼說，
這一核心轉儲文件，這，又是一大堆的零和一
你的程序在內存中，基本上代表了
墜毀在這樣的時刻。
>> 這裡的修復，我們不能只是一味地返回西格瑪，
的數目+西格瑪一個略小的問題。
我們需要有一些基本情況，
什麼的基本情況大概是什麼？
[聽不見的學生]
好了，只要數是積極的，我們其實應該返回這一點，
或者換一種說法，如果數字是多少，說，<= 0
你知道嗎，我會繼續前進，返回0，
很像威利，和其他人，我要繼續前進
並將此，所以它不是，要短得多
比，我們掀起了第一個使用for循環的迭代版本，
但請注意，這種優雅。
而不是返回一些數字，並執行所有的數學
並加入了局部變量
相反，你說：“好吧，如果這是一個超級簡單的問題，
像<0，讓我立即返回0。“
>> 我們不會去打擾支持負數，
所以我要硬編碼的值為0。
但是，除此之外，要實現這個想法的總結
所有這些數字放在一起，可以有效地一小口
出了問題，就像我們在這裡所做過的舞台上，
然後平底船剩下的問題，旁邊的人，
但在這種情況下一個人是自己。
這是一個具有相同名稱的功能。
只要把它體積更小，小的問題，每次
即使我們沒有很正式的事情在這裡的代碼
這究竟是怎麼回事0週的電話簿。
這究竟是怎麼回事，在過去的幾週裡，肖恩
和我們尋找數字的示威。
它的問題，劃分了一遍又一遍。
>> 換句話說，現在有一種方法翻譯
這個現實世界的結構，這種更高的層次結構
分而治之，一遍又一遍的東西
在代碼中，所以這是隨著時間的推移，我們將再次看到的東西。
現在，順便說一句，如果你是新遞歸，你應該至少現在明白了
為什麼這很有趣。
我要訪問google.com，
我要尋找一些技巧和竅門遞歸進入。
告訴你旁邊的人，如果他們不是剛才笑。
你的意思是遞歸？
難道你的意思是啊，我們走吧。
好了，現在剩下的大家。
某處有一個小的嵌入式復活節彩蛋在谷歌。
順便說一句，我們把課程的網站上的鏈接
今天只是這個網格的各種排序算法，
其中一些我們看起來在最後一周，但這種可視化有什麼好處
當你試圖周圍包裹你的心有關的各種事情算法
我知道，你可以很容易地現在就開始與不同類型的輸入。
所有的輸入反轉，輸入大多排序條件，輸入隨機的，等等。
當你再次嘗試，區分這些東西在你的心中
實現了課程網站的講座上，該URL
可能會幫助你通過其中的一些原因。
>> 今天，我們終於得到了一段時間後要解決這個問題，
這是交換功能，這只是沒有工作，
和什麼是最根本的問題，這個功能交換，
目標，其中的時間是，再次，交換的值，在這裡和這裡
如出現這種情況呢？
這實際上並沒有工作。為什麼呢？
是啊。
[聽不見的學生]
沒錯，這bugginess的解釋
簡直是因為當你調用函數在C
這些功能需要的參數，就像A和B，
你是通過你的任何值，該功能提供副本。
你是不是自己提供的原始值，
所以我們看到這在buggyc的背景下，
buggy3.c，這看起來有點像這樣。
>> 回想一下，我們有x和y分別初始化為1和2。
然後，我們打印出它們是什麼。
然後，我要求我的x，y調用swap交換他們的。
但問題是，交換的工作，
但只有在交換的範圍的函數本身。
只要我們打了40行這些交換值
被扔掉了，所以沒有什麼
在實際上改變了原有的功能，主要是在所有，
所以，如果你認為這看起來像在我們的記憶中
如果此電路板的左手側表示-
我會盡我所能為大家看到這如果左側董事會
代表，說，你的RAM，堆棧增長了這種方式，
和我們調用一個函數像主，主有2個局部變量，x和y，
讓我們在這裡描述為x，讓我們在這裡描述為y，
，讓我們把值1和2中，所以在此主要是，
當主呼叫交換功能的操作系統
給自己的大片的內存堆棧上的交換功能，
它自己的堆棧幀，可以這麼說。
它也分配這些32位的int型。
它發生在A和B，但是這完全是任意的。
它可以叫他們為所欲為，但會發生什麼，當主
調用swap是需要1，把一個副本，將副本。
>> 掉期為1的局部變量，不過，叫什麼？>> TMP。
TMP，所以讓我給了自己另一個32位，
我做了什麼在這個功能嗎？
我，詮釋TMP說得到，因此有1，所以我這樣做時，我們上次播放的這個例子。
然後得到b，所以b是2，所以現在變成2個，
現在b得到溫度，因此溫度是1，
所以現在B變成這樣。
這是偉大的。它的工作。
但是，當盡快在函數返回
交換的存儲器有效地消失，以便它可以被重用
由一些在未來的其他功能，和主要是顯然完全不變。
我們需要一種從根本上解決此問題，
今天我們就終於有辦法這樣做，據此
我們可以引進一些所謂的指針。
事實證明，我們可以解決這個問題
而不是通過在x和y的副本
而是通過在哪，你想，交換功能？
是啊，什麼的地址嗎？
我們還沒有真正談過地址在很多細節，
但如果這個黑板代表我的電腦的內存
當然，我們可以開始編號，我的內存中的字節
並說，這是字節＃1，這是字節＃2，＃3字節，
字節第4字節＃2億元，如果我有2 GB的RAM，
所以我們當然可以拿出一些任意的編號方案
在我的電腦的內存中的所有單個字節。
>> 什麼，如果不是，當我打電話交換
在x和y的副本，而不是通
為什麼不要我，而不是通過在這裡的x的地址，
地址為y這裡，基本上郵政的地址
因為x和y交換，如果他的通知
x和y的存儲器中的地址;
然後交換，如果我們把他訓練的一點點，
他有可能開車到該地址，可以這麼說，
X，和有改變，然後開車到y的地址，
數，即使沒有實際得到，自己這些值的副本，
因此，即使我們談到這個作為主要的記憶體
作為交換的內存，強大的和危險的C
的是，任何函數可以觸摸內存在計算機中的任何地方，
這是強大的，你可以做很花哨的東西，計算機程序C.
這是很危險的，因為你也可以很容易搞砸了。
事實上，一個最常見的方式的方案，這些天被利用
仍是一個程序員沒有意識到
他或她被允許的數據
要被寫入存儲器中的一個位置不打算。
>> 例如，他或她聲明一個數組大小為10
但後​​來意外地試圖把11個字節到該數組的內存，
你開始接觸的內存部分不再有效。
只是為了上下文此，有些人可能知道，
軟件經常會提示您輸入序列號或註冊鍵，
的Photoshop和Word這樣的程序。
存在裂縫，你們有些人知道，網上，您可以運行一個小程序，
瞧，沒有更多的請求的序列號。
如何工作？
在許多情況下，這些東西都只是尋求在電腦
在計算機的實際零和一的文本段
其中是，其中被請求的序列號的功能，
您覆蓋空間，在程序運行時，
你可以找出其中的關鍵是實際存儲
使用一些所謂的調試器，你可以破解軟件的方式。
這是不是說，這是我們的目標，在未來幾天，
但它具有非常現實世界的後果。
這發生的涉及盜竊軟件，
但也有妥協的整個機器。
>> 事實上，當網站這幾天都在利用
和妥協的數據被洩露和被竊取密碼
這往往涉及到一個人的記憶管理不善，
或者，在數據庫的情況下，未能預見
對抗性的輸入，所以更多的是在未來幾週內，
但現在只是一個先睹為快的那種傷害，你可以做
不太了解引擎蓋下是如何工作的。
讓我們去了解，這是為什麼打破
一個工具，將成為越來越多的有用
因為我們的課程變得更加複雜。
到目前為止，當你在你的程序中有一個錯誤
你如何調試了嗎？
你有什麼技術迄今為止，無論是你的TF教
或只是自學成才的嗎？
[學生]的printf。
printf的，因此我們知道printf有可能是你的朋友，如果你想看到的
這是怎麼回事，在你的程序
你只是在這裡把輸出，輸出在這裡，輸出在這裡。
然後運行它，你會得到一大堆的東西在屏幕上
，然後你可以用它來推斷出什麼是真正在你的程序錯誤。
>> printf的往往是一個非常強大的東西，
但它是一個非常手動過程。
你必須把這裡的printf，是printf這裡，
如果你把它裡面的一個循環，你可能會得到100行
的輸出，你就必須通過篩選。
這不是一個非常用戶友好的調試程序或互動機制，
但幸運的是存在替代品。
有一個程序，例如，GDB，GNU調試器，
這是一個有點神秘的，你如何使用它。
這是一個有點複雜，但坦率地說，
這是一個的東西在那裡，如果你把在本週和未來
額外的一小時了解類似GDB
從長遠來看，它可能會為你節省幾十個小時，
所以，讓我給你一個傳情的這個東西是如何工作的。
>> 我在我的終端窗口。
讓我繼續前進，編譯這個程序，buggy3。
這已經是最新的。
讓我運行它，就像我們做了一段時​​間後，而事實上，它打破了。
但是，這是為什麼？也許是我搞砸了交換功能。
也許它的A和B。我不是很感動他們周圍是否正確。
讓我繼續這樣做。
而不是僅僅buggy3，而不是讓我運行這個程序，GDB，
我要告訴它運行buggy3，
我要包括一個命令行參數，TUI，
我們會把這規格提醒未來的問題。
而現在這個黑和白的接口彈出，再次，
是有點勢​​不可擋，因為這一切
保修信息到這裡，但至少有一些熟悉的東西。
在窗口頂部的是我的實際代碼，
如果我向上滾動，在這裡讓我滾動到最頂端的我的文件，
而事實上，在此窗口底部有buggy3.c，並通知
我有這樣的GDB提示。
>> 這是我的正常的約翰·哈佛提示不一樣的。
這是一個提示，是怎麼回事，讓我來控制GDB。
GDB調試器。
調試器是一個程序，讓你走過
一行行的執行你的程序行，
前進的道路上，做任何你想要的程序，
即使調用函數，或尋找，更重要的是，
在各種變量的值。
讓我們繼續前進，並做到這一點。
我會繼續前進，在運行中輸入GDB的提示符下，
所以注意在屏幕的左下方，我輸入的運行，
和我已經打輸入，和什麼做呢？
它的字面運行我的程序，但我並沒有真正看到很多在這裡
因為我還沒有告訴調試器
暫停在一個特定的時刻。
只需鍵入運行，運行該程序。
我沒有看到任何東西。我不能操縱它。
>> 而是讓我這樣做。
在此GDB提示符下，讓我，而不是鍵入突破，進入。
這不是我的意思是什麼類型的。
讓我們，而不是主要鍵入休息。
換句話說，我想設置一個斷點，
這是恰當地命名，是因為它會破壞或暫停
執行你的程序在特定的地方。
主要是我的函數的名稱。
請注意，GDB是非常聰明的。
想通了，主要發生在大約在第18行開始
的buggy3.c，然後注意到這裡在左上角
B +第18行是正確的旁邊。
那是在提醒我，我已經在第18行設置一個斷點。
這一次，當我鍵入run，我要運行我的程序
直到它擊中斷點，
這樣的程序將暫停，我在第18行。
在這裡，我們去運行。
什麼也沒有發生，但通知左下角
啟動程序，buggy3，斷點1在主在buggy3.c第18行。
我現在能做些什麼呢？
>> 請注意，我可以開始輸入打印類的東西，
不是printf，打印x，而現在很奇怪。
1美元的僅僅是一個好奇心，我們會看到
每次你打印的東西，你會得到一個新的美元價值。
這是如此，你可以參考以前的值，以防萬一，
但現在打印告訴我的是，在這個故事中的點x的值
顯然是134514032。
什麼？在哪裡，即使是從何而來呢？
[聽不見的學生]
事實上，這就是我們要調用一個垃圾值，我們還沒有談到這一點，
但原因，你初始化變量
顯然，讓他們有一定的價值，你希望他們有。
但問題是這樣，就可以聲明變量
像我剛才在我的適馬的例子
實際上是給他們一個值。
回想我做了什麼，在這裡西格瑪。
我宣布n，但是什麼樣的價值，我給它呢？
沒有，因為我知道，在接下來的幾行
調用getInt會照顧的問題，把裡面的值的n。
>> 但在這一點上在第11行的故事
和線12和線13和第14行
在那些幾行n的值是什麼？
在C語言中，你只是不知道。
這是一些垃圾的價值，有些完全是隨機的數字
剩下的基本上是從以前的一些功能
已運行，這樣你的程序運行
記得函數獲取函數，函數，函數。
所有這些幀被放到內存中，然後這些函數的返回，
就像我建議用橡皮擦最終被重複使用他們的記憶。
好了，它只是恰巧在這個程序，這個變量x
似乎已經包含了一些垃圾的價值，如134514032
從以前的一些功能，而不是我寫的。
這可能是有效的操作系統的東西來，
引擎蓋下的一些功能。
>> 好了，這很好，但現在，讓我們進入到下一行。
如果我在我的GDB提示符中鍵入“下一步”，我按下回車鍵，
注意突出顯示向下移動到第19行，
但合乎邏輯的言下之意是，第18行
現在已經執行完畢，所以如果我再輸入“打印X”
我現在應該看到，事實上，我做的。
同樣，美元的東西是一個GDB提醒你的方式
打印的歷史是什麼，你已經完成了。
現在讓我和打印輸出Y，而事實上，y是一些瘋狂的價值，以及，
但沒有什麼大不了的，因為在第19行中，我們將其分配給
值2，所以讓我再次鍵入“下一步”。
現在，我們正上的printf線。
讓我做打印x。
讓我做印刷品Y。坦率地說，我有點累了印刷本。
讓我，而不是鍵入“顯示x”和“顯示Y”
現在每次我在未來鍵入命令
我會想起什麼x和y，x和y，x和y是什麼。
>> 我還可以，順便說一句，在“信息當地人類型。”
信息是一種特殊的命令。
當地人意味著它讓我看到局部變量。
以防萬一我忘了這是一個瘋狂的，複雜的功能
我或其他人編寫的信息當地人會告訴你
什麼是這裡面的本地函數的所有局部變量
如果你想閒逛，你可能會關心。
現在，printf是執行，所以讓我繼續前進，只需鍵入“未來”。
因為我們是在這樣的環境中，我們實際上沒有看到它
執行下來，但要注意它變得有點錯位。
但是請注意，它的首要屏幕上出現，
所以它不是一個完美的方案，但是這沒關係，因為我可以隨時閒逛
如果我想使用打印。
>> 讓我再輸入下，現在這裡是最有趣的部分。
在這一點上在故事y是2，x是1，
的建議，並再次，
這是自動顯示的原因是因為我使用的命令
顯示x和顯示Y，I型下的那一刻
x和y在理論上應該成為交換。
現在，我們已經知道這是不會的情況下，
但我們會看到一個時刻，我們如何能更深入地找出原因，這是真的。
下一步，不幸的是，Y仍然是2，x是1，我可以證實盡可能多的。
打印x，印刷品Y。
事實上，沒有交換實際上已經發生了，所以讓我們開始這個問題。
顯然，交換被打破了。
的，而不是讓我們再次鍵入“運行”。
讓我說是的，我要重新啟動它從一開始，進入。
>> 現在，我回來了在第18行。
現在，注意到x和y的值再次是垃圾。
下一步，下一步，下一步，下一步。
如果我感到無聊，我也只需要輸入n轉到下一個。
您可以縮寫，以最短的字符序列。
現在被破壞掉。
我們來看看，而不是輸入下，
現在，我要輸入步驟，加強，使我裡面的這個函數
這樣我就可以穿過它，所以我打步驟，然後輸入。
注意突出跳下在我的程序中第36行。
現在的局部變量是什麼？
信息本地人。
沒有，只是還沒有，因為我們還沒有得到該行，
所以讓我們繼續前進，並說：“下一個。”
現在，我們似乎，有tmp目錄，打印TMP。
垃圾的價值，對不對？我是這麼認為的。
如何打印，打印B，1和2嗎？
在某一時刻，只要我再輸入下
tmp是將要採取的值為1，希望，
因為tmp目錄將被分配的值。
>> 現在，讓我們做打印，頁B，
但現在打印tmp，以及它的確是1。
讓我做下一個。讓我做下一個。
我已經完成了交換功能。
我還在裡面，它在第40行，所以讓我打印，
打印B，我不關心tmp是什麼。
它看起來像掉期是正確的，當談到交換a和b。
但是，如果我現在鍵入下，我跳回到第25行，
當然，如果我在x和印刷品Y型
他們仍然是不變的，所以我們沒有固定的問題。
但診斷也許這GDB程序
至少我們已經變得更近了一步的了解
這是怎麼回事錯誤，不亂拋垃圾，我們把一個printf的代碼，
輸出，輸出，然後運行一遍又一遍
試圖找出什麼地方出了錯。
>> 我要繼續前進並退出這完全退出。
這是怎麼回事，然後說，“要離開嗎？”是。
現在，我回到了我的正常提示，我使用GDB。
順便說一句，你不需要使用這個TUI標誌。
事實上，如果你忽略它，你基本上是在屏幕的下半部分。
如果我然後鍵入突破主，然後運行
我仍然可以運行我的程序，但它會做的是文本上
你給我的當前行一次一個。
TUI，文本用戶界面，
只能說明你的程序一次，這可能是有點概念上更容易。
不過說實在的，我只是做下一個，下一個，下一個，
我看到一個在一個時間線，如果我真的想看看會發生什麼
我可以輸入列表，看到一大堆的相鄰線路。
>> 有一個視頻，我們問過，你看問題集3
內特覆蓋一些GDB的複雜性，
這是一個人的東西，說實話，你的一些不平凡的百分比
再也不會去碰GDB，這將是一件壞事
因為從字面上你會花更多的時間，這學期
追錯誤，那麼你如果你把在這半小時/小時
本週和下週的學習，獲得舒適的使用GDB。
printf的是你的朋友。
GDB現在應該是你的朋友。
>> 對GDB的任何問題？
這裡有一個快速的一些最強大，最有用的命令列表。
是啊。>>你可以打印一個字符串？
你可以打印一個字符串？當然可以。
它不具有只是整數。
如果一個變量s是一個字符串類型的打印小號。
它會告訴你是什麼字符串變量。
[聽不見的學生]
它會給你的地址和字符串本身。
它會告訴你。
最後一件事，只是因為這是好知道的太多。
回溯和框架，讓我潛入這是最後一次，
GDB完全相同的程序。
讓我繼續運行的文本用戶界面版本，
打破為主。
讓我繼續前進，再次運行。我在這裡。
現在讓我去下一個，下一個，下一個，下一個，下一個步驟中，輸入。
>> 現在假設我現在在交換故意的，但我很喜歡“媽的，什麼是x的值嗎？”
我不能做X了。
我不能做y，因為他們不在範圍內。
他們不是在上下文中，但沒有問題。
我可以輸入回溯。
這說明我已經執行了這個時間點的所有的功能。
請注意，一個在底部，主，線與主
這裡是我們的圖片的底部。
事實上，交換與交換在它上面的內存是它上面的線，
如果我想暫時回到主，我可以說，“框架”。
幾號？主要是幀＃1。
我要繼續前進，並說：“第1幀”。
>> 現在我的主，我可以打印x，我可以印刷品Y，
但我無法打印或b。
但我可以的，如果我說，“好吧，請等待一分鐘。交換在哪裡？”
讓我繼續說：“第0幀。”
現在我回來了，我想是的，和順便說一句，
也有其他命令一樣，如果你​​真的感到無聊打字下一步，下一步，下一步，下一步，
一般情況下，你可以說“下一個10的事情，”和，將逐步在未來10行。
你也可以寫“繼續”時，你真的厭倦了單步運行它。
繼續運行你的程序沒有中斷，直到碰到另一個斷點，
無論是在一個循環或降低在你的程序中。
>> 在這種情況下，我們繼續到最後，程序正常退出。
這是一種奇特的方式，劣質的過程。
只要你的程序正常退出。
更多的視頻和調試會話來。
這是一個很大。
讓我們把我們的5分鐘的休息時間，在這裡，我們將返回結構和文件。
>> 如果你已經一頭扎進這個星期的pset中
你就會知道，我們使用的分佈代碼，
為出發點，一些新的技術，我們為您提供的源代碼。
特別是，我們推出了一個新的關鍵字稱為struct結構，
這樣我們就可以創建自定義的各種變量。
我們還介紹了文件I / O，文件輸入和輸出的概念，
這是使我們能夠保存狀態
爭奪董事會光盤上的文件
這樣的教學研究員，我可以理解
你的程序內部發生了什麼事情，而無需手動播放
幾十場比賽的爭奪。
我們可以做更多automatedly的。
>> 這個想法的結構解決了一個相當引人注目的問題。
假設我們要實現的一些程序
，不知怎的，對學生的信息跟踪，
和學生可能具有，例如，一個ID，一個名稱
和一所房子在哈佛這樣的地方，所以這3個信息
我們要保持周圍，所以讓我繼續前進，開始在這裡寫了一個小程序，
包括stdio.h中。
讓我包括cs50.h.的
然後開始我的主要功能。
我不會打擾任何命令行參數，
在這裡，我想有一個學生，所以我說
一個學生都有一個名字，所以我會說“字符串名稱。”
然後我說一個學生，也有一個ID，所以int ID，
學生有一所房子，所以我也說“字符串房子。”
然後，我會為了這些更乾淨一點是這樣的。
好吧，現在我有3個變量代表一個學生，這樣的學生。“
>> 現在我要來填充這些值，所以讓我繼續前進，這樣說
“ID = 123”。
名稱是會得到大衛。
比方說，房子是會得到奧美，
，然後我要做的事情，隨意如printf（“％s，
的ID是％d，住在％s。
現在，我要在這裡堵塞，一前一後？
姓名，身份證，房屋返回0。
好吧，除非在此我搞砸了
我認為我們有一個不錯的方案，存儲一個學生。
當然，這不是那麼有趣。如果我想有2名學生？
這沒什麼大不了的。我可以支持2人。
讓我去，並強調這一點，去這裡，
我可以說“ID = 456”像羅布人住在華盛頓州Kirkland的人。
>> 好了，等待，但我不能把這些同樣的事情，
它看起來像我要複製，
所以讓我說，這將是大衛的變量，
並讓我得到一些副本，這些羅布。
我們會打電話給這些Rob的，但，這是行不通的，現在
因為我已經等待，讓我們改變了我的ID1，name1和house1。
羅布將是2，2。
我已經改變了這裡，這裡，這裡，這裡，這裡，這裡。
等待，湯米？讓我們再這樣做。
顯然，如果你仍然認為這是一個很好的方式，這樣做，不是的話，
所以複製/粘貼壞。
但是，我們解決了這一個星期前。
>> 我們的解決方案時，我們希望有相同的數據類型的多個實例嗎？
[學生]一個數組。
一個數組，所以讓我嘗試清理它。
讓我為自己出一些空間的頂部，而不是讓我在這裡做。
我們會打電話給這些人，而不是我會說“詮釋IDS，”
我要支持我們現在。
我會說“字符串名稱”，我會支持我們，
然後，我會說“字符串的房子，”我要支持我們。
現在，在這裡，而不是大衛得到他自己的局部變量
我們可以擺脫這些。
這感覺很好，我們正在清理這個。
然後，我可以說大衛將是[0]和名稱[0]
房子[0]。
然後搶，我們同樣可以省了。
讓我們把這個在這裡，所以他是怎麼回事，隨意入侵檢測系統[1]。
他的名字[1]
然後最後，房屋[1]。
>> 還是有點繁瑣，現在我已經明白這一點，
因此，讓我們說：“名[0]，ID [0]，房屋[0]
的複數此。
入侵檢測系統，入侵檢測系統，入侵檢測系統。
再次，我這樣做，如此反复，我已經訴諸再次複製/粘貼，
所以賠率是有另一種解決方案。
我也許可以清理，進一步加快循環或類似的東西，
總之，這是好一點，但仍然感覺像
我訴諸複製/粘貼，但即使這樣，我要求，
是不是真的從根本上正確的解決方案，因為
如果某個時候，我們決定你知道嗎？
我們真的應該存儲電子郵件地址為大衛和Rob
每個人都在這個程序。
我們也應當存儲的電話號碼。
我們也應該儲存緊急聯絡電話號碼。
我們有所有這些作品，我們要存儲的數據，
那麼你如何去這樣做呢？
>> 可以聲明另一個數組中的頂部，然後手動添加
[0]，[1]的電子郵件地址的電子郵件地址
大衛和Rob等等。
但真的只是一個假設這樣的設計
我使用的是榮譽系統知道
[i]的每個的多個陣列
恰好指的是同一個人，
[0] IDS中的編號為123，
我要去承擔，名字[0]
是同一個人的名字和房子[0]
是同一個人的房子等等，我創造的所有的不同的陣列。
但是請注意，有沒有根本的聯繫
除這3個信息，id，name和房子，
即使我們正在努力模型，這個程序是實體，而不是數組。
數組是這一綱領性的方式這樣做。
我們真正想要的模型在我們的節目是一個人
像大衛一樣，像Rob內，其中一個人
或封裝的名稱和ID和一所房子。
>> 我們可以以某種方式表達這種思想的封裝
由此一個人有一個ID，一個名稱和一個房子
而不是這個黑客真的，我們只是
相信，支架的東西
指的是同一人在這些不同的陣列的實體？
事實上，我們可以做到這一點。
讓我去上面的主，現在，讓我創建自己的數據類型
確實是第一次。
我們使用這種技術的爭奪，
但在這裡，我要繼續前進，並創建一個數據類型，
你知道嗎，我現在就打電話給學生或個人，
我要使用typedef定義一個類型。
我會說，這是一個結構，
那麼這個結構類型的學生，我們會說，
即使這是一個對我來說有點過時了。
我們會說：“int的ID。”
我們會說：“字符串名稱。”
然後，我們會說：“的字符串房子，”
所以現在年底的這幾行代碼
我剛才教鐺存在
除了int類型的數據類型，除了字符串，除了增加一倍，除了花車。
>> 11在時間線的這一刻，現在有一個新的數據類型，稱為學生，
現在我學生可以聲明一個變量，任何地方，我想，
所以讓我向下滾動這裡的人。
現在我可以擺脫這種，我可以回去大衛在這裡，
和大衛，其實我可以說，大衛，
我們可以從字面上命名變量照顧自己，
將是類型的學生。
這可能看起來有點怪，但是這還不是全部，不同的
作為一個int或一個字符串或浮點數申報的東西。
碰巧的是被稱為學生的現在，
如果我想這種結構把裡面的東西
我現在要使用新的語法，但它是非常簡單的，
david.id = 123，david.name =“大衛”在資本ð，
david.house =“奧美”
現在我可以擺脫這東西在這裡。
請注意，我們現在已經重新設計我們的計劃確實是一個更好的方法
現在，我們的節目反映了真實的世界。
>> 有一個現實世界的概念，一個人或一個學生。
在這裡，我們有一個人或更具體的學生的C版本。
裡面的那個人是這些相關的特性，
ID，名稱和房子，所以羅布基本上變成同樣的事情，在這裡，
讓學生搶，現在rob.id的= 456，
rob.name =“搶”。
事實上，該變量被稱為羅布是一種毫無意義的。
我們可以把它叫做x或y或z。
我們只是把它命名為搶在語義上是一致的，
但真正的名字是裡面​​的那場，
所以現在我有這個。
這也是不覺得自己是最優秀的設計，我已經硬編碼的大衛。
我硬編碼的羅布。
我還是要採取一些複製和粘貼的時候，我想新的變量。
此外，我顯然給每個變量的名稱，
即使我寧願描述這些變量
更一般的學生。
>> 現在，我們可以合併的想法，一直致力於為我們的
，而是說：“你知道嗎，給我一個變量所謂的學生，
，讓我們有它的大小為3，“所以現在我可以進一步細化此，
擺脫手動聲明的大衛，
相反，我可以說學生一樣的東西[0]在這裡。
然後，我可以說，學生[0]在這裡，
學生[0]在這裡，等等，我可以去轉轉
和清理羅布。
我也可以去，現在可能增加循環
使用GetString和調用getInt從用戶獲取這些值。
我可以加上一個常數，因為這是不好的做法
硬編碼的，有些像在這裡任意數量
，然後只需記住，你應該不超過3名學生在。
它可能是更好的在我的文件的頂部使用＃define
因素說了出來，的確，讓我去和推廣。
>> 讓我打開了一個例子，在今天的
例子提前structs1。
這是一個比較完整的程序，使用＃定義在這裡
並說，我們要默認​​情況下，有3名學生。
在這裡，我聲明一個類學生的價值，
所以教室裡的學生，現在我使用的是循環
只是為了使代碼更優雅的一點，填充類
與用戶的輸入，所以循環從i = 0上的學生，它是3。
然後，我提示用戶在這個版本中
什麼是學生的ID，我得到它與調用getInt。
什麼是學生的名字，然後我得到它的GetString。
學生的家是什麼？我得到它的GetString。
然後在底部在這裡，我決定改變
我如何打印這些和實際使用的循環，
我是誰打印？
根據我的評論我打印Mather中的任何人，
這就是它所以羅布和Tommy等等，其實湯米的Mather中。
湯米和大衛將被打印在這種情況下，這是怎麼工作的？
我們還沒有看到這個功能，但猜測這是什麼做的。
比較字符串。
>> 如何比較字符串，因為事實證明，這是一個有點非明顯
如果返回0，表示的字符串是相等的。
如果返回-1，這意味著人來之前，其他的字母順序，
如果返回+1，這意味著其他的字來按字母順序
前，你可以看看網上的手冊頁
它說，看究竟哪一種方式是，但是這一切現在正在做的是
如果[i]的房子是等於“奧美”
然後繼續前進，打印出來，並在奧美也是如此。
但在這裡我們還沒有看到過的東西，我們會回到這個。
我不記得曾經在我的程序中做到這一點。
免費顯然是指內存，釋放內存，
但什麼記憶，我明顯地釋放在這個循環的底部，這個程序嗎？
它看起來像我釋放一個人的名字
和一個人的房子，但為什麼會這樣？
>> 原來，這幾個星期，你已經使用GetString
我們已經被引入到你的程序中的每一個錯誤。
GetString的設計分配內存，因此它可以返回一個字符串，
像大衛一樣，羅布，和你就可以做任何你想要的
以該字符串在你的程序中，因為我們已經為您保留內存。
問題是每到這個時候，你需要調用getString
GetString的作者，​​我們已經要求操作系統
給我們一個位RAM的字符串。
給我們一個位的RAM，這一個字符串。
給我們一些更多的RAM，這一個字符串。
你，程序員，從來沒有做什麼
給我們，恢復記憶，
所以這幾個星期，你寫的所有程序
有什麼所謂的內存的飛躍，讓他們繼續使用
越來越多的內存每次調用GetString，這很好。
我們刻意做的第一週，因為它是不是很有趣
有擔心的字符串是來自哪裡。
所有你想要的是這個詞搶回來當用戶鍵入它。
>> 但是向前發展，我們現在必須開始對這個變得越來越複雜。
任何時候，我們分配內存，我們最終把它。
否則，在現實世界中，在您的Mac或PC，你可能偶爾有經驗豐富的
在您的計算機可能爛尾最終的症狀
或愚蠢的紡紗沙灘球只是佔用計算機的
全部精力，你不能做的事情。
這可以解釋為任意數量的錯誤，但在這些可能的錯誤
事情稱為內存洩漏，有人是誰寫的一塊軟件
你不記得，以便釋放內存
他或她問的操作系統，
不使用GetString，因為這是一個CS50的事情，但使用類似的功能
問操作系統的內存。
如果你或他們搞砸了，從來沒有真正返回該內存
一個程序，可以減緩放緩和減慢的症狀，
除非你記得打電話免費。
>> 我們會回來的時候，為什麼你會打電話免費，
但讓​​我們繼續前進的好措施，並嘗試運行特定的程序。
這被稱為structs1，請輸入。
讓我繼續運行structs1的，123，大衛·馬瑟
456，789，羅布·柯克蘭，
湯米·馬瑟，我們看到大衛的Mather中，湯米Mather中。
這僅僅是一個小的完整性檢查程序的工作。
現在，不幸的是，這個方案是一個有點沮喪，
我做過的一切工作，我輸入了9種不同的字符串，點擊進入，
被告知是誰在奧美，但很明顯，我知道是誰在奧美已經定了，因為我輸入的。
至少這將是很好，如果這個計劃更像是一個數據庫
它實際上還記得我所輸入的
所以我永遠不會再有輸入這些學生記錄。
也許這是像registrarial系統。
>> 為此，我們可以使用這種技術被稱為文件I / O，文件輸入和輸出，
一個非常通用的方法，說任何時候你想要讀取文件或寫入文件
一組特定的功能，你可以做到這一點。
讓我繼續並打開這個例子structs2.c，
這幾乎是相同的，但讓我們來看看它現在所做的。
在該文件的頂部，我宣布一個班的學生。
我然後填充類用戶的輸入，
所以這些代碼行之前是完全一樣的。
然後，如果我向下滾動，在這裡我打印大家誰是Mather中任意像以前一樣，
但是，這是一個有趣的新功能。
這兩行代碼是新的，他們在這裡介紹一些，
FILE，全部大寫，並且它有*在這裡也。
讓我搬過來，*在這裡。
>> 這個功能，我們還沒有看到之前，FOPEN，
但它意味著打開文件，讓我們翻閱這些，
這是我們會回來的東西在未來的pset，
但此行基本上是在這裡打開一個名為“數據庫，
具體地說，它以這樣一種方式，它可以做它打開？
[聽不見的學生]
對，所以“W”只是意味著它告訴操作系統
以這樣的方式，我可以寫它，打開此文件。
我不想讀它。我不想只是來看看。
我想改變它，添加的東西可能，
和文件將被稱為數據庫。
這可能是什麼。
這可能是database.txt。這可能是分貝。
如foo這可能是一個詞，但我隨意選擇命名的文件數據庫。
這是一個小的完整性檢查，我們會回來的很詳細隨著時間的推移，
如果fp文件指針，不等於NULL，這意味著一切都很好。
>> 長話短說，像fopen的功能有時會失敗。
可能是文件不存在。也許你的磁盤空間。
也許你沒有該文件夾的權限，
因此，如果FOPEN返回null的東西糟糕的事情發生。
相反，如果FOPEN沒有返回null一切都很好
我就可以開始寫這個文件。
這裡有一個新的伎倆。
這是一個for循環遍歷每個學生，
這看起來如此的相似，我們做了什麼之前，
但這個函數是一個表姐的printf稱為fprintf文件輸出，
並注意在只有2種方式是不同的。
一，它開始用f代替p，
但後​​來它的第一個參數顯然是什麼？
[學生]文件。這是一個文件。
這件事稱為FP，我們將最終梳理出一個文件指針是什麼，
但現在FP僅僅代表我已經打開的文件，
fprintf這裡說的文件打印用戶的ID，而不是在屏幕上。
打印用戶的名稱的文件，而不是在屏幕上，
房子的文件，而不是在屏幕上，然後在這裡，很明顯，
關閉該文件，​​然後在這裡釋放內存。
>> 這個版本2和版本1之間的唯一區別
是fopen和引進此文件*
這個概念fprintf，讓我們看看最終的結果是什麼。
讓我進入我的終端窗口。
讓我跑structs2，進入。
看起來一切都很好。讓我們重新運行structs2。
123，456，羅布·柯克蘭，大衛·馬瑟，
789，湯米·馬瑟進入。
看起來像它的表現是相同的，但如果我現在做的LS
注意到什麼文件是在這裡，在我所有的代碼，數據庫，
讓我們打開的是，gedit的數據庫，看看。
這不是最性感的文件格式。
這真的是每行，每行一條數據線，
但那些你們誰使用Excel或CSV文件，逗號分隔值，
當然，我可以用fprintf，而不是可能做這樣的事情
這樣我就可以創建一個Excel文件，相當於
分離用逗號，不只是新的生產線。
>> 在這種情況下，如果我，而不是使用逗號，而不是新的生產線
我可以從字面上如果我在Excel中打開該數據庫文件，而不是看起來像這樣。
總之，現在我們有能力寫入文件
我們現在可以開始持久化數據，保持光盤上
這樣我們就可以保持信息的周圍一遍又一遍。
注意其他的東西，現在有點熟悉的一對夫婦。
在這個C文件的頂部，我們有一個typedef
因為我們想創建一個數據類型，它表示一個字，
所以這種類型被稱為字，和內部的這種結構
這是一個小票友。
為什麼一個字組成的，顯然是一個數組？
什麼是一個詞，僅僅憑直覺？
>> 這是一個字符數組。
這是一個字符序列，背靠背。
全部大寫的字母恰好是我們武斷地說，最大長度
任何字在字典中，我們使用的爭奪。
為什麼我有一個+1？
空字符。
記得當我們做了Bananagrams的例子，我們需要一個特殊的值
的詞語的結尾處，以跟踪
在的話實際上結束的情況下，作為問題集規範說
在這裡，我們正在與一個給定的單詞一個布爾值，
一個標誌，可以這麼說，真或假。
你有沒有發現這個詞，因為我們意識到
我們真正需要的一種方式記憶不僅是一個字是在爭奪
但是否你的人，已經找到了
所以，如果你發現這個詞“：”你不能只鍵入，進入，進入，進入
並得到3分，3分，3分，3分。
我們希望能夠黑名單這個詞通過設置一個布爾值，
為true，如果你已經發現了，所以這就是為什麼我們
封裝在該結構中。
>> 現在，在這裡爭奪，這種結構稱為字典。
缺少這裡是字的typedef，因為在這種情況下
我們需要封裝的一本字典的想法，
和一本字典包含了一大堆的話，
這個數組所暗示的，和那些話是多少呢？
好吧，不管說這個變量的大小。
但我們只需要一個字典。
我們並不需要的數據類型稱為字典。
我們只需要其中的一個，所以在C
如果你不說的typedef，你剛才說的結構，然後在大括號中
你把你的變量，然後你把這個名字。
這是聲明一個變量稱為字典
像這樣的。
與此相反，這些行調用Word創建一個可重複使用的數據結構
您可以創建多個副本，就像我們創建
學生的多個副本。
>> 這是什麼最終讓我們做什麼？
讓我回去，比方說，一個簡單的例子，從簡單的時代，
讓我開了，讓我們說，compare1.c。
的問題，在這裡實際上是剝開
層的一個字符串，並開始起飛訓練車輪
因為它把一個字符串的所有時間
我們承諾在第1週真的只是一個暱稱，
CS50庫的東西，看起來多了幾分神秘的代名詞，
是char *，我們已經看到了這顆恆星。
我們看到它在文件中。
>> 現在，讓我們看到為什麼我們一直躲在這個細節有一段時間了。
這裡是一個名為compare1.c，
它顯然要求用戶為2個字符串，s和t，
然後，它試圖比較這些字符串平等的第26行，
如果他們是平等的說，“你輸入同樣的事情。”
如果他們不相等，它說，“您輸入不同的事情。”
讓我繼續運行這個程序。
讓我進入我的源目錄，做一個比較1。編譯沒問題。
讓我運行比較。
我會放大，進入。
說些什麼。 HELLO。
我會說些什麼了。 HELLO。
我絕對沒有輸入不同的東西。
>> 讓我再試一次。 BYE BYE。
絕對沒有什麼不同，所以在這裡發生了什麼事？
那麼，什麼是真正被比較的第26行嗎？
[聽不見的學生]
是的，所以它變成了一個字符串，數據類型，是一種善意的謊言。
一個字符串，是一個char *，但什麼是一個char *？
，正如他們所說的，是一個char *指針，
和一個指針是一個有效的地址，
一筆在內存中的位置，如果你恰好有輸入一個字，如HELLO，
回憶起過去的討論中的字符串
之類的詞，這是HELLO。
請記住，一個詞可以表示喜歡HELLO
作為一個字符數組，這樣
然後用一個特殊字符結束時稱為空字符，
\表示。
實際上是一個字符串是什麼？
請注意，這是多的內存塊，
而事實上，它的結束是唯一的已知的，一旦你通過整個字符串
尋找特殊的NULL字符。
但是，如果這是一個從我的電腦的內存中的內存塊，
讓我們武斷地說，這個字符串只是很幸運，
它被認為是放置在開始的時候，我的電腦的RAM。
這是字節0，1，2，3，4，5，6 ...
>> 當我說類似的GetString和我做字符串s = GetString的
什麼是真正的回來了嗎？
為這些過去的幾個星期，真的被儲存在s
是不是這個字符串本身，而是在這種情況下，被存儲的是
因為GetString的確實數0
它是物理上不返回一個字符串。
甚至沒有真正概念上的意義。
它的回報率是多少。
這個數字是在內存中的地址，
字符串s，然後，如果我們剝開這層，字符串並不真正存在。
這只是一個簡化的CS50庫中。
>> 這真的是所謂的char *。
字符是有道理的，因為什麼是一個詞，像HELLO？
嗯，這是一系列的字符，字符系列。
字符*表示一個字符的地址，
所以這是什麼意思返回一個字符串？
一個不錯的，簡單的方法，返回一個字符串，
而不是試圖找出如何我返回到5或6個不同的字節
讓我回到哪個字節的地址？
第一個。
換句話說，讓我給你一個字符在內存中的地址。
這就是字符“*”代表一個單一的字符在內存中的地址。
調用該變量s。
存放在那個特定的地址，我隨意說的是0，
只是為了讓事情簡單，但在現實中，它通常是一個比較大的數字。
>> 等待一分鐘。
如果你只給我的第一個字符的地址，我怎麼知道的地址是什麼
第二個字符，第三，第四和第五？
[聽不見的學生]
你只知道結尾的字符串的方法是通過這個方便的竅門，
因此，當你使用的東西像printf，printf的變相作為它的參數，
還記得我們用％s佔位符，然後你傳遞
變量的存儲字符串。
你真正傳遞的是該字符串的第一個字符的地址。
的printf然後使用for循環或while循環在收到該地址，
例如，0，所以讓我現在這樣做，
輸出（“％s \ n”）;
當我調用printf（“％s \ n”）;我真正提供輸出與
在s中的第一個字符的地址，在這種任意的情況下，這是H。
>> printf的知道如何顯示在屏幕上，究竟是什麼？
的人誰執行printf的實現了一個while循環或循環
說這個字符等於空字符？
如果沒有，打印。這個怎麼樣？
如果不能打印，打印出來，打印出來，打印出來。
哦，這是特殊的。停止打印，並返回給用戶。
這是字面上所有的引擎蓋下發生的，
這是一個很大消化的第一天，一類，
但現在它是真正了解一切的基石
已經持續我們的電腦的內存內的，
，最終，我們會逗除了一點點幫助
我們的一個朋友在斯坦福大學。
>> 在斯坦福大學的教授尼克Parlante已經這樣做了精彩的視頻序列
從各種不同的語言，介紹
這個小的黏土動畫人物Binky。
你的聲音，聽到在短短的幾秒鐘先睹為快
是斯坦福大學教授，你要
現在只有5或6秒的這一權利，
但是這是說明我們將結束今天
（星期三）開始。
我給你賓基，預覽的指針樂趣。
[♪音樂♪]教授Parlante]嘿，賓基。
喚醒。它的時間的指針樂趣。
[賓基]那是什麼？了解指針嗎？
哦，好極了！
>> 我們將看到你在週三。
[CS50.TV]