1 00:00:00,000 --> 00:00:02,730 [Powered by Google Translate] [第5條:不太舒服] 2 00:00:02,730 --> 00:00:05,180 [內特 - 哈迪森,哈佛大學] 3 00:00:05,180 --> 00:00:08,260 這是CS50。[CS50.TV] 4 00:00:08,260 --> 00:00:11,690 所以歡迎回來,伙計們。 5 00:00:11,690 --> 00:00:16,320 第5節。 6 00:00:16,320 --> 00:00:20,220 在這一點上,已完成測驗,並看到了你所做的, 7 00:00:20,220 --> 00:00:25,770 希望你覺得真的很不錯,因為我的分數在本節留下了非常深刻的印象。 8 00:00:25,770 --> 00:00:28,050 對於我們的在線觀眾,我們有幾個問題 9 00:00:28,050 --> 00:00:33,680 有關問題上的最後兩個問題 - 或測驗,而。 10 00:00:33,680 --> 00:00:39,690 因此,我們要對這些真的很快,讓大家看到發生了什麼事 11 00:00:39,690 --> 00:00:45,060 以及如何通過實際的解決方案,而不是僅僅查看解決方案本身。 12 00:00:45,060 --> 00:00:50,330 我們要在過去的幾個問題真的很快,32和33。 13 00:00:50,330 --> 00:00:53,240 只是,再次,使在線的觀眾可以看到這一點。 14 00:00:53,240 --> 00:00:59,080 >> 如果你把你的問題是32,第13頁, 15 00:00:59,080 --> 00:01:02,730 13 16 32,問題是所有有關掉期。 16 00:01:02,730 --> 00:01:05,010 這是所有關於交換兩個整數。 17 00:01:05,010 --> 00:01:08,740 這是問題,一對夫婦在演講的時候,我們已經走了。 18 00:01:08,740 --> 00:01:13,590 在這裡,我們要你做的是一個快速的記憶痕跡。 19 00:01:13,590 --> 00:01:17,000 要填寫的值的變量,因為它們是在棧上 20 00:01:17,000 --> 00:01:20,250 的代碼通過這個交換功能。 21 00:01:20,250 --> 00:01:24,500 特別是我們正在尋找的 - 我打算把這款iPad - 22 00:01:24,500 --> 00:01:29,650 特別是,我們看到的是,這條線在這裡6。 23 00:01:29,650 --> 00:01:36,740 而它的編號為6的連續性與前面的問題。 24 00:01:36,740 --> 00:01:41,720 我們想要做的是顯示或標籤的內存狀態 25 00:01:41,720 --> 00:01:46,090 因為它是在的時候,當我們執行這條線6號, 26 00:01:46,090 --> 00:01:52,540 這實際上是一個回報,我們這裡的交換功能。 27 00:01:52,540 --> 00:01:59,450 如果我們向下滾動在這裡,我們看到的一切都在內存中的地址提供給我們的。 28 00:01:59,450 --> 00:02:02,540 這是非常關鍵的,我們會回來的,在短短的時刻。 29 00:02:02,540 --> 00:02:09,240 然後在這裡的底部,我們有一個小的內存圖,我們要參考。 30 00:02:09,240 --> 00:02:12,490 其實我已經做到了這一點,在我的iPad。 31 00:02:12,490 --> 00:02:20,720 所以,我要交替之間來回iPad和這個代碼僅作參考。 32 00:02:20,720 --> 00:02:26,540 >> 讓我們開始。首先,讓我們把注意力集中在這裡的第一對夫婦行的主要。 33 00:02:26,540 --> 00:02:30,220 首先,我們要初始化x為1和y 2。 34 00:02:30,220 --> 00:02:33,040 因此,我們有兩個整型變量,它們都是被放置在棧上。 35 00:02:33,040 --> 00:02:36,050 我們打算把他們的A 1和A 2。 36 00:02:36,050 --> 00:02:43,150 所以,如果我翻轉過來,希望我的iPad,讓我們來看看 - 37 00:02:43,150 --> 00:02:48,660 Apple TV的鏡像,和我們走吧。好吧。 38 00:02:48,660 --> 00:02:51,670 所以,如果我翻轉過來,以我的iPad, 39 00:02:51,670 --> 00:02:56,220 我想初始化x為1和y 2。 40 00:02:56,220 --> 00:03:00,580 我們做到這一點很簡單,寫一個包裝盒中標記為x 1 41 00:03:00,580 --> 00:03:07,730 2包裝盒中標記為Y。相當簡單的。 42 00:03:07,730 --> 00:03:11,620 所以,現在讓我們回到筆記本電腦,看看接下來會發生什麼。 43 00:03:11,620 --> 00:03:15,810 因此,這下一行是在事情變得棘手。 44 00:03:15,810 --> 00:03:28,110 我們傳遞的地址的x和y的地址作為參數a和b的交換函數。 45 00:03:28,110 --> 00:03:32,380 x和y的地址,該地址是我們無法計算的東西, 46 00:03:32,380 --> 00:03:36,360 沒有這些子彈​​點就在這裡。 47 00:03:36,360 --> 00:03:39,750 幸運的是,前兩個要點告訴我們的答案是什麼。 48 00:03:39,750 --> 00:03:44,740 x的地址是10,在存儲器中,存儲器中的y的地址是14。 49 00:03:44,740 --> 00:03:51,870 因此,那些得到的值通過在A和B的向上頂在我們的交換功能。 50 00:03:51,870 --> 00:04:00,760 所以,再一次,切換回我們的圖,我可以寫在10 51 00:04:00,760 --> 00:04:07,400 和14 b中。 52 00:04:07,400 --> 00:04:11,610 現在,這一點是我們進行交換。 53 00:04:11,610 --> 00:04:14,520 所以再次翻轉的筆記本電腦, 54 00:04:14,520 --> 00:04:21,079 我們可以看到,交換的工作方式是我第一次解引用一個,並將結果存儲在tmp。 55 00:04:21,079 --> 00:04:27,650 因此,解引用運算符說,“嘿,治療的變量a的地址的內容。 56 00:04:27,650 --> 00:04:33,830 無論是存儲在該地址,並加載它。“ 57 00:04:33,830 --> 00:04:41,720 你加載的變量將被存儲到我們的TMP變量。 58 00:04:41,720 --> 00:04:45,150 翻轉到iPad。 59 00:04:45,150 --> 00:04:51,690 如果我們去解決10,我們知道地址10是輸出變x 60 00:04:51,690 --> 00:04:55,480 告訴我們,因為我們的子彈點x在內存中的地址是10。 61 00:04:55,480 --> 00:05:00,180 因此,我們可以去那裡,得到了它的價值,這是1,因為我們看到我們的iPad, 62 00:05:00,180 --> 00:05:06,300 並加載到tmp目錄。 63 00:05:06,300 --> 00:05:08,250 再次,這是不是最後的內容。 64 00:05:08,250 --> 00:05:14,350 我們要走過和結束時,我們會得到我們的最終狀態的程序。 65 00:05:14,350 --> 00:05:17,210 但是現在,我們的值為1,存儲在tmp。 66 00:05:17,210 --> 00:05:19,210 >> 在這裡有一個快速的問題。 67 00:05:19,210 --> 00:05:23,980 [亞歷山大]是解引用運算符 - 這只是前面的變量的明星權嗎? 68 00:05:23,980 --> 00:05:27,600 “是的。因此,解引用運算符,當我們打開再次回到我們的筆記本電腦, 69 00:05:27,600 --> 00:05:33,780 這是明星就在眼前。 70 00:05:33,780 --> 00:05:37,460 從這個意義上說,它是 - 你對比乘法運算符 71 00:05:37,460 --> 00:05:42,400 這需要兩件事情:解引用運算符是一元運算符。 72 00:05:42,400 --> 00:05:46,130 剛剛申請到一個值,而不是一個二元操作符, 73 00:05:46,130 --> 00:05:48,810 適用於兩種不同的價值觀。 74 00:05:48,810 --> 00:05:52,080 所以,這就是發生在這條線。 75 00:05:52,080 --> 00:05:58,390 我們裝的值為1,並把它保存到我們的臨時整型變量。 76 00:05:58,390 --> 00:06:05,800 下一行,我們的內容存儲的B - 77 00:06:05,800 --> 00:06:12,630 或者說,我們,b是指向到的地方,一個是指向存儲的內容。 78 00:06:12,630 --> 00:06:17,690 如果我們分析這個由右至左,我們將取消引用b, 79 00:06:17,690 --> 00:06:23,580 我們要解決14,我們要搶的整數,它是有, 80 00:06:23,580 --> 00:06:26,900 然後我們要去的地址10, 81 00:06:26,900 --> 00:06:34,240 我們要拋的結果,我們解引用的b到該空間。 82 00:06:34,240 --> 00:06:40,080 翻轉回我們的iPad,在這裡我們可以使這一點更具體的, 83 00:06:40,080 --> 00:06:44,070 它可能會幫助,如果我在這裡寫號上的所有地址。 84 00:06:44,070 --> 00:06:53,820 因此,我們知道,我們在y地址為14,x是地址10。 85 00:06:53,820 --> 00:07:00,180 當我們開始在B,我們解引用b,我們要抓住的價值2。 86 00:07:00,180 --> 00:07:08,320 我們要抓住這個值,因為是住在地址14的值。 87 00:07:08,320 --> 00:07:15,700 我們打算把它的變量,居住地址10, 88 00:07:15,700 --> 00:07:19,160 這是正確的,相應的變量x。 89 00:07:19,160 --> 00:07:21,810 所以,我們可以做一點點的覆蓋這裡 90 00:07:21,810 --> 00:07:35,380 我們擺脫我們的1,而我們寫了一個2。 91 00:07:35,380 --> 00:07:39,560 因此,所有的好和良好的世界,即使我們已經覆蓋x現在。 92 00:07:39,560 --> 00:07:44,890 我們已經存儲在我們的TMP變量x的舊值。 93 00:07:44,890 --> 00:07:50,210 因此,我們可以完成交換的下一行。 94 00:07:50,210 --> 00:07:53,030 翻轉回我們的筆記本電腦。 95 00:07:53,030 --> 00:07:58,150 現在,剩下的就是我們的臨時整型變量的內容 96 00:07:58,150 --> 00:08:05,630 並將它們存儲到地址b被保持住在變量。 97 00:08:05,630 --> 00:08:10,230 因此,我們要有效地解引用b的變量 98 00:08:10,230 --> 00:08:14,340 這是在它的地址是b持有, 99 00:08:14,340 --> 00:08:19,190 我們將tmp是保存它的東西的價值。 100 00:08:19,190 --> 00:08:23,280 翻轉到iPad一次。 101 00:08:23,280 --> 00:08:31,290 我在這裡可以刪除此值,2, 102 00:08:31,290 --> 00:08:41,010 相反,我們將複製到它的。 103 00:08:41,010 --> 00:08:43,059 然後,下一行執行的,當然 - 104 00:08:43,059 --> 00:08:47,150 如果我們翻回的筆記本電腦 - 這是6點, 105 00:08:47,150 --> 00:08:52,500 這是我們希望我們的圖完全充滿。 106 00:08:52,500 --> 00:08:58,940 所以,翻轉到iPad,只是讓你可以看到已完成的圖, 107 00:08:58,940 --> 00:09:06,610 你可以看到,我們在10,14在b,1 tmp中,2 x中,在y和1。 108 00:09:06,610 --> 00:09:11,000 是否有任何問題嗎? 109 00:09:11,000 --> 00:09:14,640 這是否更有意義,已經走過嗎? 110 00:09:14,640 --> 00:09:24,850 就不是那麼有意義嗎?但願不會。好吧。 111 00:09:24,850 --> 00:09:28,230 >> 指針是一個非常棘手的問題。 112 00:09:28,230 --> 00:09:33,420 與我們合作的球員之一有一個很常見的說法: 113 00:09:33,420 --> 00:09:36,590 “要了解指針,你必須先了解指針。” 114 00:09:36,590 --> 00:09:40,530 我認為這是非常真實的。它確實需要一段時間才能使用它。 115 00:09:40,530 --> 00:09:45,360 抽籤的圖片,像這樣的抽籤的內存圖是非常有幫助的, 116 00:09:45,360 --> 00:09:49,480 後例如,在你走過的例子後,例如, 117 00:09:49,480 --> 00:09:54,450 它會開始做一些更有意義一些更有意義和更有意義一點。 118 00:09:54,450 --> 00:10:01,560 終於,有一天,你會擁有這一切完全掌握。 119 00:10:01,560 --> 00:10:13,800 任何問題之前,我們進入下一個問題嗎?好的。 120 00:10:13,800 --> 00:10:18,840 因此,翻轉的筆記本電腦。 121 00:10:18,840 --> 00:10:23,300 我們的下一個問題是問題33號文件I / O。 122 00:10:23,300 --> 00:10:26,350 這是一個有點放大。 123 00:10:26,350 --> 00:10:28,710 問題33 - 是嗎? 124 00:10:28,710 --> 00:10:32,110 >> [丹尼爾]我剛做了一個簡單的問題。此星或星號, 125 00:10:32,110 --> 00:10:35,590 這就是所謂的提領時,你使用一個星號之前。 126 00:10:35,590 --> 00:10:38,820 它是什麼時調用之前使用的符號嗎? 127 00:10:38,820 --> 00:10:43,140 >>“符號前是運營商的地址。 128 00:10:43,140 --> 00:10:45,880 因此,讓我們向上卷動。 129 00:10:45,880 --> 00:10:49,310 哎呀。我在變焦模式,所以我真的不能滾動。 130 00:10:49,310 --> 00:10:52,780 如果我們看一下這段代碼,在這裡真的很快, 131 00:10:52,780 --> 00:10:54,980 再次,同樣的事情發生。 132 00:10:54,980 --> 00:10:59,180 如果我們看一下這段代碼,在這裡,在這條線,我們撥打電話交換, 133 00:10:59,180 --> 00:11:10,460 “&”只是說“的地址在變量x的生活。” 134 00:11:10,460 --> 00:11:14,460 當你的編譯器編譯你的代碼, 135 00:11:14,460 --> 00:11:20,590 它實際物理標記在內存中所有的變量住的地方。 136 00:11:20,590 --> 00:11:24,910 所以編譯器就可以做一次,它的編譯一切, 137 00:11:24,910 --> 00:11:31,110 都知道,“哦,我把x地址10地址14,我要把Y”。 138 00:11:31,110 --> 00:11:34,640 然後,它可以為你填寫這些值。 139 00:11:34,640 --> 00:11:44,740 這樣你就可以 - 它可以通過本和通&Y以及。 140 00:11:44,740 --> 00:11:50,730 這些人得到的地址,但他們也,當你通過它們的交換功能, 141 00:11:50,730 --> 00:11:55,690 這此int *類型的信息,在這裡,告訴編譯器, 142 00:11:55,690 --> 00:12:01,350 “好了,我們將要解釋這個地址作為一個整型變量的地址。” 143 00:12:01,350 --> 00:12:05,900 一個int作為一個地址,它是從一個字符變量的地址不同 144 00:12:05,900 --> 00:12:09,930 因為一個int佔用了一個32位的機器上,佔用4個字節的空間, 145 00:12:09,930 --> 00:12:13,310 而一個字符只佔用1個字節的空間。 146 00:12:13,310 --> 00:12:17,310 因此,它是重要的是要知道什麼是 - 生活中,什麼類型的值 147 00:12:17,310 --> 00:12:20,340 住在傳入的地址,進行了 148 00:12:20,340 --> 00:12:22,020 或地址,你的工作。 149 00:12:22,020 --> 00:12:29,020 這樣一來,你知道多少個字節的信息的實際加載的RAM。 150 00:12:29,020 --> 00:12:31,780 然後,是的,這種反引用運算符,就像你問, 151 00:12:31,780 --> 00:12:37,200 在一個特定的地址去訪問信息。 152 00:12:37,200 --> 00:12:42,820 所以說,這是一個變量,在這裡,治療的內容作為地址, 153 00:12:42,820 --> 00:12:47,880 去到該地址,並拉出,到寄存器加載到處理器中,負載 154 00:12:47,880 --> 00:12:56,340 實際值或住在該地址的內容。 155 00:12:56,340 --> 00:12:59,620 還有什麼問題嗎?這些都是很好的問題。 156 00:12:59,620 --> 00:13:01,650 這是一個很多新的術語。 157 00:13:01,650 --> 00:13:09,800 這也是一種時髦,看到&和*在不同的地方。 158 00:13:09,800 --> 00:13:13,180 >> 好的。 159 00:13:13,180 --> 00:13:18,530 所以回到問題33,文件I / O。 160 00:13:18,530 --> 00:13:22,540 這是一個發生的幾件事情,我認為這些問題。 161 00:13:22,540 --> 00:13:25,400 一,這是一個相當新的課題。 162 00:13:25,400 --> 00:13:30,590 據介紹很快測驗前, 163 00:13:30,590 --> 00:13:33,400 然後,我認為這是種像這些字中的數學問題之一 164 00:13:33,400 --> 00:13:39,720 ,他們給你很多的信息,但實際上你不使用一噸的。 165 00:13:39,720 --> 00:13:44,060 這個問題的第一部分描述的是一個CSV文件是什麼。 166 00:13:44,060 --> 00:13:50,620 現在,一個CSV文件,根據描述,是一個以逗號分隔值文件。 167 00:13:50,620 --> 00:13:55,300 因此,這些在所有有趣的是,和你使用過他們的原因, 168 00:13:55,300 --> 00:14:00,800 ,因為,你們有多少人曾經使用Excel之類的東西嗎? 169 00:14:00,800 --> 00:14:03,240 圖你最有可能,或將使用在一些點在你的生活中。 170 00:14:03,240 --> 00:14:06,430 你會使用Excel之類的東西。 171 00:14:06,430 --> 00:14:10,940 為了得到數據的Excel電子表格或做任何形式的處理, 172 00:14:10,940 --> 00:14:17,240 如果你想編寫一個C程序或Python程序,Java程序, 173 00:14:17,240 --> 00:14:20,070 處理的數據儲存在那裡, 174 00:14:20,070 --> 00:14:23,170 把它弄出來的最常見的方式之一,是一個CSV文件中。 175 00:14:23,170 --> 00:14:26,850 ,你可以打開Excel中,當你去到“另存為”對話, 176 00:14:26,850 --> 00:14:32,840 你可以得到一個實際的CSV文件。 177 00:14:32,840 --> 00:14:35,890 >> 很方便的知道如何處理這些事情。 178 00:14:35,890 --> 00:14:42,010 它的工作方式是,它是類似的 - 我的意思是,它本質上是模仿電子表格, 179 00:14:42,010 --> 00:14:47,590 在那裡,我們在這裡看到,最左邊的一塊, 180 00:14:47,590 --> 00:14:49,910 我們所有的姓氏。 181 00:14:49,910 --> 00:14:54,670 因此,我們有馬蘭,那麼哈迪森,然後鮑登,MacWilliam,然後生。 182 00:14:54,670 --> 00:14:59,470 所有的姓氏。然後一個逗號分隔的姓氏第一個名字。 183 00:14:59,470 --> 00:15:02,970 大衛奈特,搶劫,張宇,和Zamyla。 184 00:15:02,970 --> 00:15:06,850 我總是混淆:羅比和湯姆。 185 00:15:06,850 --> 00:15:10,940 然後,終於,第三列是電子郵件地址。 186 00:15:10,940 --> 00:15:18,500 一旦你了解了,其餘的程序是非常簡單的實現。 187 00:15:18,500 --> 00:15:23,850 我們所做的,以模仿相同的結構在我們的C程序 188 00:15:23,850 --> 00:15:27,510 是我們使用了一個結構。 189 00:15:27,510 --> 00:15:30,520 我們將開始播放這一點以及。 190 00:15:30,520 --> 00:15:35,790 我們看到了他們的第一個問題集3,當我們正在處理的字典點點。 191 00:15:35,790 --> 00:15:40,290 但是,這名員工結構存儲一個姓氏,一個名字,和電子郵件。 192 00:15:40,290 --> 00:15:44,500 就像我們的CSV文件存儲。 193 00:15:44,500 --> 00:15:47,950 因此,這只是從一種格式轉換到另一個。 194 00:15:47,950 --> 00:15:54,630 我們必須轉換,在這種情況下,工作人員成一條線的結構的, 195 00:15:54,630 --> 00:15:59,060 一個以逗號分隔的行,就這樣。 196 00:15:59,060 --> 00:16:01,500 這是否有意義嗎?你們都採取了有獎問答, 197 00:16:01,500 --> 00:16:07,680 所以我想你已經至少有一些時間來思考這個問題。 198 00:16:07,680 --> 00:16:16,410 >> 在租用功能,這道題我們 - 我們將在這一點位變焦 - 199 00:16:16,410 --> 00:16:22,480 在人員結構,人員結構,名稱為s, 200 00:16:22,480 --> 00:16:30,900 並附加其內容到我們的staff.csv文件。 201 00:16:30,900 --> 00:16:34,230 事實證明,這是非常簡單的使用。 202 00:16:34,230 --> 00:16:37,430 我們將發揮著這些功能,今天多一點點。 203 00:16:37,430 --> 00:16:44,510 但是,在這種情況下,fprintf函數是真正的關鍵。 204 00:16:44,510 --> 00:16:51,960 因此,fprintf,我們可以打印,就像你們一直在使用printf的整個任期。 205 00:16:51,960 --> 00:16:55,050 您可以輸出到一個文件中的行。 206 00:16:55,050 --> 00:16:59,030 因此,而不是只是通常的printf調用,你給它一個格式字符串 207 00:16:59,030 --> 00:17:05,380 然後你替換所有的變量與下面的參數, 208 00:17:05,380 --> 00:17:11,290 與fprintf,你的第一個參數,而不是你要寫入的文件。 209 00:17:11,290 --> 00:17:21,170 如果我們要看看這個設備,例如,人fprintf, 210 00:17:21,170 --> 00:17:25,980 我們可以看到的printf和fprintf的區別。 211 00:17:25,980 --> 00:17:28,960 我將在這裡一點點放大。 212 00:17:28,960 --> 00:17:33,140 因此,用printf,我們給它一個格式字符串,然後在隨後的參數 213 00:17:33,140 --> 00:17:37,580 更換或替換成我們的格式化字符串中的所有的變量。 214 00:17:37,580 --> 00:17:47,310 而與fprintf,第一個參數是事實上,這稱為流文件*。 215 00:17:47,310 --> 00:17:51,800 >> 在這裡,我們的租賃, 216 00:17:51,800 --> 00:17:54,550 我們已經為我們打開了我們的文件*流。 217 00:17:54,550 --> 00:17:57,810 那這是什麼第一線;它打開了staff.csv的文件, 218 00:17:57,810 --> 00:18:01,690 它以附加的方式打開它,並為我們做了所有剩下的是 219 00:18:01,690 --> 00:18:08,640 編寫人員結構的文件。 220 00:18:08,640 --> 00:18:10,870 而且,讓我們來看看,我想使用iPad? 221 00:18:10,870 --> 00:18:17,900 我會使用iPad。我們有無效的 - 讓我們把這個放在桌子上,這樣我就可以寫一個好一點的 - 222 00:18:17,900 --> 00:18:33,680 無效租用,它需要一個參數,稱為s的人員結構。 223 00:18:33,680 --> 00:18:44,120 得到了我們的大括號,我們有我們的文件*文件, 224 00:18:44,120 --> 00:18:48,380 我們有我們的FOPEN線給我們, 225 00:18:48,380 --> 00:18:51,890 ,我就寫點,因為它已經在百科。 226 00:18:51,890 --> 00:19:00,530 然後在我們的下一行,我們要撥打電話為fprintf 227 00:19:00,530 --> 00:19:03,700 和我們將要通過的文件中,我們要打印的, 228 00:19:03,700 --> 00:19:10,290 然後我們的格式化字符串,其中 - 229 00:19:10,290 --> 00:19:14,300 我會告訴你們告訴我它是什麼樣子。 230 00:19:14,300 --> 00:19:20,500 你怎麼樣,Stella嗎?你知道的格式字符串的第一部分看起來像什麼? 231 00:19:20,500 --> 00:19:24,270 斯特拉]我不知道。 >>隨意問吉米。 232 00:19:24,270 --> 00:19:27,690 你知道嗎,吉米? 233 00:19:27,690 --> 00:19:31,000 [麥]這是最後一個嗎?我不知道。我不能完全肯定。 234 00:19:31,000 --> 00:19:39,020 “好了。怎麼樣,有沒有人得到這個正確的成績? 235 00:19:39,020 --> 00:19:41,770 所有權利。 236 00:19:41,770 --> 00:19:47,920 原來,這裡所有我們需要做的是,我們希望我們的人員結構各部分的 237 00:19:47,920 --> 00:19:53,290 作為一個字符串到我們的文件被打印出來。 238 00:19:53,290 --> 00:19:59,900 我們只是使用字符串替換字符,三個不同的時間,因為我們有個姓 239 00:19:59,900 --> 00:20:07,160 其次是逗號,然後一個名字後跟一個逗號, 240 00:20:07,160 --> 00:20:12,430 然後最後的電子郵件地址,其次是 - 這是不 241 00:20:12,430 --> 00:20:15,140 適合我的屏幕上 - 但它後面的一個換行符。 242 00:20:15,140 --> 00:20:20,060 所以我要去寫它只是出現了下滑。 243 00:20:20,060 --> 00:20:23,560 然後按照我們的格式化字符串, 244 00:20:23,560 --> 00:20:27,880 我們只需要換人,我們使用點表示法訪問 245 00:20:27,880 --> 00:20:31,370 我們所看到的問題集3。 246 00:20:31,370 --> 00:20:48,820 我們可以使用s.last,s.first,s.email 247 00:20:48,820 --> 00:20:58,990 在這三個值到我們的格式化字符串來代替。 248 00:20:58,990 --> 00:21:06,190 所以,這是怎麼去的?有意義嗎? 249 00:21:06,190 --> 00:21:09,700 是嗎?不是嗎?有可能嗎?好吧。 250 00:21:09,700 --> 00:21:14,180 >> 最後一點,我們做印刷後,我們已經打開的文件後,我們已經: 251 00:21:14,180 --> 00:21:17,370 每當我們打開一個文件,我們總是要記住關閉。 252 00:21:17,370 --> 00:21:19,430 否則,我們將最終的內存洩漏, 253 00:21:19,430 --> 00:21:22,500 使用文件描述符。 254 00:21:22,500 --> 00:21:25,950 因此,要關閉它,我們使用哪些功能?丹尼爾? 255 00:21:25,950 --> 00:21:30,120 [丹尼爾] FCLOSE? >> FCLOSE,準確。 256 00:21:30,120 --> 00:21:37,520 因此,這個問題的最後一部分是正確地關閉文件,使用fclose函數, 257 00:21:37,520 --> 00:21:40,370 它只是看起來像。 258 00:21:40,370 --> 00:21:43,880 太瘋狂了。 259 00:21:43,880 --> 00:21:46,990 酷。 260 00:21:46,990 --> 00:21:49,520 所以這就是問題的測驗33。 261 00:21:49,520 --> 00:21:52,480 I / O來了,我們肯定將有更多的文件。 262 00:21:52,480 --> 00:21:55,130 我們會做多一點點在今天的演講,或在今天的部分, 263 00:21:55,130 --> 00:22:01,710 因為這是怎麼回事形成這個即將到來的pset中的大部分。 264 00:22:01,710 --> 00:22:05,020 讓我們繼續在這一點上測驗。是嗎? 265 00:22:05,020 --> 00:22:10,880 >> [夏洛特]為什麼FCLOSE(文件),而不是FCLOSE(staff.csv)? 266 00:22:10,880 --> 00:22:19,100 “啊。因為事實證明 - 這樣的問題,這是一個偉大的, 267 00:22:19,100 --> 00:22:27,800 正因為如此,當我們寫FCLOSE,我們,寫FCLOSE(文件)明星變量 268 00:22:27,800 --> 00:22:33,680 而不是在文件名的,staff.csv?是正確的嗎?是啊。 269 00:22:33,680 --> 00:22:39,570 因此,讓我們一起來看看。如果我切換回我的筆記本電腦, 270 00:22:39,570 --> 00:22:45,040 讓我們來看看fclose函數。 271 00:22:45,040 --> 00:22:51,460 因此,fclose函數關閉一個流,它需要的指針,我們要關閉的流, 272 00:22:51,460 --> 00:22:57,010 而不是實際文件名,我們要關閉。 273 00:22:57,010 --> 00:23:01,620 這是因為在幕後,當你撥打電話的FOPEN, 274 00:23:01,620 --> 00:23:12,020 當你打開一個文件時,你實際上是在分配內存來存儲信息的文件。 275 00:23:12,020 --> 00:23:16,380 所以,你必須有信息的文件的文件指針, 276 00:23:16,380 --> 00:23:23,080 如它是開放的,它的大小,在那裡你目前在該文件中, 277 00:23:23,080 --> 00:23:29,100 這樣就可以在文件中讀取和寫入到特定的地方調用。 278 00:23:29,100 --> 00:23:38,060 您最終成交的指針,而不是關閉的文件名。 279 00:23:38,060 --> 00:23:48,990 >> 是嗎? [丹尼爾]因此,為了使用租用,你會說 - 它是如何獲得用戶輸入? 280 00:23:48,990 --> 00:23:53,830 fprintf像在這個意義上,它會等待用戶輸入的GetString 281 00:23:53,830 --> 00:23:57,180 要求用戶輸入 - 等待你輸入這三樣東西? 282 00:23:57,180 --> 00:24:00,480 或者你需要使用的東西,落實租? 283 00:24:00,480 --> 00:24:04,100 >>呀。因此,我們不 - 的問題是,如何得到用戶輸入 284 00:24:04,100 --> 00:24:09,220 為了實現租嗎?我們這裡是出租的呼叫者, 285 00:24:09,220 --> 00:24:17,690 在這種人員結構,所有的數據存儲結構已經通過。 286 00:24:17,690 --> 00:24:22,990 因此,fprintf是只是數據直接寫入到文件。 287 00:24:22,990 --> 00:24:25,690 有沒有等待用戶輸入。 288 00:24:25,690 --> 00:24:32,110 用戶是否已經輸入適當的把它在這名員工結構。 289 00:24:32,110 --> 00:24:36,510 的事情,當然,將打破,如果這些指針為空的, 290 00:24:36,510 --> 00:24:40,370 因此,我們在這裡向後滾動,我們期待在我們的結構。 291 00:24:40,370 --> 00:24:43,640 我們有字符串,字符串的第一個字符串的郵件。 292 00:24:43,640 --> 00:24:48,530 現在我們知道,所有的那些真正的,引擎蓋下,是char *變量。 293 00:24:48,530 --> 00:24:53,470 這可能會或可能不會被指向空。 294 00:24:53,470 --> 00:24:55,800 他們可能指向堆內存, 295 00:24:55,800 --> 00:24:59,650 也許內存堆棧。 296 00:24:59,650 --> 00:25:04,580 我們真的不知道,但如果其中任一指針是空的,或無效的, 297 00:25:04,580 --> 00:25:08,120 一定會崩潰,我們的租賃功能。 298 00:25:08,120 --> 00:25:11,050 這是什麼,這是一種超越的考試範圍。 299 00:25:11,050 --> 00:25:16,440 我們不擔心這一點。 300 00:25:16,440 --> 00:25:22,170 大。好吧。因此移動從測驗。 301 00:25:22,170 --> 00:25:25,760 >> 讓我們來關閉這個傢伙,我們要看看在pset中4。 302 00:25:25,760 --> 00:25:34,700 所以,如果你們看在pset規範,一旦你可以訪問它的,cs50.net/quizzes, 303 00:25:34,700 --> 00:25:42,730 我們要經過幾個部分問題,今天。 304 00:25:42,730 --> 00:25:52,240 我向下滾動 - 部分問題開始的第三頁上的pset的規範。 305 00:25:52,240 --> 00:25:57,800 第一部分要求你去觀看短重定向和管道。 306 00:25:57,800 --> 00:26:02,820 這是一個很酷的短,顯示出一些新的,很酷的命令行技巧,您可以使用。 307 00:26:02,820 --> 00:26:06,050 然後,我們有幾個問題要問你。 308 00:26:06,050 --> 00:26:10,860 這第一個問題,關於流,輸出寫入默認情況下, 309 00:26:10,860 --> 00:26:15,920 一種感動剛才只是一點點。 310 00:26:15,920 --> 00:26:22,380 我們剛才談到的這fp​​rintf需要在一個文件中*流作為它的參數。 311 00:26:22,380 --> 00:26:26,580 FCLOSE需要在一個文件中*流為好, 312 00:26:26,580 --> 00:26:32,660 和返回值的FOPEN給你一個文件*流以及。 313 00:26:32,660 --> 00:26:36,060 究其原因,我們還沒有看到那些之前我們已經處理了printf 314 00:26:36,060 --> 00:26:39,450 是因為輸出有一個默認的流。 315 00:26:39,450 --> 00:26:41,810 而它的默認流寫 316 00:26:41,810 --> 00:26:45,190 你會發現在短期內。 317 00:26:45,190 --> 00:26:50,080 所以,一定要看看它。 318 00:26:50,080 --> 00:26:53,010 >> 在今天的部分,我們要談一點關於GDB 319 00:26:53,010 --> 00:26:57,720 ,因為你是比較熟悉的,它更多的練習,你得到它, 320 00:26:57,720 --> 00:27:01,390 你能夠更好地將追捕在自己的代碼錯誤。 321 00:27:01,390 --> 00:27:05,540 這加快了極大的調試過程。 322 00:27:05,540 --> 00:27:09,230 因此,通過使用printf,每次你這樣做,你必須重新編譯你的代碼, 323 00:27:09,230 --> 00:27:13,000 你必須再次運行它,有時你必須左右移動printf調用, 324 00:27:13,000 --> 00:27:17,100 註釋掉的代碼,它只是需要一段時間。 325 00:27:17,100 --> 00:27:20,850 我們的目標是嘗試說服你,你基本上可以用GDB, 326 00:27:20,850 --> 00:27:26,810 在任何時候在你的代碼中的printf什麼,你永遠不會有重新編譯它。 327 00:27:26,810 --> 00:27:35,120 你從來沒有開始,並不斷猜測的printf下。 328 00:27:35,120 --> 00:27:40,910 要做的第一件事是複製這條線和部分代碼的網站。 329 00:27:40,910 --> 00:27:47,530 我說,“wget的http://cdn.cs50.net”這行代碼複製。 330 00:27:47,530 --> 00:27:49,510 我要複製它。 331 00:27:49,510 --> 00:27:55,950 我要到我的設備,縮放,所以你可以看到我在做什麼, 332 00:27:55,950 --> 00:28:01,890 將其粘貼在那裡,當我按下Enter鍵,這個wget命令從字面上是一個網絡獲得。 333 00:28:01,890 --> 00:28:06,210 這是怎麼回事拉下這個文件在互聯網上傳播, 334 00:28:06,210 --> 00:28:11,790 它的將它保存到當前目錄中。 335 00:28:11,790 --> 00:28:21,630 現在,如果我列出當前目錄中,你可以看到,我已經了這section5.zip的文件右鍵在那裡。 336 00:28:21,630 --> 00:28:25,260 那傢伙處理的方式是將其解壓縮, 337 00:28:25,260 --> 00:28:27,650 您可以在命令行中,就是這樣。 338 00:28:27,650 --> 00:28:31,880 Section5.zip。 339 00:28:31,880 --> 00:28:36,980 將它解壓縮,創建文件夾對我來說, 340 00:28:36,980 --> 00:28:40,410 膨脹中的所有內容,讓他們在那裡。 341 00:28:40,410 --> 00:28:47,410 所以,現在我可以進入我的第5節目錄使用cd命令。 342 00:28:47,410 --> 00:28:58,310 清除屏幕採用了明確。因此,清除屏幕。 343 00:28:58,310 --> 00:29:02,280 現在我有一個乾淨漂亮的終端處理。 344 00:29:02,280 --> 00:29:06,200 >> 現在,如果我列出我看到在這個目錄中的所有文件, 345 00:29:06,200 --> 00:29:12,270 你看到我已經得到四個文件:buggy1,buggy2,buggy3,並buggy4,。 346 00:29:12,270 --> 00:29:16,180 我也得到了相應的文件。 347 00:29:16,180 --> 00:29:20,400 我們不會看的。c文件。 348 00:29:20,400 --> 00:29:24,140 相反,我們要使用它們時,我們打開了GDB。 349 00:29:24,140 --> 00:29:28,220 我們已經把他們周圍,使我們有機會獲得實際的源代碼,當我們使用GDB, 350 00:29:28,220 --> 00:29:32,740 這部分的組成部分,但我們的目標是修改周圍的GDB 351 00:29:32,740 --> 00:29:40,370 看看我們如何能夠用它來找出什麼地方出了錯這四個錯誤的程序。 352 00:29:40,370 --> 00:29:43,380 所以我們僅僅是在房間裡真的很快, 353 00:29:43,380 --> 00:29:47,000 我要問別人的bug的程序運行一個, 354 00:29:47,000 --> 00:29:54,730 ,然後我們會去通過GDB作為一個群體,我們將看看我們能做些什麼來解決這些計劃, 355 00:29:54,730 --> 00:29:58,460 或者至少確定發生了什麼事情錯在他們每個人。 356 00:29:58,460 --> 00:30:04,760 讓我們從這裡開始與丹尼爾。你會運行buggy1?讓我們看看會發生什麼。 357 00:30:04,760 --> 00:30:09,470 丹尼爾說,有一個應用程序錯誤。 >>呀。沒錯。 358 00:30:09,470 --> 00:30:12,460 所以,如果我運行buggy1,我得到了賽格故障。 359 00:30:12,460 --> 00:30:16,210 在這一點上,我可以去開拓buggy1.c, 360 00:30:16,210 --> 00:30:19,450 試圖找出什麼地方出了錯, 361 00:30:19,450 --> 00:30:22,000 但該段故障錯誤最厭惡的事情之一 362 00:30:22,000 --> 00:30:27,610 的是,它不會告訴你哪一行的程序的東西實際是錯誤的,並打破。 363 00:30:27,610 --> 00:30:29,880 你有看的代碼 364 00:30:29,880 --> 00:30:33,990 找出猜測檢查或printf來看看會發生什麼錯誤。 365 00:30:33,990 --> 00:30:37,840 關於GDB的最酷的事情之一是,它是真的,真的很容易 366 00:30:37,840 --> 00:30:42,170 要弄清楚的線在你的程序崩潰。 367 00:30:42,170 --> 00:30:46,160 這是完全值得的,使用它,即使只是。 368 00:30:46,160 --> 00:30:56,190 啟動GDB,我輸入GDB,然後我給它的,我想運行的可執行文件的路徑。 369 00:30:56,190 --> 00:31:01,960 在這裡,我打字:GDB ./buggy1。 370 00:31:01,960 --> 00:31:06,600 按下回車鍵。給了我這一切版權信息, 371 00:31:06,600 --> 00:31:13,000 在這裡你會看到這條線,說:“從/ home /讀取符號 372 00:31:13,000 --> 00:31:17,680 jharvard/section5/buggy1。“ 373 00:31:17,680 --> 00:31:22,060 如果一切順利的話,你會看到它看起來像這樣打印出的信息。 374 00:31:22,060 --> 00:31:25,500 它會讀取符號,它會說:“我從你的可執行文件,讀取符號” 375 00:31:25,500 --> 00:31:29,900 ,然後將這個“做”的消息在這裡。 376 00:31:29,900 --> 00:31:35,410 如果你看到一些其他的變化,你看到它找不到符號 377 00:31:35,410 --> 00:31:41,460 或類似的東西,這是什麼意思,你只需要編譯你的可執行文件。 378 00:31:41,460 --> 00:31:49,980 當我們使用GDB編譯程序,我們必須使用特殊的-g標誌, 379 00:31:49,980 --> 00:31:54,540 ,這就是默認情況下,如果你編譯你的程序,通過鍵入make 380 00:31:54,540 --> 00:31:59,320 或車或恢復,任何人。 381 00:31:59,320 --> 00:32:07,800 但是,如果你正在編譯手動鐺,那麼你就必須去,其中包括,使用-g標誌。 382 00:32:07,800 --> 00:32:10,310 >> 在這一點上,現在,我們有我們的GDB提示, 383 00:32:10,310 --> 00:32:12,310 這是很簡單的運行程序。 384 00:32:12,310 --> 00:32:19,740 我們可以鍵入運行,我們就可以輸入r。 385 00:32:19,740 --> 00:32:22,820 大多數GDB命令都可以縮寫。 386 00:32:22,820 --> 00:32:25,940 通常只是一個或幾個字母,這是相當不錯的。 387 00:32:25,940 --> 00:32:30,980 因此,薩阿德,如果你輸入r,並按下Enter鍵,會發生什麼呢? 388 00:32:30,980 --> 00:32:39,390 薩阿德我SIGSEGV,分割故障,那麼這一切的官樣文章。 389 00:32:39,390 --> 00:32:43,650 >>呀。 390 00:32:43,650 --> 00:32:47,990 就像我們在屏幕上看到,現在,像薩阿德說, 391 00:32:47,990 --> 00:32:53,430 當我們鍵入run或r並按下回車鍵,我們仍然得到同樣的賽格故障。 392 00:32:53,430 --> 00:32:55,830 因此,使用GDB不解決我們的問題。 393 00:32:55,830 --> 00:32:59,120 但它為我們提供了一些官樣文章,而事實證明,這種官樣文章 394 00:32:59,120 --> 00:33:03,080 實際上告訴了我們它的發生。 395 00:33:03,080 --> 00:33:10,680 要解析這一點,第一位的功能是,在這一切是怎麼回事了。 396 00:33:10,680 --> 00:33:20,270 有__ strcmp_sse4_2,它告訴我們發生了什麼事在這個文件中的 397 00:33:20,270 --> 00:33:29,450 被稱為sysdeps/i386,這一切,再次,種混亂 - 而行254。 398 00:33:29,450 --> 00:33:31,670 這是一種很難解析。通常,當你看到這樣的東西, 399 00:33:31,670 --> 00:33:38,770 這意味著它在一個系統庫段斷層。 400 00:33:38,770 --> 00:33:43,220 因此,做的strcmp。你們已經看到的strcmp。 401 00:33:43,220 --> 00:33:52,730 不是太瘋狂了,但是這是否意味著STRCMP破損或STRCMP,有一個問題嗎? 402 00:33:52,730 --> 00:33:57,110 你怎麼想,亞歷山大? 403 00:33:57,110 --> 00:34:04,890 [亞歷山大]是 - 是254的行嗎? - 不是二進制的,但是這不是他們的天花板, 404 00:34:04,890 --> 00:34:10,590 然後有每個函數的另一種語言。 254在該函數中,或者 - ? 405 00:34:10,590 --> 00:34:21,460 >>這是第254行。它看起來像。文件,所以它的彙編代碼可能。 406 00:34:21,460 --> 00:34:25,949 >> 但是,我想更緊迫的事情,因為我們已經得到了賽格故障, 407 00:34:25,949 --> 00:34:29,960 它看起來像它來自strcmp函數, 408 00:34:29,960 --> 00:34:38,030 ,那麼,這是否意味著strcmp的壞了? 409 00:34:38,030 --> 00:34:42,290 它不應該有希望。因此,僅僅因為你有一個分割故障 410 00:34:42,290 --> 00:34:49,480 系統的功能之一,通常這意味著,你只是還沒有被稱為是正確的。 411 00:34:49,480 --> 00:34:52,440 的事情弄清楚什麼是怎麼回事 412 00:34:52,440 --> 00:34:55,500 當你看到這樣的瘋狂的東西,每當你看到一個段故障, 413 00:34:55,500 --> 00:34:59,800 特別是如果你有一個程序,使用多只主, 414 00:34:59,800 --> 00:35:03,570 使用的回溯。 415 00:35:03,570 --> 00:35:13,080 我寫BT,而不是全面的回溯字縮寫回溯。 416 00:35:13,080 --> 00:35:16,510 但是,夏洛特,當你鍵入BT並按下回車鍵,會發生什麼呢? 417 00:35:16,510 --> 00:35:23,200 夏洛特它讓我看到兩行,0行和第1行。 418 00:35:23,200 --> 00:35:26,150 >>呀。所以第0行和第1行。 419 00:35:26,150 --> 00:35:34,560 這些是實際的棧幀目前在播放的時候,你的程序崩潰。 420 00:35:34,560 --> 00:35:42,230 從最上面的幀,幀0開始,並持續到最底層的,這是第1幀。 421 00:35:42,230 --> 00:35:45,140 我們的最高框架是strcmp的框架,。 422 00:35:45,140 --> 00:35:50,080 你可以認為這是類似的問題,我們只是在做測驗的指針, 423 00:35:50,080 --> 00:35:54,890 我們交換堆棧幀上的主棧幀的頂部, 424 00:35:54,890 --> 00:35:59,700 和我們的互換使用,主要使用的變量的頂部上的變量。 425 00:35:59,700 --> 00:36:08,440 在這裡我們的崩潰發生在我們的strcmp函數,這被稱為我們的主要功能, 426 00:36:08,440 --> 00:36:14,370 回溯,不僅給我們的功能在裡面的東西沒有, 427 00:36:14,370 --> 00:36:16,440 但它也告訴我們,這裡的一切,被稱為。 428 00:36:16,440 --> 00:36:18,830 所以,如果我多一點點滾動的權利, 429 00:36:18,830 --> 00:36:26,110 我們可以看到,是的,我們在這個的strcmp,sse4.s文件的254行。 430 00:36:26,110 --> 00:36:32,540 但有人呼籲在buggy1.c,6號線。 431 00:36:32,540 --> 00:36:35,960 因此,這意味著我們可以做的 - 是我們可以去看看,看看發生了什麼事 432 00:36:35,960 --> 00:36:39,930 在6號線buggy1.c。 433 00:36:39,930 --> 00:36:43,780 同樣,也有幾種方法可以做到這一點。一個是退出GDB 434 00:36:43,780 --> 00:36:49,460 或者你的代碼在另一個窗口中打開和交叉引用。 435 00:36:49,460 --> 00:36:54,740 ,其本身而言,是非常方便的,因為現在,如果你在辦公時間 436 00:36:54,740 --> 00:36:57,220 和你已經有了一個段故障和TF想知道一切都被打破, 437 00:36:57,220 --> 00:36:59,710 你可以說,“哦,第6行,我不知道這是怎麼回事, 438 00:36:59,710 --> 00:37:03,670 但6號線是什麼導致我的計劃打破。“ 439 00:37:03,670 --> 00:37:10,430 做到這一點的另一種方法是,你可以使用此命令列表中GDB。 440 00:37:10,430 --> 00:37:13,650 您也可以將其縮寫為升。 441 00:37:13,650 --> 00:37:18,910 因此,如果我們打升,我們在這裡嗎? 442 00:37:18,910 --> 00:37:21,160 我們得到了一大堆怪異的東西。 443 00:37:21,160 --> 00:37:26,030 這是實際的彙編代碼 444 00:37:26,030 --> 00:37:29,860 是在strcmp_sse4_2。 445 00:37:29,860 --> 00:37:32,440 這看起來有點時髦的, 446 00:37:32,440 --> 00:37:36,520 的原因,我們正在這是,因為現在, 447 00:37:36,520 --> 00:37:40,160 GDB我們在第0幀。 448 00:37:40,160 --> 00:37:43,070 >> 所以,任何時候我們看變量,任何時候我們來看看源代碼, 449 00:37:43,070 --> 00:37:50,530 我們正在尋找源代碼的堆棧幀,涉及到我們目前所在 450 00:37:50,530 --> 00:37:53,200 因此,為了獲得什麼有意義的事情,我們必須 451 00:37:53,200 --> 00:37:57,070 轉移到更有意義的棧幀。 452 00:37:57,070 --> 00:38:00,180 在這種情況下,主要的堆棧幀將使一些更有意義, 453 00:38:00,180 --> 00:38:02,680 因為這實際上是我們寫的代碼。 454 00:38:02,680 --> 00:38:05,330 strcmp的代碼。 455 00:38:05,330 --> 00:38:08,650 的方式,可以在幀之間移動,在這種情況下,因為我們有兩個, 456 00:38:08,650 --> 00:38:10,430 我們有0和1, 457 00:38:10,430 --> 00:38:13,650 你這樣做的up和down命令。 458 00:38:13,650 --> 00:38:18,480 如果我把一幀, 459 00:38:18,480 --> 00:38:21,770 現在,我在主堆棧幀。 460 00:38:21,770 --> 00:38:24,330 我可以向下移動到的地方,我回去, 461 00:38:24,330 --> 00:38:32,830 再上去,走了,再上去。 462 00:38:32,830 --> 00:38:39,750 如果你這樣做你的程序在GDB,你得到一個崩潰時,你會得到回溯, 463 00:38:39,750 --> 00:38:42,380 你看到它的一些文件,你不知道發生了什麼事情。 464 00:38:42,380 --> 00:38:45,460 您嘗試列表,代碼並不很熟悉你, 465 00:38:45,460 --> 00:38:48,150 一起來看看在您的框架,並找出你在哪裡。 466 00:38:48,150 --> 00:38:51,010 你可能在錯誤的堆棧幀。 467 00:38:51,010 --> 00:38:58,760 或者至少,你是不是你真的可以調試堆棧幀中。 468 00:38:58,760 --> 00:39:03,110 現在,我們在適當的堆棧幀,我們在主, 469 00:39:03,110 --> 00:39:08,100 現在我們可以使用list命令可以計算出該行是什麼。 470 00:39:08,100 --> 00:39:13,590 你也可以看到它,它打印我們就在這裡。 471 00:39:13,590 --> 00:39:19,470 但是,我們可以打列出所有相同,列表,為我們提供了這個漂亮的打印輸出 472 00:39:19,470 --> 00:39:23,920 實際的源代碼,在這裡是怎麼回事。 473 00:39:23,920 --> 00:39:26,420 >> 特別是,我們可以看一下在第6行。 474 00:39:26,420 --> 00:39:29,330 我們可以看到,在這裡發生了什麼事情。 475 00:39:29,330 --> 00:39:31,250 它看起來像我們正在做的字符串比較 476 00:39:31,250 --> 00:39:41,050 字符串“CS50石頭”和argv [1]。 477 00:39:41,050 --> 00:39:45,700 他到這裡來是崩潰。 478 00:39:45,700 --> 00:39:54,120 所以,大小姐,你有什麼想法什麼可能會在這裡? 479 00:39:54,120 --> 00:39:59,400 [大小姐]我不知道為什麼它的崩潰。 >>你不知道為什麼它的崩潰? 480 00:39:59,400 --> 00:40:02,700 吉米,有什麼想法嗎? 481 00:40:02,700 --> 00:40:06,240 [麥]我不能完全肯定,但我們最後一次使用的字符串比較, 482 00:40:06,240 --> 00:40:10,260 或strcmp的,我們有三種不同的情況下。 483 00:40:10,260 --> 00:40:12,800 我們沒有一個==,我不認為,正確的,第一行。 484 00:40:12,800 --> 00:40:16,700 相反,它被分離成三個,一個是== 0, 485 00:40:16,700 --> 00:40:19,910 1 <0,我覺得,一個是> 0。 486 00:40:19,910 --> 00:40:22,590 因此,也許這樣的事情? >>呀。所以有這個問題 487 00:40:22,590 --> 00:40:27,200 我們做的比較正確? 488 00:40:27,200 --> 00:40:31,660 Stella嗎?有什麼想法? 489 00:40:31,660 --> 00:40:38,110 斯特拉]我不知道。 >>不知道。丹尼爾?思考?好吧。 490 00:40:38,110 --> 00:40:44,770 事實證明,所發生的事情在這裡是當我們運行程序時, 491 00:40:44,770 --> 00:40:48,370 我們得到了賽格故障,當你第一次運行的程序,丹尼爾, 492 00:40:48,370 --> 00:40:50,800 你給它任何命令行參數? 493 00:40:50,800 --> 00:40:58,420 [丹尼爾]第>>號在這種情況下,是什麼時,argv [1]? 494 00:40:58,420 --> 00:41:00,920 >>沒有任何價值。 “沒錯。 495 00:41:00,920 --> 00:41:06,120 那麼,有沒有適當的字符串值。 496 00:41:06,120 --> 00:41:10,780 但有一定的價值。被存儲在那裡的價值是什麼? 497 00:41:10,780 --> 00:41:15,130 >> A垃圾的價值呢? >>它要么是一個垃圾值,或者,在這種情況下, 498 00:41:15,130 --> 00:41:19,930 argv數組結束始終與null的終止。 499 00:41:19,930 --> 00:41:26,050 所以實際上存儲在那裡是空的。 500 00:41:26,050 --> 00:41:30,810 另一種方法解決這個問題,而不是想著它通過, 501 00:41:30,810 --> 00:41:33,420 是要設法把它打印出來。 502 00:41:33,420 --> 00:41:35,880 這是我說的,使用GDB是偉大的, 503 00:41:35,880 --> 00:41:40,640 因為你可以打印出所有的變量,所有你想要的值 504 00:41:40,640 --> 00:41:43,230 使用這種方便,花花公子p命令。 505 00:41:43,230 --> 00:41:48,520 所以,如果我鍵入p,然後我輸入一個變量的值或變量的名稱, 506 00:41:48,520 --> 00:41:55,320 說是argc,我看到argc是1。 507 00:41:55,320 --> 00:42:01,830 如果我想打印出來的argv [0],我可以這樣做,就這樣。 508 00:42:01,830 --> 00:42:04,840 就像我們所看到的,ARGV [0]是你的程序的名稱, 509 00:42:04,840 --> 00:42:06,910 總是的可執行文件的名稱。 510 00:42:06,910 --> 00:42:09,740 這裡你可以看到它有完整的路徑名。 511 00:42:09,740 --> 00:42:15,920 我還可以打印出的argv [1],看看會發生什麼。 512 00:42:15,920 --> 00:42:20,890 >> 在這裡,我們得到了這種神秘的值。 513 00:42:20,890 --> 00:42:23,890 我們拿到的這款0x0的。 514 00:42:23,890 --> 00:42:27,850 記得在學期開始時,我們談到十六進制數字嗎? 515 00:42:27,850 --> 00:42:34,680 或者說,在年底​​的pset 0的小問題如何表示十六進制50? 516 00:42:34,680 --> 00:42:39,410 我們編寫的十六進制數在CS,只是為了不混淆自己 517 00:42:39,410 --> 00:42:46,080 帶小數點的數字,是我們始終以0x前綴。 518 00:42:46,080 --> 00:42:51,420 因此,這0x前綴始終只是解釋為十六進制數, 519 00:42:51,420 --> 00:42:57,400 而不是字符串,而不是作為一個十進制數,而不是作為一個二進制數。 520 00:42:57,400 --> 00:43:02,820 由於5-0是一個有效的十六進制數。 521 00:43:02,820 --> 00:43:06,240 這是一個十進制數,50。 522 00:43:06,240 --> 00:43:10,050 因此,這是我們如何消除歧義。 523 00:43:10,050 --> 00:43:14,860 因此,0x0的裝置,十六進制的0,這也是十進制0,二進制0。 524 00:43:14,860 --> 00:43:17,030 只是,它的值為0。 525 00:43:17,030 --> 00:43:22,630 事實證明,這是空的,其實是在內存中。 526 00:43:22,630 --> 00:43:25,940 NULL就是0。 527 00:43:25,940 --> 00:43:37,010 在這裡,存儲元件的argv [1]為null。 528 00:43:37,010 --> 00:43:45,220 因此,我們試圖比較“CS50石頭”字符串為空字符串。 529 00:43:45,220 --> 00:43:48,130 因此,提領空,試圖訪問空的東西, 530 00:43:48,130 --> 00:43:55,050 通常會造成某種分割故障或其他不好的事情發生。 531 00:43:55,050 --> 00:43:59,350 而事實證明,STRCMP不請檢查 532 00:43:59,350 --> 00:44:04,340 您是否已經通過了一個值,該值是空的。 533 00:44:04,340 --> 00:44:06,370 相反,它只是前進,試圖做的事情, 534 00:44:06,370 --> 00:44:14,640 ,如果段故障,段故障,這是你的問題。你必須去解決它。 535 00:44:14,640 --> 00:44:19,730 真的很快,我們會如何解決這個問題?夏洛特? 536 00:44:19,730 --> 00:44:23,540 [夏洛特,您可以檢查使用的話。 537 00:44:23,540 --> 00:44:32,240 因此,如果argv [1]為null == 0,則返回1,什麼不知所云。 538 00:44:32,240 --> 00:44:34,590 >>呀。所以這是一個偉大的方式來做到這一點,我們可以查看, 539 00:44:34,590 --> 00:44:39,230 我們的價值傳遞到strcmp的,ARGV [1],它是空? 540 00:44:39,230 --> 00:44:45,830 如果是null,那麼我們可以這樣說好了,中止。 541 00:44:45,830 --> 00:44:49,450 >> 更常見的方式做,這是使用的argc的值。 542 00:44:49,450 --> 00:44:52,040 在這裡你可以看到在開始的主, 543 00:44:52,040 --> 00:44:58,040 我們省略了,第一,我們通常做測試時,我們使用命令行參數, 544 00:44:58,040 --> 00:45:05,240 這是我們ARGC值測試是否是我們所期望的。 545 00:45:05,240 --> 00:45:10,290 在這種情況下,我們預計至少需要兩個參數, 546 00:45:10,290 --> 00:45:13,660 的程序名加一個其它。 547 00:45:13,660 --> 00:45:17,140 因為我們使用的第二個參數在這裡。 548 00:45:17,140 --> 00:45:21,350 因此,有一些測試的結果之前,在我們的strcmp呼叫 549 00:45:21,350 --> 00:45:37,390 argv是,測試是否至少2個,也做了同樣的事情。 550 00:45:37,390 --> 00:45:40,620 我們可以看到,如果再次運行程序。 551 00:45:40,620 --> 00:45:45,610 您可以隨時重新啟動你的程序在GDB中,這是非常好的。 552 00:45:45,610 --> 00:45:49,310 您可以運行,而當你傳遞參數給你的程序, 553 00:45:49,310 --> 00:45:53,060 通過他們,當你調用運行,而不是當你啟動GDB。 554 00:45:53,060 --> 00:45:57,120 這樣,你可以每次都用不同的參數調用程序。 555 00:45:57,120 --> 00:46:08,080 所以運行,或者,我可以輸入r,,讓我們看看會發生什麼,如果我們輸入“你好”。 556 00:46:08,080 --> 00:46:11,140 它總是會問你,如果你想從一開始就再次啟動。 557 00:46:11,140 --> 00:46:17,490 通常情況下,你想從一開始就再次啟動它。 558 00:46:17,490 --> 00:46:25,010 而在這一點上,它會重新啟動一次,它打印出 559 00:46:25,010 --> 00:46:28,920 該程序,我們正在運行,buggy1的說法您好, 560 00:46:28,920 --> 00:46:32,720 並打印出這個標準了,它說,“你得到一個D,”悲傷的臉。 561 00:46:32,720 --> 00:46:37,610 但是,我們不段錯誤。它說,過程正常退出。 562 00:46:37,610 --> 00:46:39,900 所以,看起來還不錯。 563 00:46:39,900 --> 00:46:43,050 沒有更多的賽格故障,我們做了過去, 564 00:46:43,050 --> 00:46:48,190 所以看起來這的確是段故障錯誤,我們得到。 565 00:46:48,190 --> 00:46:51,540 不幸的是,它告訴我們,我們需要一個D. 566 00:46:51,540 --> 00:46:54,090 >> 我們可以回去看一下代碼,看看在那裡發生了什麼事情 567 00:46:54,090 --> 00:46:57,980 要弄清楚什麼是 - 為什麼它告訴我們,我們得到了D. 568 00:46:57,980 --> 00:47:03,690 讓我們來看看,這裡被這個printf說,你有D. 569 00:47:03,690 --> 00:47:08,540 如果我們輸入列表,你繼續輸入列表,它不斷迭代,通過你們的節目, 570 00:47:08,540 --> 00:47:10,940 因此,它會告訴你你的程序的前幾行。 571 00:47:10,940 --> 00:47:15,450 然後,它會告訴你在接下來的幾行字,下一個塊和下一塊。 572 00:47:15,450 --> 00:47:18,240 它會繼續嘗試下去。 573 00:47:18,240 --> 00:47:21,180 現在,我們會得到“線16號超出範圍。” 574 00:47:21,180 --> 00:47:23,940 因為它只有15行。 575 00:47:23,940 --> 00:47:30,310 如果你到了這一點,你想知道,我該怎麼辦?“你可以用help命令。 576 00:47:30,310 --> 00:47:34,340 使用幫助“,然後給它一個命令的名稱。 577 00:47:34,340 --> 00:47:36,460 你看到GDB為我們提供了這樣的東西。 578 00:47:36,460 --> 00:47:43,870 它說,“不帶參數,列出了10個多行後或以前上市。 579 00:47:43,870 --> 00:47:47,920 列表 - 列出了前十行 - “ 580 00:47:47,920 --> 00:47:52,960 所以,讓我們嘗試使用列表中減去。 581 00:47:52,960 --> 00:47:57,000 這列出的前10行,你可以玩弄名單一點點。 582 00:47:57,000 --> 00:48:02,330 你可以做的列表,列表 - ,你甚至可以給列出一個數字,如清單8, 583 00:48:02,330 --> 00:48:07,500 ,它就會列出了10條線,8號線附近。 584 00:48:07,500 --> 00:48:10,290 你可以看到在這裡發生了什麼事,是你已經有了一個簡單的if else。 585 00:48:10,290 --> 00:48:13,980 如果您鍵入在CS50岩石,它會打印出“你會得到一個A.” 586 00:48:13,980 --> 00:48:16,530 否則,它會打印出“你得到了D.” 587 00:48:16,530 --> 00:48:23,770 遊民鎮。好的。是嗎? 588 00:48:23,770 --> 00:48:26,730 >> [丹尼爾]因此,當我試圖這樣做CS50不帶引號的岩石, 589 00:48:26,730 --> 00:48:29,290 它說:“你得到了D.” 590 00:48:29,290 --> 00:48:32,560 我需要引號來得到它的工作,這是為什麼? 591 00:48:32,560 --> 00:48:38,490 >>呀。事實證明,當 - 這是另一個有趣的小花絮 - 592 00:48:38,490 --> 00:48:47,900 當您運行該程序,如果我們運行和輸入CS50岩石, 593 00:48:47,900 --> 00:48:50,800 就像丹尼爾說他這樣做,按Enter鍵, 594 00:48:50,800 --> 00:48:52,870 它說,我們得到了D. 595 00:48:52,870 --> 00:48:55,580 而問題是,這是為什麼? 596 00:48:55,580 --> 00:49:02,120 而事實證明,我們的終端和的GDB解析這些作為兩個單獨的參數。 597 00:49:02,120 --> 00:49:04,800 因為當有一個空間,這暗示 598 00:49:04,800 --> 00:49:08,730 第一個參數結束,即將開始的下一個參數。 599 00:49:08,730 --> 00:49:13,260 結合的方式一分為二,或遺憾的是,成為一個參數, 600 00:49:13,260 --> 00:49:18,510 使用引號。 601 00:49:18,510 --> 00:49:29,560 所以現在,如果我們把它放在引號並再次運行它,我們可以得到一個A。 602 00:49:29,560 --> 00:49:38,780 因此,只要回顧一下,沒有引號,的CS50和岩石被解析為兩個獨立的參數。 603 00:49:38,780 --> 00:49:45,320 隨著行情中,它作為一個參數完全解析。 604 00:49:45,320 --> 00:49:53,070 >> 我們可以看到這一個斷點。 605 00:49:53,070 --> 00:49:54,920 到目前為止,我們已經運行我們的程序,它的運行 606 00:49:54,920 --> 00:49:58,230 直到它賽格故障或點擊錯誤 607 00:49:58,230 --> 00:50:05,930 或直到它已退出所有已經完全正常。 608 00:50:05,930 --> 00:50:08,360 這並不一定是最有幫助的事情,因為有時 609 00:50:08,360 --> 00:50:11,840 你有一個錯誤在你的程序中,但它不是一個分割故障導致。 610 00:50:11,840 --> 00:50:16,950 它不會導致程序停止或類似的東西。 611 00:50:16,950 --> 00:50:20,730 GDB的方式來獲得你的程序在一個特定的點暫停 612 00:50:20,730 --> 00:50:23,260 是設置一個斷點。 613 00:50:23,260 --> 00:50:26,520 你可以做到這一點,一個函數名上設置一個斷點 614 00:50:26,520 --> 00:50:30,770 或者您可以設置一個特定的代碼行上設置一個斷點。 615 00:50:30,770 --> 00:50:34,450 我想設置斷點的函數名,因為 - 簡單易記, 616 00:50:34,450 --> 00:50:37,700 如果你真的一點點去改變你的源代碼, 617 00:50:37,700 --> 00:50:42,020 您的斷點將留在你的代碼在同一個地方。 618 00:50:42,020 --> 00:50:44,760 而如果你使用的是行號,行號更改 619 00:50:44,760 --> 00:50:51,740 因為你添加或刪除了一些代碼,然後斷點都完全搞砸了。 620 00:50:51,740 --> 00:50:58,590 其中最常見的事情,我做的是設置一個斷點上的主要功能。 621 00:50:58,590 --> 00:51:05,300 我經常會啟動GDB,我會鍵入b主,按下回車鍵,將設置一個斷點 622 00:51:05,300 --> 00:51:10,630 的主要功能,只是說,“暫停程序盡快開始運行,” 623 00:51:10,630 --> 00:51:17,960 這樣一來,當我運行我的程序,比方說,CS50岩石的兩個參數 624 00:51:17,960 --> 00:51:24,830 並按下回車鍵,得到的主要功能,它就停在第一線, 625 00:51:24,830 --> 00:51:30,620 前strcmp函數求值。 626 00:51:30,620 --> 00:51:34,940 >> 由於我停頓了一下,現在我可以開始擺弄周圍,看是怎麼回事 627 00:51:34,940 --> 00:51:40,250 所有的不同的變量傳遞到我的程序。 628 00:51:40,250 --> 00:51:43,670 在這裡,我可以打印出argc和看看會發生什麼。 629 00:51:43,670 --> 00:51:50,030 請參閱argc是3,因為它有3個不同的值。 630 00:51:50,030 --> 00:51:54,060 它得名的程序,它得到的第一個參數,第二個參數。 631 00:51:54,060 --> 00:52:09,330 我們可以打印在ARGV [0],ARGV [1]和argv [2]。 632 00:52:09,330 --> 00:52:12,030 所以,現在你也可以看到為什麼這STRCMP調用是要失敗的, 633 00:52:12,030 --> 00:52:21,650 因為你看到,它並分裂成兩個獨立的參數的CS50和岩石。 634 00:52:21,650 --> 00:52:27,250 在這一點上,一旦你已經打了斷點,你可以通過你的程序繼續加強 635 00:52:27,250 --> 00:52:32,920 一行行,而不是重新啟動程序。 636 00:52:32,920 --> 00:52:35,520 所以,如果你不想再次啟動程序,只是繼續從這裡開始, 637 00:52:35,520 --> 00:52:41,970 您可以使用continue命令,並繼續將運行該程序的結束。 638 00:52:41,970 --> 00:52:45,010 就像它在這裡做的。 639 00:52:45,010 --> 00:52:54,880 不過,如果我重新啟動程序,CS50岩石,它打我的斷點再次, 640 00:52:54,880 --> 00:52:59,670 而這一次,如果我不想去,一路過關斬將,其餘的程序, 641 00:52:59,670 --> 00:53:08,040 我可以用下一個命令,這也是我縮寫與n。 642 00:53:08,040 --> 00:53:12,960 而這將逐步的程序行線。 643 00:53:12,960 --> 00:53:17,530 所以,你可以看的東西執行,作為變量的變化,事情得到更新。 644 00:53:17,530 --> 00:53:21,550 這是相當不錯的。 645 00:53:21,550 --> 00:53:26,570 其他很酷的事情,而不是一遍又一遍,再重複同樣的命令, 646 00:53:26,570 --> 00:53:30,670 所以在這裡,如果你只需要敲擊回車 - 你看,我沒有在任何輸入 - 647 00:53:30,670 --> 00:53:33,780 如果我只是打回車鍵,將重複前面的命令, 648 00:53:33,780 --> 00:53:36,900 或以前的GDB命令,我剛剛放進去。 649 00:53:36,900 --> 00:53:56,000 我可以保持按下回車鍵,它會通過我的代碼行的行不斷加強。 650 00:53:56,000 --> 00:53:59,310 我會鼓勵你們去看看其他bug的程序。 651 00:53:59,310 --> 00:54:01,330 我們沒有時間去通過所有這些今天在第。 652 00:54:01,330 --> 00:54:05,890 源代碼是存在的,所以你可以看到這是怎麼回事 653 00:54:05,890 --> 00:54:07,730 如果你真的卡幕後, 654 00:54:07,730 --> 00:54:11,940 但最起碼,練習啟動GDB, 655 00:54:11,940 --> 00:54:13,940 運行該程序,直到它打破了你, 656 00:54:13,940 --> 00:54:18,260 回溯,搞清楚什麼樣的功能崩潰, 657 00:54:18,260 --> 00:54:24,450 哪一行,打印出一些變量的值, 658 00:54:24,450 --> 00:54:30,140 只是讓你的感覺,因為這將真正幫助你前進。 659 00:54:30,140 --> 00:54:36,340 在這一點上,我們要退出的GDB,你退出或者只是q。 660 00:54:36,340 --> 00:54:40,460 如果你的程序的運行仍然在中間,並​​沒有退出, 661 00:54:40,460 --> 00:54:43,510 它總是會問你:“你確定你真的要退出嗎?” 662 00:54:43,510 --> 00:54:48,770 您可以打是肯定的。 663 00:54:48,770 --> 00:54:55,250 >> 現在,我們要看看我們的下一個問題,這是貓的程序。 664 00:54:55,250 --> 00:54:59,880 如果你看重定向和管道短,你會看到湯米使用這個程序 665 00:54:59,880 --> 00:55:07,540 基本上所有輸出的文件打印到屏幕上。 666 00:55:07,540 --> 00:55:12,660 所以,如果我遇到貓,這實際上是一個內置的程序到設備, 667 00:55:12,660 --> 00:55:16,860 ,如果你有Mac電腦,你可以做到這一點在您的Mac上,如果你打開終端。 668 00:55:16,860 --> 00:55:25,630 而我們 - 貓,比方說,cp.c,並按下回車鍵。 669 00:55:25,630 --> 00:55:29,640 這是什麼做的,如果我們向上滾動一點點,看到我們跑線, 670 00:55:29,640 --> 00:55:40,440 我們跑了cat命令,它實際上只是打印出來的內容cp.c我們的屏幕上。 671 00:55:40,440 --> 00:55:44,140 我們可以再次運行它,你可以把多個文件一起。 672 00:55:44,140 --> 00:55:49,880 所以,你可以做貓cp.c,那麼我們也可以連接起來的cat.c的文件, 673 00:55:49,880 --> 00:55:53,250 這是我們寫的程序, 674 00:55:53,250 --> 00:55:58,140 它會同時打印文件備份到我們的屏幕上。 675 00:55:58,140 --> 00:56:05,490 因此,如果我們向上滾動一點點,我們看到,當我們跑了這貓cp.c,cat.c, 676 00:56:05,490 --> 00:56:17,110 首先它打印出來cp文件,然後在下面的,它打印出cat.c的文件就在這裡。 677 00:56:17,110 --> 00:56:19,650 我們將用此來只是讓我們的腳濕。 678 00:56:19,650 --> 00:56:25,930 玩簡單的打印到終端,請參閱如何工作的。 679 00:56:25,930 --> 00:56:39,170 如果你們打開用gedit cat.c,按Enter鍵, 680 00:56:39,170 --> 00:56:43,760 你可以看到我們寫的程序。 681 00:56:43,760 --> 00:56:48,980 我們這個漂亮的鍋爐板,所以我們不必花時間打字了這一切。 682 00:56:48,980 --> 00:56:52,310 我們還檢查傳入的參數 683 00:56:52,310 --> 00:56:56,910 我們打印出不錯的用法消息。 684 00:56:56,910 --> 00:57:00,950 >> 這是諸如此類的事情,再次,就像我們一直在談論, 685 00:57:00,950 --> 00:57:04,490 這幾乎就像肌肉記憶。 686 00:57:04,490 --> 00:57:07,190 只記得繼續做同樣的東西 687 00:57:07,190 --> 00:57:11,310 總是打印出某種有用的消息 688 00:57:11,310 --> 00:57:17,670 讓人們知道如何運行你的程序。 689 00:57:17,670 --> 00:57:21,630 隨著貓,它是非常簡單的,我們只是要通過不同的參數 690 00:57:21,630 --> 00:57:24,300 被傳遞到我們的計劃,我們要打印 691 00:57:24,300 --> 00:57:29,950 其內容在一個時間的一個屏幕。 692 00:57:29,950 --> 00:57:35,670 為了打印文件輸出到屏幕上,我們要做的東西非常相似 693 00:57:35,670 --> 00:57:38,120 我們所做的,在測驗結束時。 694 00:57:38,120 --> 00:57:45,350 在測驗結束,聘用程序,我們要打開一個文件, 695 00:57:45,350 --> 00:57:48,490 然後我們有打印到它。 696 00:57:48,490 --> 00:57:54,660 在這種情況下,我們要打開一個文件,我們要讀取它,而不是。 697 00:57:54,660 --> 00:58:00,630 然後我們要打印的,而不是到一個文件中,我們將要打印到屏幕上。 698 00:58:00,630 --> 00:58:05,830 所以打印到屏幕上,你用printf之前全部完成。 699 00:58:05,830 --> 00:58:08,290 所以這是不是太瘋狂了。 700 00:58:08,290 --> 00:58:12,190 但是,讀取一個文件是一種奇怪的。 701 00:58:12,190 --> 00:58:17,300 我們將通過那麼一點點的時間。 702 00:58:17,300 --> 00:58:20,560 如果你們回去,最後一個問題,您的測驗,問題33, 703 00:58:20,560 --> 00:58:27,280 我們要在這裡做的第一行,打開文件,非常類似於我們在那裡做了什麼。 704 00:58:27,280 --> 00:58:36,370 因此,斯特拉,是什麼樣子,當我們打開一個文件時,該行嗎? 705 00:58:36,370 --> 00:58:47,510 [特拉]資本FILE *文件 - “”好了。 >> - 是平等的FOPEN。 “是啊。 706 00:58:47,510 --> 00:58:55,980 在這種情況下是什麼?這是在註釋中。 707 00:58:55,980 --> 00:59:06,930 >>這是在評論嗎?的argv [i]的和r? 708 00:59:06,930 --> 00:59:11,300 “沒錯。正確的。斯特拉是完全正確的。 709 00:59:11,300 --> 00:59:13,720 這是行看起來像什麼。 710 00:59:13,720 --> 00:59:19,670 我們將得到一個文件流變量,它存儲在一個FILE *,所以全部大寫字母, 711 00:59:19,670 --> 00:59:25,720 將文件FILE *,這個變量的名稱。 712 00:59:25,720 --> 00:59:32,250 無論我們喜歡,我們可以把它稱為。我們可以把它first_file,或file_i的,無論我們想要的。 713 00:59:32,250 --> 00:59:37,590 在命令行上這個節目,然後通過的文件名。 714 00:59:37,590 --> 00:59:44,450 因此,它存儲在argv [我],然後我們要打開這個文件在讀取模式。 715 00:59:44,450 --> 00:59:48,100 現在,我們已經打開了文件,有什麼事情,我們總是要記住做 716 00:59:48,100 --> 00:59:52,230 每當我們打開一個文件?關閉它。 717 00:59:52,230 --> 00:59:57,220 所以,大小姐,我們該如何關閉一個文件? 718 00:59:57,220 --> 01:00:01,020 [大小姐] FCLOSE(文件)>> FCLOSE(文件)。沒錯。 719 01:00:01,020 --> 01:00:05,340 大。好吧。如果我們看一下在這裡做評論, 720 01:00:05,340 --> 01:00:11,940 它說,“開放的argv [i]和它的內容打印到stdout。” 721 01:00:11,940 --> 01:00:15,460 >> 標準輸出是一個奇怪的名字。 stdout是我們的一種說法 722 01:00:15,460 --> 01:00:22,880 我們要打印到終端,我們希望將其打印到標準輸出流。 723 01:00:22,880 --> 01:00:26,450 事實上,我們可以擺脫這個評論就在這裡。 724 01:00:26,450 --> 01:00:36,480 我要複製並粘貼它,因為這是我們所做的。 725 01:00:36,480 --> 01:00:41,290 在這一點上,現在我們要讀取的文件的點點滴滴。 726 01:00:41,290 --> 01:00:46,300 我們已經討論了一對夫婦的讀取文件的方式。 727 01:00:46,300 --> 01:00:51,830 哪些是你最喜歡這麼遠嗎? 728 01:00:51,830 --> 01:00:57,960 哪種方式,你見過,你還記得,讀文件? 729 01:00:57,960 --> 01:01:04,870 [丹尼爾·弗里德? >>弗里德?因此,弗里德是其中之一。吉米,你知不知道什麼人嗎? 730 01:01:04,870 --> 01:01:12,150 [麥]第>>好。不。夏洛特?亞歷山大?還有其他人嗎?好吧。 731 01:01:12,150 --> 01:01:20,740 因此,其他的是fgetc,是我們將使用一個不少。 732 01:01:20,740 --> 01:01:26,410 還有fscanf,你們看到這裡的模式嗎? 733 01:01:26,410 --> 01:01:29,170 他們都以f。任何一個文件。 734 01:01:29,170 --> 01:01:35,260 有FREAD,fgetc函數,fscanf。這些所有的讀出功能。 735 01:01:35,260 --> 01:01:49,120 為寫我們FWRITE,我們的fputc,而不是fgetc函數。 736 01:01:49,120 --> 01:01:58,250 我們也fprintf,像我們看到的測驗。 737 01:01:58,250 --> 01:02:01,680 由於這是一個問題,涉及從文件中讀取, 738 01:02:01,680 --> 01:02:04,940 我們將使用這三個功能中的一個。 739 01:02:04,940 --> 01:02:10,890 我們不打算使用這些功能。 740 01:02:10,890 --> 01:02:14,880 這些功能都在標準I / O庫。 741 01:02:14,880 --> 01:02:17,510 所以,如果你看一下這個程序的頂部, 742 01:02:17,510 --> 01:02:24,110 你可以看到,我們已經包含標準I / O庫的頭文件。 743 01:02:24,110 --> 01:02:27,120 如果我們想弄清楚,我們要使用哪一個, 744 01:02:27,120 --> 01:02:29,690 我們可以隨時打開的手冊頁。 745 01:02:29,690 --> 01:02:34,350 因此,我們可以輸入man的stdio 746 01:02:34,350 --> 01:02:43,180 並閱讀所有的的stdio的輸入和輸出功能C. 747 01:02:43,180 --> 01:02:49,870 我們已經可以看到啊,看看。提fgetc,它的一提的fputc。 748 01:02:49,870 --> 01:02:57,220 所以,你可以向下一點點,看,說,fgetc函數 749 01:02:57,220 --> 01:03:00,060 看它的man page。 750 01:03:00,060 --> 01:03:03,430 你可以看到,它伴隨著一大堆的其他功能: 751 01:03:03,430 --> 01:03:12,640 fgetc函數,FGETS,getc函數,getchar函數,獲取,ungetc的函數,其輸入的字符和字符串。 752 01:03:12,640 --> 01:03:19,180 因此,這是我們如何從標準輸入文件讀取的字符和字符串, 753 01:03:19,180 --> 01:03:21,990 這本質上是從用戶。 754 01:03:21,990 --> 01:03:24,780 這是如何做到這一點,在實際C. 755 01:03:24,780 --> 01:03:30,850 因此,這是不使用的GetString和getchar功能 756 01:03:30,850 --> 01:03:36,840 我們使用的從CS50庫。 757 01:03:36,840 --> 01:03:39,710 我們要做的這個問題的幾種方法 758 01:03:39,710 --> 01:03:43,430 所以,你可以看到兩種不同的方法做這件事。 759 01:03:43,430 --> 01:03:48,490 fread函數,丹尼爾提到的和fgetc函數都不錯的辦法做到這一點。 760 01:03:48,490 --> 01:03:53,790 我認為fgetc函數是一個容易一些,因為它只有你可以看到, 761 01:03:53,790 --> 01:03:59,660 一個參數,FILE *,我們試圖讀取的字符, 762 01:03:59,660 --> 01:04:02,740 它的返回值是一個int。 763 01:04:02,740 --> 01:04:05,610 這是一個有點混亂,對嗎? 764 01:04:05,610 --> 01:04:11,450 >> 因為我們得到一個字符,那麼為什麼沒有這個返回一個字符? 765 01:04:11,450 --> 01:04:18,700 為什麼這可能不會返回一個字符,你們有什麼想法? 766 01:04:18,700 --> 01:04:25,510 [的大小姐答案,不知所云] >>呀。所以大小姐是完全正確的。 767 01:04:25,510 --> 01:04:31,570 如果它是ASCII,那麼這個整數被映射到一個實際的字符。 768 01:04:31,570 --> 01:04:33,520 可能是一個ASCII字符,這是正確的。 769 01:04:33,520 --> 01:04:36,220 這到底發生了什麼。 770 01:04:36,220 --> 01:04:39,190 我們使用的是一個int,只是因為它有更多的比特。 771 01:04:39,190 --> 01:04:44,750 這是更大的不是一個字符的字符只有8位,32位機,1個字節。 772 01:04:44,750 --> 01:04:48,520 和一個int的所有4個字節的空間價值。 773 01:04:48,520 --> 01:04:50,940 事實證明,fgetc函數的工作方式, 774 01:04:50,940 --> 01:04:53,940 如果我們向下滾動本手冊頁一點點,在我們的簡介 775 01:04:53,940 --> 01:05:05,000 向下滾動的方式。原來,他們用這種特殊的值EOF。 776 01:05:05,000 --> 01:05:09,640 這是一個特殊的常量,fgetc函數的返回值 777 01:05:09,640 --> 01:05:14,570 只要你打的文件,或者如果你得到一個錯誤。 778 01:05:14,570 --> 01:05:18,170 事實證明,做這些比較EOF正確的, 779 01:05:18,170 --> 01:05:24,060 你想有額外的大量的信息,你必須在一個int 780 01:05:24,060 --> 01:05:28,420 而不是使用一個char變量。 781 01:05:28,420 --> 01:05:32,130 即使fgetc函數有效地從一個文件中的字符, 782 01:05:32,130 --> 01:05:38,450 你要記住,它返回的東西是你的類型為int。 783 01:05:38,450 --> 01:05:41,360 這就是說,它很容易使用。 784 01:05:41,360 --> 01:05:44,960 它給我們一個字符,所以我們要做的是保持要求的文件, 785 01:05:44,960 --> 01:05:48,440 “給我的下一個字符的下一個字符給我,給我的下一個字符。” 786 01:05:48,440 --> 01:05:51,400 直到我們得到的文件結束。 787 01:05:51,400 --> 01:05:54,730 這會拉一個字符的時間從我們的文件, 788 01:05:54,730 --> 01:05:56,250 然後我們可以做任何我們喜歡它。 789 01:05:56,250 --> 01:06:00,160 我們可以將其存儲,我們可以將其添加為一個字符串,我們可以把它打印出來。 790 01:06:00,160 --> 01:06:04,630 任何。 791 01:06:04,630 --> 01:06:09,600 >> 放大退了出去,並要回到我們的cat.c的程序, 792 01:06:09,600 --> 01:06:16,170 如果我們要使用fgetc函數, 793 01:06:16,170 --> 01:06:21,710 我們會如何對待這下一行代碼? 794 01:06:21,710 --> 01:06:26,020 我們將使用 - 弗里德會做一些事情略有不同。 795 01:06:26,020 --> 01:06:32,600 而這個時候,我們只是要使用fgetc函數得到一​​個字符的時間。 796 01:06:32,600 --> 01:06:40,910 為了處理一個完整的文件,我們可能會做什麼? 797 01:06:40,910 --> 01:06:44,030 在一個文件中有多少個字符? 798 01:06:44,030 --> 01:06:47,390 有很多。所以,你可能希望得到一個 799 01:06:47,390 --> 01:06:49,860 然後得到另一個獲得,並得到另一個。 800 01:06:49,860 --> 01:06:53,330 你認為我們可能要在這裡使用的是什麼樣的算法? 801 01:06:53,330 --> 01:06:55,470 什麼類型的 - ? [亞歷山大]一個for循環? “沒錯。 802 01:06:55,470 --> 01:06:57,500 某些類型的循環。 803 01:06:57,500 --> 01:07:03,380 一個for循環實際上是很大的,在這種情況下。 804 01:07:03,380 --> 01:07:08,620 像你說的,這聽起來像你想有一個循環,在整個文件, 805 01:07:08,620 --> 01:07:11,820 獲得一個字符的時間。 806 01:07:11,820 --> 01:07:13,850 任何建議,可能看起來像什麼? 807 01:07:13,850 --> 01:07:22,090 [亞歷山大,不知所云] 808 01:07:22,090 --> 01:07:30,050 好了,只是英語告訴我你想要做的是什麼? [亞歷山大,不知所云] 809 01:07:30,050 --> 01:07:36,270 因此,在這種情況下,這聽起來像我們只是試圖在整個文件中環。 810 01:07:36,270 --> 01:07:45,330 [亞歷山大]所以,我為int的大小嗎? >>的大小 - ? 811 01:07:45,330 --> 01:07:49,290 我猜大小的文件,對不對?的大小 - 我們就會把它寫這樣的。 812 01:07:49,290 --> 01:07:57,470 尺寸文件的時間,我+ +。 813 01:07:57,470 --> 01:08:04,610 因此,原來的方式,你使用fgetc,這是新的, 814 01:08:04,610 --> 01:08:10,460 是,有沒有簡單的方法得到的文件大小 815 01:08:10,460 --> 01:08:16,979 這個“大小”式的結構,你已經看到過。 816 01:08:16,979 --> 01:08:20,910 當我們在使用,fgetc功能,我們要介紹的某種 817 01:08:20,910 --> 01:08:29,069 新的,時髦的語法for循環,而不是只使用基本的計數器 818 01:08:29,069 --> 01:08:33,920 去逐個字符,我們要拉一個字符的時候, 819 01:08:33,920 --> 01:08:37,120 一次一個字符的方式,以及我們所知道的,我們是在結束 820 01:08:37,120 --> 01:08:41,290 是不是當我們已經數了一定數目的字符, 821 01:08:41,290 --> 01:08:49,939 但是,當我們拉出來的字符是特殊的文件結束符。 822 01:08:49,939 --> 01:08:58,689 因此,我們可以做到這一點 - 我把這種路,我們要初始化 823 01:08:58,689 --> 01:09:08,050 我們的第一次調用出來的文件的第一個字符。 824 01:09:08,050 --> 01:09:14,979 所以這部分就在這裡,這是怎麼回事字符的文件 825 01:09:14,979 --> 01:09:20,840 並把它存儲到變量ch。 826 01:09:20,840 --> 01:09:25,420 我們將繼續這樣做,直到我們得到的文件, 827 01:09:25,420 --> 01:09:41,170 我們做測試不等於EOF字符,特殊字符。 828 01:09:41,170 --> 01:09:48,750 然後,而不是做CH + +,這將只是增加價值, 829 01:09:48,750 --> 01:09:52,710 因此,如果我們看到一個出來的文件,一個大寫的A,說, 830 01:09:52,710 --> 01:09:56,810 CH + +會給我們B,然後我們會得到C,然後按下d。 831 01:09:56,810 --> 01:09:59,310 這顯然不是我們想要的。我們想在這裡 832 01:09:59,310 --> 01:10:05,830 在這最後一點是,我們​​希望得到的下一個字符的文件。 833 01:10:05,830 --> 01:10:09,500 >> 所以,我們怎麼可能得到的下一個字符的文件呢? 834 01:10:09,500 --> 01:10:13,470 我們怎樣才能從文件的第一個字符? 835 01:10:13,470 --> 01:10:17,200 [學生]:fgetfile? >> fgetc函數,對不起,你是完全正確的。 836 01:10:17,200 --> 01:10:20,470 我拼錯了就在那裡。所以,是的。 837 01:10:20,470 --> 01:10:26,240 在這裡,而不是做CH + +, 838 01:10:26,240 --> 01:10:29,560 我們只是調用fgetc函數(文件) 839 01:10:29,560 --> 01:10:39,180 和存儲相同ch變量的結果在我們的。 840 01:10:39,180 --> 01:10:43,730 [學生提問,不知所云] 841 01:10:43,730 --> 01:10:52,390 >>這是這些FILE *人是特殊的。 842 01:10:52,390 --> 01:10:59,070 他們的工作方式是 - 當你第一次打開 - 當你第一次作出這樣的fopen的調用, 843 01:10:59,070 --> 01:11:04,260 有效地作為開頭的文件指針FILE *。 844 01:11:04,260 --> 01:11:12,830 然後每次調用fgetc,移動一個字符通過該文件。 845 01:11:12,830 --> 01:11:23,280 所以每當你打電話,你的文件增加一個字符指針。 846 01:11:23,280 --> 01:11:26,210 ,並時,fgetc再次,​​你要搬到另一個字符 847 01:11:26,210 --> 01:11:28,910 另一個字符和其他字符和其他字符。 848 01:11:28,910 --> 01:11:32,030 [學生提問,難以理解] >> that's的 - 是啊。 849 01:11:32,030 --> 01:11:34,810 這是一種這種神奇的引擎蓋下。 850 01:11:34,810 --> 01:11:37,930 你不斷遞增通過。 851 01:11:37,930 --> 01:11:46,510 在這一點上,你能夠真正與字符。 852 01:11:46,510 --> 01:11:52,150 因此,我們怎麼可能打印出來的畫面,現在呢? 853 01:11:52,150 --> 01:11:58,340 我們可以使用相同的printf的事情,我們之前使用。 854 01:11:58,340 --> 01:12:00,330 我們一直在使用一學期。 855 01:12:00,330 --> 01:12:05,450 我們可以調用printf, 856 01:12:05,450 --> 01:12:21,300 我們可以通過在性格就是這樣。 857 01:12:21,300 --> 01:12:27,430 做到這一點的另一種方式是使用printf不必做此格式字符串,而不是 858 01:12:27,430 --> 01:12:29,490 我們也可以使用其他的功能之一。 859 01:12:29,490 --> 01:12:40,090 我們可以使用的fputc,可打印字符在屏幕上, 860 01:12:40,090 --> 01:12:52,580 除非我們看的fputc - 讓我放大了一點點。 861 01:12:52,580 --> 01:12:56,430 我們看到了什麼是好的,是需要我們讀出的字符使用fgetc函數, 862 01:12:56,430 --> 01:13:05,100 但後​​來我們給它一個流打印到。 863 01:13:05,100 --> 01:13:11,850 我們也可以用putchar函數,就可以直接輸出到標準輸出。 864 01:13:11,850 --> 01:13:16,070 因此,有一大堆不同的選擇,我們可以使用的打印。 865 01:13:16,070 --> 01:13:19,580 他們都在標準I / O庫。 866 01:13:19,580 --> 01:13:25,150 每當你想打印 - 輸出,默認情況下,將打印的特殊標準輸出流, 867 01:13:25,150 --> 01:13:27,910 這是標準輸出。 868 01:13:27,910 --> 01:13:41,300 因此,我們就可以把它作為一種本魔法值,在這裡的stdout。 869 01:13:41,300 --> 01:13:48,410 哎呀。將分號外部。 870 01:13:48,410 --> 01:13:52,790 >> 這是很多新的,時髦的信息在這裡。 871 01:13:52,790 --> 01:13:58,600 很多,這是很地道的,在這個意義上,這是代碼 872 01:13:58,600 --> 01:14:05,700 是這樣寫的,只是因為它是乾淨的,易於閱讀。 873 01:14:05,700 --> 01:14:11,520 有很多不同的方式來做到這一點,您可以使用許多不同的功能, 874 01:14:11,520 --> 01:14:14,680 但我們往往只是遵循相同的模式,一遍又一遍。 875 01:14:14,680 --> 01:14:20,180 所以,不要驚訝,如果你看到這樣的代碼來了一次又一次。 876 01:14:20,180 --> 01:14:25,690 好的。在這一點上,我們需要打破的一天。 877 01:14:25,690 --> 01:14:31,300 感謝您的到來。感謝收看如果你在線。我們會看到你下週。 878 01:14:31,300 --> 01:14:33,890 [CS50.TV]