[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]