1 00:00:00,000 --> 00:00:02,520 [Powered by Google Translate] [第4節 - 更舒適] 2 00:00:02,520 --> 00:00:04,850 [羅布·鮑登 - 哈佛大學] 3 00:00:04,850 --> 00:00:07,370 [這是CS50。 - CS50.TV] 4 00:00:08,920 --> 00:00:13,350 我們明天有一個測驗,如果你們不知道。 5 00:00:14,810 --> 00:00:20,970 它基本上是你能看到在課堂上或在課堂上所看到的一切。 6 00:00:20,970 --> 00:00:26,360 這包括指針,即使他們是一個非常新的主題。 7 00:00:26,360 --> 00:00:29,860 你至少應該深入了解他們的高水平。 8 00:00:29,860 --> 00:00:34,760 凡是過去在課堂上,你應該了解的測驗。 9 00:00:34,760 --> 00:00:37,320 所以,如果你有問題了,你可以問他們。 10 00:00:37,320 --> 00:00:43,280 但是,這將是一個非常學生主導的會議,你們問的問題, 11 00:00:43,280 --> 00:00:45,060 所以我希望人們有很多疑問。 12 00:00:45,060 --> 00:00:48,020 有沒有人有問題嗎? 13 00:00:49,770 --> 00:00:52,090 是。 >> [學生]你能對指針呢? 14 00:00:52,090 --> 00:00:54,350 我就去了指針。 15 00:00:54,350 --> 00:00:59,180 所有的變量一定住在內存中, 16 00:00:59,180 --> 00:01:04,450 但通常你不擔心你剛才說X + 2和y + 3 17 00:01:04,450 --> 00:01:07,080 編譯器將找出的東西都在那裡生活。 18 00:01:07,080 --> 00:01:12,990 當你正在處理的指針,現在你顯式地使用這些內存地址。 19 00:01:12,990 --> 00:01:19,800 因此,一個單一的變量將永遠只住在任何給定的時間在一個單一的地址。 20 00:01:19,800 --> 00:01:24,040 如果我們想聲明一個指針,類型是什麼的樣子? 21 00:01:24,040 --> 00:01:26,210 >> 我要聲明一個指針p。的類型是什麼樣子呢? 22 00:01:26,210 --> 00:01:33,530 [學生] * P。 >>呀。所以int * p。 23 00:01:33,530 --> 00:01:38,030 我怎樣才能使它指向為x? >> [學生]連字號。 24 00:01:40,540 --> 00:01:45,300 鮑登]符號是真正的被稱為運營商的地址。 25 00:01:45,300 --> 00:01:50,460 所以當我說&X變量x的內存地址。 26 00:01:50,460 --> 00:01:56,790 所以現在我有指針p,在我的代碼中的任何地方,我可以使用* P 27 00:01:56,790 --> 00:02:02,960 我也可以用x,這將是完全一樣的東西。 28 00:02:02,960 --> 00:02:09,520 (* P)。這是什麼做的嗎?這是什麼明星是什麼意思? 29 00:02:09,520 --> 00:02:13,120 [學生]是指在該點的值。 >>呀。 30 00:02:13,120 --> 00:02:17,590 因此,如果我們看它,它可以是非常有用的,畫出來的圖 31 00:02:17,590 --> 00:02:22,230 這是一個小方塊的記憶,而這恰好為x值4, 32 00:02:22,230 --> 00:02:25,980 然後我們有一個小盒子,內存為P, 33 00:02:25,980 --> 00:02:31,590 ,因此P點為x,所以我們畫一個箭頭從p到x。 34 00:02:31,590 --> 00:02:40,270 所以,當我們說我們說* P框,即p。 35 00:02:40,270 --> 00:02:46,480 星是按照箭頭,然後做你想做的那個盒子在那裡。 36 00:02:46,480 --> 00:03:01,090 因此,我可以說,* P = 7;將去框,x和變化,7。 37 00:03:01,090 --> 00:03:13,540 或者,我可以說Z = * P * 2,這是令人困惑,因為它的明星,明星。 38 00:03:13,540 --> 00:03:19,230 一星級提領P,其他明星乘以2。 39 00:03:19,230 --> 00:03:26,780 請注意,我可以有一樣好更換用x * P。 40 00:03:26,780 --> 00:03:29,430 您可以使用它們以同樣的方式。 41 00:03:29,430 --> 00:03:38,000 再後來我可以有p指向一個完全新的東西。 42 00:03:38,000 --> 00:03:42,190 我只能說,P = &z; 43 00:03:42,190 --> 00:03:44,940 所以,現在P沒有再久點為x,它指向到z。 44 00:03:44,940 --> 00:03:50,510 任何時候,我做* P一樣做Ž。 45 00:03:50,510 --> 00:03:56,170 因此,有用的事情是,一旦我們開始進入功能。 46 00:03:56,170 --> 00:03:59,790 >> 聲明一個指針,它指向的東西,這是一種無用的 47 00:03:59,790 --> 00:04:03,140 然後你只提領 48 00:04:03,140 --> 00:04:06,060 時,你也可以使用原來的變量開始。 49 00:04:06,060 --> 00:04:18,190 但是,當你進入功能 - 讓我們說,我們有一些功能,詮釋富, 50 00:04:18,190 --> 00:04:32,810 需要一個指針,* p = 6; 51 00:04:32,810 --> 00:04:39,990 就像我們之前看到的掉期,你不能做一個有效的交換和一個單獨的函數 52 00:04:39,990 --> 00:04:45,180 只是路過,因為一切都在C總是按值傳遞的整數。 53 00:04:45,180 --> 00:04:48,360 即使當你通過指針是按值傳遞的。 54 00:04:48,360 --> 00:04:51,940 碰巧的是,這些值是內存地址。 55 00:04:51,940 --> 00:05:00,770 所以當我說富(P);我的指針傳遞到函數foo 56 00:05:00,770 --> 00:05:03,910 然後foo是做* P = 6; 57 00:05:03,910 --> 00:05:08,600 所以裡面的函數,* p是等價於x, 58 00:05:08,600 --> 00:05:12,720 但我不能使用x裡面的這個函數該功能,因為它不是範圍之內。 59 00:05:12,720 --> 00:05:19,510 因此,* p = 6是唯一的出路,我可以訪問另一個函數的局部變量。 60 00:05:19,510 --> 00:05:23,600 或者,指針是唯一的出路,我可以訪問另一個函數的局部變量。 61 00:05:23,600 --> 00:05:31,600 [學生]:比方說,你想返回一個指針。你究竟是如何做到這一點? 62 00:05:31,600 --> 00:05:44,270 [鮑登]返回一個指針的東西,如int y = 3的回報&Y? >> [學生]是啊。 63 00:05:44,270 --> 00:05:48,480 鮑登]好吧。你不應該這樣做。這是不好的。 64 00:05:48,480 --> 00:05:59,480 我想我看到了在這些演講的幻燈片,你開始看到這個圖的內存 65 00:05:59,480 --> 00:06:02,880 在這裡,你有內存地址0 66 00:06:02,880 --> 00:06:09,550 在這裡你有內存地址4演出或2到32。 67 00:06:09,550 --> 00:06:15,120 那麼,你已經得到了一些東西,有些東西,然後你有你的堆棧 68 00:06:15,120 --> 00:06:21,780 你有你的堆,你剛開始學習,長大了。 69 00:06:21,780 --> 00:06:24,390 [學生]是不是在堆上面的堆棧? 70 00:06:24,390 --> 00:06:27,760 >> 是啊。堆在上面,不是嗎? >> [學生]好了,他把0之上。 71 00:06:27,760 --> 00:06:30,320 [學生]:哦,他把0之上。 >> [學生]:哦,好吧。 72 00:06:30,320 --> 00:06:36,060 免責聲明:Anywhere與CS50你要這樣看。 >> [學生]好吧。 73 00:06:36,060 --> 00:06:40,290 只是,當你第一次看到棧, 74 00:06:40,290 --> 00:06:45,000 就像當你想到一個堆棧,你認為彼此頂部堆放的東西。 75 00:06:45,000 --> 00:06:50,810 因此,我們傾向於翻轉左右,所以堆棧的增長就像一個堆棧通常會 76 00:06:50,810 --> 00:06:55,940 代替堆棧垂下。 >> [學生]不要堆技術上長大過,雖然? 77 00:06:55,940 --> 00:07:01,100 這取決於你的意思是長大了。 78 00:07:01,100 --> 00:07:04,010 堆和棧的增長方向相反。 79 00:07:04,010 --> 00:07:09,420 棧是在不斷增長,在這個意義上,它的成長過程 80 00:07:09,420 --> 00:07:12,940 朝著更高的內存地址和堆增長 81 00:07:12,940 --> 00:07:17,260 在它的增長向低內存地址。 82 00:07:17,260 --> 00:07:20,250 因此,頂端是0和底部是高的存儲器地址。 83 00:07:20,250 --> 00:07:26,390 他們兩人都不斷增長,只是在相反的方向。 84 00:07:26,390 --> 00:07:29,230 [學生]:我剛才只是說,因為你說你把堆棧的底部 85 00:07:29,230 --> 00:07:33,640 因為它的堆棧看起來更直觀,因為在堆的頂部開始, 86 00:07:33,640 --> 00:07:37,520 堆的本身上,所以that's - >>呀。 87 00:07:37,520 --> 00:07:44,960 你也覺得長大了,大的堆空間,但堆棧如此。 88 00:07:44,960 --> 00:07:50,280 因此,堆棧是一個樣的,我們要展現長大的。 89 00:07:50,280 --> 00:07:55,390 但是無論你看,否則會顯示地址0頂部 90 00:07:55,390 --> 00:07:59,590 和最高的內存地址的底部,所以這是你的內存通常的看法。 91 00:07:59,590 --> 00:08:02,100 >> 你有問題嗎? 92 00:08:02,100 --> 00:08:04,270 [學生]:你能告訴我們更多的堆? 93 00:08:04,270 --> 00:08:06,180 是啊。我會在第二。 94 00:08:06,180 --> 00:08:12,220 首先,要追溯到為什麼返回&Y是一件壞事, 95 00:08:12,220 --> 00:08:18,470 在棧上,你有一堆的棧幀代表所有的功能 96 00:08:18,470 --> 00:08:20,460 已被調用。 97 00:08:20,460 --> 00:08:27,990 因此,忽略以前的事情,你的堆棧的頂部總是要的主要功能 98 00:08:27,990 --> 00:08:33,090 因為這是第一個函數的調用。 99 00:08:33,090 --> 00:08:37,130 然後當你調用另一個函數的堆棧是怎麼回事增長下降。 100 00:08:37,130 --> 00:08:41,640 所以,如果我調用一些函數,foo和它得到它自己的堆棧幀, 101 00:08:41,640 --> 00:08:47,280 它可以調用一些函數,酒吧,它得到它自己的堆棧幀。 102 00:08:47,280 --> 00:08:49,840 和酒吧可以是遞歸的,它可以調用本身, 103 00:08:49,840 --> 00:08:54,150 等第二次調用酒吧是會得到它自己的堆棧幀。 104 00:08:54,150 --> 00:08:58,880 因此,這些堆棧幀的局部變量 105 00:08:58,880 --> 00:09:03,450 和所有的功能參數 - 106 00:09:03,450 --> 00:09:08,730 此功能是在本地範圍內的任何事情,這些堆棧幀。 107 00:09:08,730 --> 00:09:21,520 因此,這意味著當我說像酒吧是一個函數, 108 00:09:21,520 --> 00:09:29,270 我只是要聲明一個整數,然後返回一個指針,該整數。 109 00:09:29,270 --> 00:09:33,790 Ÿ生活? 110 00:09:33,790 --> 00:09:36,900 [學生] Y住在酒吧。 >> [鮑登]是啊。 111 00:09:36,900 --> 00:09:45,010 在這個小廣場的內存的某個地方,是一個較小的廣場,有Y。 112 00:09:45,010 --> 00:09:53,370 當我返回&Y,我返回一個指針,這個小的內存塊。 113 00:09:53,370 --> 00:09:58,400 但後​​來當函數返回時,它的堆棧幀被彈出堆棧。 114 00:10:01,050 --> 00:10:03,530 這就是為什麼它被稱為堆棧。 115 00:10:03,530 --> 00:10:06,570 這是堆棧的數據結構,如果你知道那是什麼。 116 00:10:06,570 --> 00:10:11,580 甚至像一個托盤堆疊的例子, 117 00:10:11,580 --> 00:10:16,060 主要是要去的底部,然後你調用的第一個函數是要去最重要的是, 118 00:10:16,060 --> 00:10:20,400 ,你可以回到主,直到返回的所有功能,被稱為 119 00:10:20,400 --> 00:10:22,340 已放置在它上面。 120 00:10:22,340 --> 00:10:28,650 >> [學生]所以,如果你做返回該值是Y,如有更改,恕不另行通知。 121 00:10:28,650 --> 00:10:31,290 是的,it's - >> [學生]會被覆蓋。 >>呀。 122 00:10:31,290 --> 00:10:34,660 這是完全 - 如果你嘗試 - 123 00:10:34,660 --> 00:10:38,040 這也將是一個int *吧,因為它返回一個指針, 124 00:10:38,040 --> 00:10:41,310 因此它的返回類型是int *。 125 00:10:41,310 --> 00:10:46,500 如果您嘗試使用這個函數的返回值,這是不確定的行為 126 00:10:46,500 --> 00:10:51,770 因為指針所指向壞的內存。 >> [學生]好吧。 127 00:10:51,770 --> 00:11:01,250 那麼,如果,例如,你宣布INT * Y = malloc的(如sizeof(int))? 128 00:11:01,250 --> 00:11:03,740 這是更好的。是。 129 00:11:03,740 --> 00:11:07,730 [學生]當我們談到如何將事情拖到我們的回收站 130 00:11:07,730 --> 00:11:11,750 他們實際上沒有被刪除,我們只是失去它們的指針。 131 00:11:11,750 --> 00:11:15,550 因此,在這種情況下,我們實際上是刪除值是它在內存中仍然存在? 132 00:11:15,550 --> 00:11:19,130 對於在大多數情況下,它會仍然存在。 133 00:11:19,130 --> 00:11:24,220 但是,讓我們說,我們碰巧調用一些其他的功能,巴茲。 134 00:11:24,220 --> 00:11:28,990 巴茲在這裡會得到它自己的堆棧幀。 135 00:11:28,990 --> 00:11:31,470 這將覆蓋所有的這些東西, 136 00:11:31,470 --> 00:11:34,180 然後如果你稍後嘗試和使用的指針,你有, 137 00:11:34,180 --> 00:11:35,570 它不會是相同的值。 138 00:11:35,570 --> 00:11:38,150 它已經改變了,只是因為你調用該函數巴茲。 139 00:11:38,150 --> 00:11:43,080 [學生],但我們沒有,我們仍然可以得到3? 140 00:11:43,080 --> 00:11:44,990 鮑登在所有的可能性,你會的。 141 00:11:44,990 --> 00:11:49,670 但你不能依靠這一點。 Ç只是說未定義的行為。 142 00:11:49,670 --> 00:11:51,920 >> [學生]:哦,確實如此。好吧。 143 00:11:51,920 --> 00:11:58,190 所以,當你想返回一個指針,這是在使用中的malloc來。 144 00:12:00,930 --> 00:12:15,960 我其實只是返回的malloc(3 *表示sizeof(int))。 145 00:12:17,360 --> 00:12:24,050 我們將在malloc的在第二,但對malloc的想法是所有的局部變量 146 00:12:24,050 --> 00:12:26,760 始終走在堆棧中。 147 00:12:26,760 --> 00:12:31,570 任何malloced的堆,它會永遠,始終是在堆上 148 00:12:31,570 --> 00:12:34,490 直到你明確地釋放它。 149 00:12:34,490 --> 00:12:42,130 因此,這意味著,當你的malloc東西,在函數返回後,它要生存下去。 150 00:12:42,130 --> 00:12:46,800 [學生]程序停止運行後,它會生存嗎? >>序號 151 00:12:46,800 --> 00:12:53,180 好了,所以它會在那裡,直到該程序是所有的方式運行。 “是的。 152 00:12:53,180 --> 00:12:57,510 我們可以去當程序停止運行時,會發生什麼。 153 00:12:57,510 --> 00:13:02,150 您可能需要提醒我,但是這是一個完全獨立的東西。 154 00:13:02,150 --> 00:13:04,190 [學生]的malloc創建一個指針? >>呀。 155 00:13:04,190 --> 00:13:13,030 的malloc的 - >> [學生]我認為的malloc指定的內存塊的指針可以使用。 156 00:13:15,400 --> 00:13:19,610 [鮑登我想,圖。 >> [學生]因此,雖然此功能嗎? 157 00:13:19,610 --> 00:13:26,430 [學生]是啊,malloc的指定,您可以使用一個內存塊, 158 00:13:26,430 --> 00:13:30,470 然後返回該內存塊的地址。 159 00:13:30,470 --> 00:13:36,750 >> 鮑登]是啊。所以,當你的malloc,你抓住一些的內存塊 160 00:13:36,750 --> 00:13:38,260 這是目前在堆中。 161 00:13:38,260 --> 00:13:43,040 如果堆太小,則堆只是要發展壯大,它生長在這個方向。 162 00:13:43,040 --> 00:13:44,650 因此,讓我們說,堆太小。 163 00:13:44,650 --> 00:13:49,960 然後,它的增長一點點,返回一個指向塊,只是增長。 164 00:13:49,960 --> 00:13:55,130 當你免費的東西,你有更多的空間在堆中, 165 00:13:55,130 --> 00:14:00,030 於是在以後調用malloc的,可以重複使用,您以前釋放的內存。 166 00:14:00,030 --> 00:14:09,950 malloc和free重要的事情是,它可以完全控制 167 00:14:09,950 --> 00:14:12,700 這些內存塊的整個生命週期。 168 00:14:12,700 --> 00:14:15,420 全局變量是永遠活著。 169 00:14:15,420 --> 00:14:18,500 在其範圍內的局部變量還活著。 170 00:14:18,500 --> 00:14:22,140 只要你走過去花括號,局部變量都死了。 171 00:14:22,140 --> 00:14:28,890 Malloced記憶是活著的時候,你希望它是活著的 172 00:14:28,890 --> 00:14:33,480 然後被釋放,當你告訴它被釋放。 173 00:14:33,480 --> 00:14:38,420 其實這些都是只有3種類型的內存,真的。 174 00:14:38,420 --> 00:14:41,840 自動內存管理,這是堆棧。 175 00:14:41,840 --> 00:14:43,840 事情發生自動為您。 176 00:14:43,840 --> 00:14:46,910 當你說詮釋的x,分配的內存詮釋x。 177 00:14:46,910 --> 00:14:51,630 當x超出範圍時,內存回收的x。 178 00:14:51,630 --> 00:14:54,790 有動態內存管理,這是malloc的, 179 00:14:54,790 --> 00:14:56,740 這是當你有控制。 180 00:14:56,740 --> 00:15:01,290 您可以動態決定內存時應該和不應該被分配。 181 00:15:01,290 --> 00:15:05,050 然後是靜態的,它只是意味著它永遠常存, 182 00:15:05,050 --> 00:15:06,610 這是全局變量是什麼。 183 00:15:06,610 --> 00:15:10,240 他們只是一直在內存中。 184 00:15:10,960 --> 00:15:12,760 >> 有問題嗎? 185 00:15:14,490 --> 00:15:17,230 [學生]:你可以定義一個塊用花括號 186 00:15:17,230 --> 00:15:21,220 但不必有一個if語句或while語句或類似的東西嗎? 187 00:15:21,220 --> 00:15:29,130 您可以在一個函數中定義一個塊,但有花括號。 188 00:15:29,130 --> 00:15:32,100 [學生]:所以,你不能只是像一個隨機的一對花括號中的代碼 189 00:15:32,100 --> 00:15:35,680 有局部變量嗎? >>是的,你可以。 190 00:15:35,680 --> 00:15:45,900 裡面的int酒吧,我們可以有{Y = 3;}。 191 00:15:45,900 --> 00:15:48,440 這應該是在這裡。 192 00:15:48,440 --> 00:15:52,450 但是,這完全定義的詮釋y的範圍。 193 00:15:52,450 --> 00:15:57,320 之後,第二個大括號,Y不能使用了。 194 00:15:57,910 --> 00:16:00,630 你幾乎從來沒有這樣做,雖然。 195 00:16:02,940 --> 00:16:07,370 程序結束時會發生什麼, 196 00:16:07,370 --> 00:16:18,760 有一個誤解/的一半謊言,我們只是使事情變得更容易給人以種。 197 00:16:18,760 --> 00:16:24,410 我們告訴你,當你分配內存 198 00:16:24,410 --> 00:16:29,860 你分配一些內存塊,該變量。 199 00:16:29,860 --> 00:16:34,190 但是你沒有真正直接接觸RAM永遠在你的程序中。 200 00:16:34,190 --> 00:16:37,490 如果你想起來了,我怎麼德魯 - 201 00:16:37,490 --> 00:16:44,330 實際上,如果你通過在GDB中,你會看到同樣的事情。 202 00:16:51,120 --> 00:16:57,590 不管有多少次你運行你的程序或你正在運行什麼程序, 203 00:16:57,590 --> 00:16:59,950 棧總是要開始 - 204 00:16:59,950 --> 00:17:06,510 你總是會看到的變數時,地址oxbffff的東西。 205 00:17:06,510 --> 00:17:09,470 它通常是在該地區的某個地方。 206 00:17:09,470 --> 00:17:18,760 但如何才能在2個節目可能有相同的內存的指針呢? 207 00:17:20,640 --> 00:17:27,650 [學生]有一些任意指定的地方應該是在RAM oxbfff 208 00:17:27,650 --> 00:17:31,320 其實是可以在不同的地方,當該功能被稱為。 209 00:17:31,320 --> 00:17:35,920 是啊。這個詞是虛擬內存。 210 00:17:35,920 --> 00:17:42,250 我們的想法是,每一個過程,每一個正在運行的程序在您的計算機上 211 00:17:42,250 --> 00:17:49,450 有自己的 - 讓我們假設32位 - 完全獨立的地址空間。 212 00:17:49,450 --> 00:17:51,590 這是一個地址空間。 213 00:17:51,590 --> 00:17:56,220 它有自己完全獨立的4 GB的使用。 214 00:17:56,220 --> 00:18:02,220 >> 所以,如果你同時運行2個節目,這個程序本身,看到4千兆字節 215 00:18:02,220 --> 00:18:04,870 這個程序看到4 GB的本身, 216 00:18:04,870 --> 00:18:07,720 這是不可能對這一計劃取消引用指針 217 00:18:07,720 --> 00:18:10,920 從這項計劃中的內存。 218 00:18:10,920 --> 00:18:18,200 虛擬內存是什麼是一個進程的地址空間的映射 219 00:18:18,200 --> 00:18:20,470 實際的事情上RAM。 220 00:18:20,470 --> 00:18:22,940 所以,就看您的操作系統知道, 221 00:18:22,940 --> 00:18:28,080 嘿,這傢伙解引用指針oxbfff,這實際上意味著 222 00:18:28,080 --> 00:18:31,040 他希望1000字節RAM, 223 00:18:31,040 --> 00:18:38,150 而如果這個程序指針引用oxbfff,他真正想要的RAM字節10000。 224 00:18:38,150 --> 00:18:41,590 他們可以隨意相距甚遠。 225 00:18:41,590 --> 00:18:48,730 在一個單一的進程的地址空間,即使是真實的東西。 226 00:18:48,730 --> 00:18:54,770 所以像看到所有4個千兆本身,但讓我們說 - 227 00:18:54,770 --> 00:18:57,290 [學生]:是否每一個過程 - 228 00:18:57,290 --> 00:19:01,350 比方說,你有一台電腦,只有4 GB的RAM。 229 00:19:01,350 --> 00:19:06,430 每一個過程看到整個4 GB的嗎? “是的。 230 00:19:06,430 --> 00:19:13,060 但是,4千兆字節,它認為是騙人的。 231 00:19:13,060 --> 00:19:20,460 這只是它認為這一切的記憶,因為它不知道任何其他過程中存​​在。 232 00:19:20,460 --> 00:19:28,140 它只會使用盡可能多的內存,因為它實際上需要。 233 00:19:28,140 --> 00:19:32,340 操作系統不會給RAM這一過程 234 00:19:32,340 --> 00:19:35,750 如果它不使用任何內存在這整個地區。 235 00:19:35,750 --> 00:19:39,300 它不會給該地區的記憶體。 236 00:19:39,300 --> 00:19:54,780 但這樣的想法是 - 我想 - 我不能想到一個比喻。 237 00:19:54,780 --> 00:19:56,780 類比是很難的。 238 00:19:57,740 --> 00:20:02,700 的虛擬內存的問題之一,它解決的事情之一 239 00:20:02,700 --> 00:20:06,810 是的進程應該是彼此完全不知道。 240 00:20:06,810 --> 00:20:12,140 所以你可以寫任何程​​序,任何指針解除引用, 241 00:20:12,140 --> 00:20:19,340 喜歡只寫一個程序,說*(ox1234), 242 00:20:19,340 --> 00:20:22,890 而這解引用的內存地址為1234。 243 00:20:22,890 --> 00:20:28,870 >> 但它的操作系統,然後翻譯一下1234手段。 244 00:20:28,870 --> 00:20:33,960 所以,如果1234恰好是一個有效的內存地址,這個過程中, 245 00:20:33,960 --> 00:20:38,800 就像是在堆棧上或什麼的,然後將返回值的內存地址 246 00:20:38,800 --> 00:20:41,960 據的過程都知道。 247 00:20:41,960 --> 00:20:47,520 但是,如果1234是不是一個有效的地址,如發生土地 248 00:20:47,520 --> 00:20:52,910 在一些小的內存,這裡說的是超越的堆棧和堆超越 249 00:20:52,910 --> 00:20:57,200 和你還沒有真正使用,那麼這時候你得到的東西一樣的segfaults 250 00:20:57,200 --> 00:21:00,260 因為你接觸的記憶,你不應該接觸。 251 00:21:07,180 --> 00:21:09,340 這也是如此 - 252 00:21:09,340 --> 00:21:15,440 一個32位系統,32位意味著你有32位以確定一個內存地址。 253 00:21:15,440 --> 00:21:22,970 這就是為什麼指針為8個字節,因為32位是8個字節 - 或4個字節。 254 00:21:22,970 --> 00:21:25,250 指針是4個字節。 255 00:21:25,250 --> 00:21:33,680 所以,當你看到一個指針一樣oxbfffff上,即是 - 256 00:21:33,680 --> 00:21:40,080 在任何給定的程序中,你可以構建任意的指針, 257 00:21:40,080 --> 00:21:46,330 任何地方,從OX0的牛8 f's的 - FFFFFFFF。 258 00:21:46,330 --> 00:21:49,180 [學生]:你不是說他們是4個字節? >>呀。 259 00:21:49,180 --> 00:21:52,730 [學生]然後每個字節 - >> [鮑登]十六進制。 260 00:21:52,730 --> 00:21:59,360 十六進制 - 5,6,7,8。所以指針,你要總是在十六進制。 261 00:21:59,360 --> 00:22:01,710 這只是我們如何分類的指針。 262 00:22:01,710 --> 00:22:05,240 每2個數字的十六進制數是1個字節。 263 00:22:05,240 --> 00:22:09,600 因此,有4個字節是8個十六進制數字。 264 00:22:09,600 --> 00:22:14,190 因此,每一個指針在32位系統將是4個字節, 265 00:22:14,190 --> 00:22:18,550 這意味著,在你的過程,你可以構造任意4個字節 266 00:22:18,550 --> 00:22:20,550 和一個指針,它 267 00:22:20,550 --> 00:22:32,730 這意味著,只要它是知道的,它可以處理一個完整的2到32個字節的存儲器。 268 00:22:32,730 --> 00:22:34,760 雖然它並沒有真正訪問, 269 00:22:34,760 --> 00:22:40,190 即使你的電腦只有512兆,它認為它有那麼多的記憶。 270 00:22:40,190 --> 00:22:44,930 和操作系統是足夠聰明的,它只會分配你真正需要的。 271 00:22:44,930 --> 00:22:49,630 它不只是去了,哦,一個新的進程:4個音樂會。 272 00:22:49,630 --> 00:22:51,930 >> 是啊。 >> [學生]什麼牛是什麼意思?你為什麼不寫呢? 273 00:22:51,930 --> 00:22:54,980 這僅僅是十六進制的符號。 274 00:22:54,980 --> 00:22:59,590 當你看到一個數字開始牛的,連續的東西是十六進制的。 275 00:23:01,930 --> 00:23:05,760 [學生]您解釋有關程序結束時會發生什麼。 “是的。 276 00:23:05,760 --> 00:23:09,480 程序結束時會發生什麼事是操作系統 277 00:23:09,480 --> 00:23:13,600 只是,它已經為這些地址,這就是它的映射刪除。 278 00:23:13,600 --> 00:23:17,770 操作系統可以現在只是給另一個程序使用該內存。 279 00:23:17,770 --> 00:23:19,490 [學生]好的。 280 00:23:19,490 --> 00:23:24,800 所以,當你分配在堆或堆棧或全局變量或任何東西, 281 00:23:24,800 --> 00:23:27,010 他們都只是消失盡快程序結束 282 00:23:27,010 --> 00:23:32,120 因為操作系統現在是免費的,任何其他進程的內存。 283 00:23:32,120 --> 00:23:35,150 [學生]:即使有可能還是寫的值嗎? >>呀。 284 00:23:35,150 --> 00:23:37,740 值很可能仍然存在。 285 00:23:37,740 --> 00:23:41,570 這只是這將是很難得到他們。 286 00:23:41,570 --> 00:23:45,230 它更難以得到他們比是在一個已刪除的文件 287 00:23:45,230 --> 00:23:51,450 因為被刪除的文件類型的坐在那裡,很長一段時間,和硬盤驅動器是大了很多。 288 00:23:51,450 --> 00:23:54,120 因此,它要覆蓋的不同部分的內存 289 00:23:54,120 --> 00:23:58,640 在它發生之前,該文件用於在覆蓋的內存塊。 290 00:23:58,640 --> 00:24:04,520 但主記憶體,RAM,循環快了很多, 291 00:24:04,520 --> 00:24:08,040 所以要非常迅速地被覆蓋。 292 00:24:10,300 --> 00:24:13,340 或其他任何問題嗎? 293 00:24:13,340 --> 00:24:16,130 [學生]我有一個不同的題目的問題。 “好了。 294 00:24:16,130 --> 00:24:19,060 有沒有人有問題嗎? 295 00:24:20,170 --> 00:24:23,120 >> 好吧。不同的主題。 >> [學生]好吧。 296 00:24:23,120 --> 00:24:26,550 我所經歷的實踐考驗, 297 00:24:26,550 --> 00:24:30,480 在其中的一個,它是談論的sizeof 298 00:24:30,480 --> 00:24:35,630 和它返回的值或不同類型的變量。 “是的。 299 00:24:35,630 --> 00:24:45,060 它說,int和long都返回4,所以他們都是4個字節長。 300 00:24:45,060 --> 00:24:48,070 是一個int和long之間有什麼區別呢,還是同樣的事情嗎? 301 00:24:48,070 --> 00:24:50,380 是的,是有差別的。 302 00:24:50,380 --> 00:24:52,960 C標準 - 303 00:24:52,960 --> 00:24:54,950 我可能會陷入困境。 304 00:24:54,950 --> 00:24:58,800 就像C標準C是什麼,官方文件C. 305 00:24:58,800 --> 00:25:00,340 這是它說什麼。 306 00:25:00,340 --> 00:25:08,650 因此,在C標準只是說,一個字符將永遠,永遠是1字節。 307 00:25:10,470 --> 00:25:19,040 之後的一切 - 簡短的永遠只是定義為大於或等於一個字符。 308 00:25:19,040 --> 00:25:23,010 這可能是嚴格大於,但不積極。 309 00:25:23,010 --> 00:25:31,940 一個int剛剛定義為大於或等於一個短。 310 00:25:31,940 --> 00:25:36,210 長定義為大於或等於int。 311 00:25:36,210 --> 00:25:41,600 和長的長是大於或等於長。 312 00:25:41,600 --> 00:25:46,610 因此,C標準定義是唯一的相對順序的一切。 313 00:25:46,610 --> 00:25:54,880 實際的內存佔用量普遍實施, 314 00:25:54,880 --> 00:25:57,640 但它在這一點上相當不錯的。 >> [學生]好吧。 315 00:25:57,640 --> 00:26:02,490 因此,短褲幾乎總是為2個字節。 316 00:26:04,920 --> 00:26:09,950 詮釋幾乎總是要為4個字節。 317 00:26:12,070 --> 00:26:15,340 長期多頭幾乎總是​​為8個字節。 318 00:26:17,990 --> 00:26:23,160 和渴望,這取決於您使用的是32位或64位系統。 319 00:26:23,160 --> 00:26:27,450 如此長的是將對應的系統的類型。 320 00:26:27,450 --> 00:26:31,920 如果您使用的是32位系統,如家電,這將是4個字節。 321 00:26:34,530 --> 00:26:42,570 如果您使用的是64位的,想了很多最新的計算機,這將是8個字節。 322 00:26:42,570 --> 00:26:45,230 >> 整數是幾乎總是在這一點上的4個字節。 323 00:26:45,230 --> 00:26:47,140 長期多頭幾乎都是8個字節。 324 00:26:47,140 --> 00:26:50,300 在過去,整數用於僅是2個字節。 325 00:26:50,300 --> 00:26:56,840 但是請注意,這完全滿足所有這些關係大於等於。 326 00:26:56,840 --> 00:27:01,280 ,只要是完全可以是相同的大小為一個整數, 327 00:27:01,280 --> 00:27:04,030 它也可以是相同的大小作為一個長長。 328 00:27:04,030 --> 00:27:11,070 它只是恰巧是在99.999%的系統,它是將等於 329 00:27:11,070 --> 00:27:15,800 int或一個很長很長。它僅僅依賴於32位或64位。 >> [學生]好吧。 330 00:27:15,800 --> 00:27:24,600 在彩車上,是如何指定的小數點位? 331 00:27:24,600 --> 00:27:27,160 作為二進制一樣嗎? >>呀。 332 00:27:27,160 --> 00:27:30,570 你不需要知道,CS50。 333 00:27:30,570 --> 00:27:32,960 你甚至不知道,在61。 334 00:27:32,960 --> 00:27:37,350 你不好好學習,真的在任何課程。 335 00:27:37,350 --> 00:27:42,740 這只是一個表象。 336 00:27:42,740 --> 00:27:45,440 我忘了確切的位分配。 337 00:27:45,440 --> 00:27:53,380 浮點的想法是,你分配一個特定的比特數來表示 - 338 00:27:53,380 --> 00:27:56,550 基本上,一切都在科學記數法。 339 00:27:56,550 --> 00:28:05,600 所以,你分配一個特定的數位代表的數量,如1.2345。 340 00:28:05,600 --> 00:28:10,200 我不能代表一個數字位數多於5。 341 00:28:12,200 --> 00:28:26,300 然後,你也分配一個特定的數位,它往往能像 342 00:28:26,300 --> 00:28:32,810 你只能去到了一定的數量,那樣你可以有最大的指數, 343 00:28:32,810 --> 00:28:36,190 和你只能去到一定指數, 344 00:28:36,190 --> 00:28:38,770 喜歡,你可以有最小的指數。 345 00:28:38,770 --> 00:28:44,410 >> 我不記得確切的方式位被分配到所有這些值, 346 00:28:44,410 --> 00:28:47,940 但在一定的比特數的致力於為1.2345, 347 00:28:47,940 --> 00:28:50,930 另一個一定的比特數,致力於指數, 348 00:28:50,930 --> 00:28:55,670 它的唯一可能代表一個具有一定規模的指數。 349 00:28:55,670 --> 00:29:01,100 [學生]和雙?那是像一個額外的長期持股量呢? >>呀。 350 00:29:01,100 --> 00:29:07,940 這是同樣的事情,但現在你用8個字節,而不是4個字節為float。 351 00:29:07,940 --> 00:29:11,960 現在,您就可以使用9位或10位, 352 00:29:11,960 --> 00:29:16,630 而這將是能上去到第300,而不是100。 >> [學生]好吧。 353 00:29:16,630 --> 00:29:21,550 花車也是4個字節。 “是的。 354 00:29:21,550 --> 00:29:27,520 好了,再次,它可能取決於整體上普遍實施, 355 00:29:27,520 --> 00:29:30,610 但花車為4個字節,雙打有8個。 356 00:29:30,610 --> 00:29:33,440 雙打被稱為雙,因為它們的兩倍大小的花車。 357 00:29:33,440 --> 00:29:38,380 [學生]好的。以及是否有兩雙嗎? >>有沒有。 358 00:29:38,380 --> 00:29:43,660 我想 - >> [學生]喜歡長期多頭? >>呀。我不認為如此。是。 359 00:29:43,660 --> 00:29:45,950 [學生]在去年的測試的主要功能有問題 360 00:29:45,950 --> 00:29:49,490 是程序的一部分。 361 00:29:49,490 --> 00:29:52,310 答案是,它並沒有你的程序的一部分。 362 00:29:52,310 --> 00:29:55,100 在什麼情況下?這是我所看到的。 363 00:29:55,100 --> 00:29:59,090 [波頓似乎 - >> [學生]什麼情況? 364 00:29:59,090 --> 00:30:02,880 你有問題嗎? >> [學生]是的,我可以肯定拉起來。 365 00:30:02,880 --> 00:30:07,910 它沒有,從技術上說,但基本上將是。 366 00:30:07,910 --> 00:30:10,030 [學生]我看到了一個不同的年份的。 367 00:30:10,030 --> 00:30:16,220 這是True或False:一個有效的 - “”哦,。c文件嗎? 368 00:30:16,220 --> 00:30:18,790 [學生]所有的文件必須有 - [都講一次 - 不知所云] 369 00:30:18,790 --> 00:30:21,120 好吧。所以這是分開的。 370 00:30:21,120 --> 00:30:26,800 >> 。c文件只需要包含的功能。 371 00:30:26,800 --> 00:30:32,400 你可以編譯成機器代碼,二進制文件,不管, 372 00:30:32,400 --> 00:30:36,620 沒有它的可執行文件。 373 00:30:36,620 --> 00:30:39,420 一個有效的可執行文件必須有一個main函數。 374 00:30:39,420 --> 00:30:45,460 你可以寫100個函數在1個文件,但沒有主 375 00:30:45,460 --> 00:30:48,800 ,然後編譯為二進制, 376 00:30:48,800 --> 00:30:54,460 那麼你就寫另一個文件,只有主,但這些函數調用了一堆 377 00:30:54,460 --> 00:30:56,720 在這個二進制文件在這裡。 378 00:30:56,720 --> 00:31:01,240 因此,如果你正在做的可執行文件,這就是鏈接器 379 00:31:01,240 --> 00:31:05,960 是它結合了這2成一個可執行的二進制文件。 380 00:31:05,960 --> 00:31:11,400 因此,一個c文件並不需要在所有的主要功能。 381 00:31:11,400 --> 00:31:19,220 而在大的代碼庫,你會看到成千上萬的文件和1個主文件。 382 00:31:23,960 --> 00:31:26,110 還有問題嗎? 383 00:31:29,310 --> 00:31:31,940 [學生]是另一個問題。 384 00:31:31,940 --> 00:31:36,710 它說是一個編譯器。 True或False? 385 00:31:36,710 --> 00:31:42,030 得到的答案是假的,我明白了為什麼它不是像鏗鏘。 386 00:31:42,030 --> 00:31:44,770 但我們所說的是什麼,如果不是嗎? 387 00:31:44,770 --> 00:31:49,990 Make是基本上只是 - 我可以清楚地看到它調用它。 388 00:31:49,990 --> 00:31:52,410 但它只是運行命令。 389 00:31:53,650 --> 00:31:55,650 製作。 390 00:31:58,240 --> 00:32:00,870 我可以拉起來。是啊。 391 00:32:10,110 --> 00:32:13,180 哦,是的。同時也要做到這一點。 392 00:32:13,180 --> 00:32:17,170 這說的make工具的目的是自動確定 393 00:32:17,170 --> 00:32:19,610 一個大程序都需要重新編譯件 394 00:32:19,610 --> 00:32:22,350 發出的命令重新編譯它們。 395 00:32:22,350 --> 00:32:27,690 你可以讓文件,絕對是巨大的。 396 00:32:27,690 --> 00:32:33,210 讓看文件的時間戳記,就像我們之前說的, 397 00:32:33,210 --> 00:32:36,930 你可以編譯單個文件,並且它不是,直到你得到的鏈接器 398 00:32:36,930 --> 00:32:39,270 他們拼湊成一個可執行文件。 399 00:32:39,270 --> 00:32:43,810 所以,如果你有10個不同的文件,你犯了一個變化1, 400 00:32:43,810 --> 00:32:47,870 那麼是什麼牌子要做的只是重新編譯,1個文件 401 00:32:47,870 --> 00:32:50,640 然後重新鏈接起來。 402 00:32:50,640 --> 00:32:53,020 但比它更笨。 403 00:32:53,020 --> 00:32:55,690 它是由你來完全確定,這就是它應該做的。 404 00:32:55,690 --> 00:32:59,560 默認情況下,有能力認識到這一點時間戳的東西, 405 00:32:59,560 --> 00:33:03,220 但你可以寫一個make文件做任何事情。 406 00:33:03,220 --> 00:33:09,150 你可以寫一個文件,這樣,當你鍵入它只是CD到另一個目錄。 407 00:33:09,150 --> 00:33:15,560 我感到沮喪,因為我粘性裡面的一切,我的產品 408 00:33:15,560 --> 00:33:21,740 然後我看到的PDF從Mac。 409 00:33:21,740 --> 00:33:30,720 >> 所以我去搜索,我可以幹什麼去了,連接到服務器, 410 00:33:30,720 --> 00:33:36,950 連接到服務器,我為我的設備,然後我打開PDF 411 00:33:36,950 --> 00:33:40,190 被編譯使用LaTeX。 412 00:33:40,190 --> 00:33:49,320 但我感到沮喪,因為每一次我需要更新的PDF, 413 00:33:49,320 --> 00:33:53,900 我不得不將它複製到一個特定的目錄,它可以訪問 414 00:33:53,900 --> 00:33:57,710 它越來越煩了。 415 00:33:57,710 --> 00:34:02,650 所以我寫了一個make文件,你必須定義它使事情。 416 00:34:02,650 --> 00:34:06,130 這是你如何使PDF LaTeX的。 417 00:34:06,130 --> 00:34:10,090 就像任何其他的make文件 - 我猜你沒見過的牌子文件, 418 00:34:10,090 --> 00:34:13,510 但我們有一個全球性的品牌在家電文件,該文件只是說, 419 00:34:13,510 --> 00:34:16,679 如果你要編譯一個C文件,使用鏗鏘。 420 00:34:16,679 --> 00:34:20,960 所以在這裡,我讓我說,在我的make文件 421 00:34:20,960 --> 00:34:25,020 這個文件,你會想與PDF LaTeX的編譯。 422 00:34:25,020 --> 00:34:27,889 所以它的PDF膠乳做編譯。 423 00:34:27,889 --> 00:34:31,880 提出的,是不能編譯。它只是運行這些命令中指定的順序我。 424 00:34:31,880 --> 00:34:36,110 所以它運行的PDF LaTeX的,它會將我希望它被複製到的目錄, 425 00:34:36,110 --> 00:34:38,270 它的CD的目錄和做其他的事情, 426 00:34:38,270 --> 00:34:42,380 但它是所有認識的文件改變時, 427 00:34:42,380 --> 00:34:45,489 ,如果它的變化,然後它會運行它應該運行的命令 428 00:34:45,489 --> 00:34:48,760 當文件更改。 >> [學生]好吧。 429 00:34:50,510 --> 00:34:54,420 我不知道在哪裡的全球MAKE文件是為我檢查出來的。 430 00:34:57,210 --> 00:35:04,290 其他問題嗎?任何東西,從過去的測驗?任何指針的東西嗎? 431 00:35:06,200 --> 00:35:08,730 有一些微妙的指針一樣的東西 - 432 00:35:08,730 --> 00:35:10,220 我不會能夠找到一個競猜的問題上 - 433 00:35:10,220 --> 00:35:16,250 但就像這樣的事情。 434 00:35:19,680 --> 00:35:24,060 請確保你明白,當我說* X * Y - 435 00:35:24,890 --> 00:35:28,130 這不正是任何東西,我猜。 436 00:35:28,130 --> 00:35:32,140 但是,像* X * Y,那是2個變量是在棧上。 437 00:35:32,140 --> 00:35:37,220 當我說X = malloc的(如sizeof(int)),X仍然是一個變量在棧上, 438 00:35:37,220 --> 00:35:41,180 malloc的一些塊以上的堆,我們在x點的堆。 439 00:35:41,180 --> 00:35:43,900 >> 因此,在棧上的堆的東西。 440 00:35:43,900 --> 00:35:48,100 無論何時,只要你的malloc什麼,你不可避免地存儲它裡面一個指針。 441 00:35:48,100 --> 00:35:55,940 因此,該指針是在棧上,malloced塊在堆中。 442 00:35:55,940 --> 00:36:01,240 很多人感到困惑,並說* X = malloc的,x是在堆上。 443 00:36:01,240 --> 00:36:04,100 號X點是在堆上。 444 00:36:04,100 --> 00:36:08,540 x本身是在棧上,無論出於何種原因,除非你有X是一個全局變量, 445 00:36:08,540 --> 00:36:11,960 在這種情況下,它正好是在另一個區域中的內存。 446 00:36:13,450 --> 00:36:20,820 因此,跟踪,這些盒子和箭頭圖是很常見的測驗。 447 00:36:20,820 --> 00:36:25,740 或者,如果它不是0測驗,測驗1。 448 00:36:27,570 --> 00:36:31,940 你應該知道所有的這些,在編譯的步驟 449 00:36:31,940 --> 00:36:35,740 因為你必須回答這些問題。是。 450 00:36:35,740 --> 00:36:38,940 [學生]:我們能不能去這些步驟 - >>當然。 451 00:36:48,340 --> 00:36:58,640 我們之前的步驟和編譯預處理, 452 00:36:58,640 --> 00:37:16,750 編譯,彙編和鏈接。 453 00:37:16,750 --> 00:37:21,480 預處理。那是幹什麼的? 454 00:37:29,720 --> 00:37:32,290 這是最簡單的一步 - 嗯,不喜歡 - 455 00:37:32,290 --> 00:37:35,770 這並不意味著它應該是顯而易見的,但是它是最容易的一步。 456 00:37:35,770 --> 00:37:38,410 你們能實現它自己。是啊。 457 00:37:38,410 --> 00:37:43,410 [學生]你有你的,包括像這樣的副本,然後還定義。 458 00:37:43,410 --> 00:37:49,250 它看起來的東西如#include和#define, 459 00:37:49,250 --> 00:37:53,800 它只是複製和粘貼那些真正的意思。 460 00:37:53,800 --> 00:37:59,240 因此,當你說#cs50.h的,預處理的複製和粘貼cs50.h 461 00:37:59,240 --> 00:38:01,030 到該線。 462 00:38:01,030 --> 00:38:06,640 當你說#定義x為4,預處理整個程序 463 00:38:06,640 --> 00:38:10,400 4 x的所有實例替換。 464 00:38:10,400 --> 00:38:17,530 因此,預處理器需要一個有效的C文件,並輸出一個有效的C文件 465 00:38:17,530 --> 00:38:20,300 事情已經複製和粘貼。 466 00:38:20,300 --> 00:38:24,230 所以,現在編譯。那是幹什麼的? 467 00:38:25,940 --> 00:38:28,210 [學生]從C到二進制。 468 00:38:28,210 --> 00:38:30,970 >> 鮑登]不走,一路為二進制。 469 00:38:30,970 --> 00:38:34,220 [學生]為機器代碼呢? >>這是不是機器代碼。 470 00:38:34,220 --> 00:38:35,700 [學生]大會? >>大會。 471 00:38:35,700 --> 00:38:38,890 在大會之前,去所有的方式為C代碼, 472 00:38:38,890 --> 00:38:45,010 和大多數語言做這樣的事情。 473 00:38:47,740 --> 00:38:50,590 選擇任何高級語言,如果你要編譯它, 474 00:38:50,590 --> 00:38:52,390 它的編譯步驟。 475 00:38:52,390 --> 00:38:58,140 首先,它要編譯Python到C,那麼它會編譯C大會, 476 00:38:58,140 --> 00:39:01,600 然後,大會會得到轉換為二進制。 477 00:39:01,600 --> 00:39:07,800 所以編譯是把它從C到大會。 478 00:39:07,800 --> 00:39:12,130 這個詞編譯通常是指把它從一個更高的水平 479 00:39:12,130 --> 00:39:14,340 到一個較低的電平的編程語言。 480 00:39:14,340 --> 00:39:19,190 因此,這是唯一的編譯步驟,你開始與一個高層次的語言 481 00:39:19,190 --> 00:39:23,270 並最終在一個低層次的語言,這就是為什麼被稱為編譯步驟。 482 00:39:25,280 --> 00:39:33,370 [學生]在編寫過程中,讓我們說你已經完成了#cs50.h. 483 00:39:33,370 --> 00:39:42,190 編譯器重新編譯cs50.h,類似的功能,在那裡, 484 00:39:42,190 --> 00:39:45,280 翻譯成彙編代碼為好, 485 00:39:45,280 --> 00:39:50,830 或將它複製並粘貼大會前的東西嗎? 486 00:39:50,830 --> 00:39:56,910 cs50.h將幾乎永遠不會結束在大會。 487 00:39:59,740 --> 00:40:03,680 函數原型和事情的東西一樣,只是你要小心。 488 00:40:03,680 --> 00:40:09,270 它保證了編譯器可以檢查的事情,比如你調用函數 489 00:40:09,270 --> 00:40:12,910 用正確的返回類型和正確的參數之類的東西。 490 00:40:12,910 --> 00:40:18,350 >> 所以cs50.h將預處理到文​​件中,然後當它的編譯 491 00:40:18,350 --> 00:40:22,310 它基本上是扔掉後,確保一切都被正確調用。 492 00:40:22,310 --> 00:40:29,410 但定義的函數在CS50庫,這是分開cs50.h, 493 00:40:29,410 --> 00:40:33,610 那些不會被單獨編譯。 494 00:40:33,610 --> 00:40:37,270 這實際上會在連接步驟,所以我們會在第二。 495 00:40:37,270 --> 00:40:40,100 但首先,什麼是裝配? 496 00:40:41,850 --> 00:40:44,500 [學生]:大會為二進制? >>呀。 497 00:40:46,300 --> 00:40:48,190 組裝。 498 00:40:48,190 --> 00:40:54,710 我們不把它編譯,因為大會是一個很值得純二進制翻譯。 499 00:40:54,710 --> 00:41:00,230 大會二進制的邏輯是非常小的。 500 00:41:00,230 --> 00:41:03,180 這就像在一個表中查找,哦,我們有這個指令; 501 00:41:03,180 --> 00:41:06,290 對應於二進制01110。 502 00:41:10,200 --> 00:41:15,230 因此,組裝一般輸出。o文件的文件。 503 00:41:15,230 --> 00:41:19,020 o文件是我們之前說的, 504 00:41:19,020 --> 00:41:21,570 怎樣文件不需要有一個主要的功能。 505 00:41:21,570 --> 00:41:27,640 可將任何文件編譯成。o文件,只要它是一個有效的C文件。 506 00:41:27,640 --> 00:41:30,300 它可以被編譯成。Ø。 507 00:41:30,300 --> 00:41:43,030 現在,連接實際上是帶來了一堆的。o文件,並給他們帶來一個可執行的。 508 00:41:43,030 --> 00:41:51,110 因此,聯做的是你能想到的的CS50庫的。o文件。 509 00:41:51,110 --> 00:41:56,980 這是一個已編譯的二進制文件。 510 00:41:56,980 --> 00:42:03,530 因此,當你編譯你的文件,你的hello.c的,這調用getString, 511 00:42:03,530 --> 00:42:06,360 ,hello.c中被編譯成hello.o 512 00:42:06,360 --> 00:42:08,910 hello.o是二進制。 513 00:42:08,910 --> 00:42:12,830 它使用GetString的,所以它需要去到cs50.o的, 514 00:42:12,830 --> 00:42:16,390 連接器smooshes在一起,並將其複製到這個文件中的GetString 515 00:42:16,390 --> 00:42:20,640 和出來一個可執行文件,它需要的所有功能。 516 00:42:20,640 --> 00:42:32,620 因此,cs50.o是不實際的O文件,但它是足夠接近,有沒有根本的區別。 517 00:42:32,620 --> 00:42:36,880 因此,聯剛帶來了一大堆的文件 518 00:42:36,880 --> 00:42:41,390 分別包含了所有的功能,我需要使用 519 00:42:41,390 --> 00:42:46,120 並創建將實際運行的可執行文件。 520 00:42:48,420 --> 00:42:50,780 >> 因此,這也是我們之前說什麼 521 00:42:50,780 --> 00:42:55,970 在那裡你可以有1000個。c文件,在編譯所有。o文件, 522 00:42:55,970 --> 00:43:00,040 這可能會需要一段時間,那麼你改變1。c文件。 523 00:43:00,040 --> 00:43:05,480 你只需要重新編譯。c文件,然後重新鏈接一切, 524 00:43:05,480 --> 00:43:07,690 連接一切重新走到一起。 525 00:43:09,580 --> 00:43:11,430 [學生]當我們連接我們寫lcs50嗎? 526 00:43:11,430 --> 00:43:20,510 是啊,所以lcs50。這標誌信號連接器,你應該鏈接該庫中。 527 00:43:26,680 --> 00:43:28,910 有問題嗎? 528 00:43:41,310 --> 00:43:46,860 我們走了過來二進制以外的第一堂課,5秒嗎? 529 00:43:50,130 --> 00:43:53,010 我不認為如此。 530 00:43:55,530 --> 00:43:58,820 你應該知道,我們已經討論了所有的大的OS, 531 00:43:58,820 --> 00:44:02,670 ,你應該是可以的,如果我給你一個函數, 532 00:44:02,670 --> 00:44:09,410 你可以說這是大O,大約。好,大O是粗糙的。 533 00:44:09,410 --> 00:44:15,300 所以如果你看到嵌套的for循環遍歷相同數量的東西, 534 00:44:15,300 --> 00:44:22,260 如INT I,I > [學生] n的平方。 >>它往往為n的平方。 535 00:44:22,260 --> 00:44:25,280 如果您有三重嵌套的,它往往是n的三次方。 536 00:44:25,280 --> 00:44:29,330 這樣的事情,你應該能夠立即指出。 537 00:44:29,330 --> 00:44:33,890 你需要知道插入排序,冒泡排序和歸併排序和所有的人。 538 00:44:33,890 --> 00:44:41,420 這是容易理解為什麼他們是那些N的平方和n日誌n和所有的 539 00:44:41,420 --> 00:44:47,810 因為我覺得有一個測驗的一年,我們基本上給你 540 00:44:47,810 --> 00:44:55,050 冒泡排序算法的實現和說,“什麼是這個函數的運行時間?” 541 00:44:55,050 --> 00:45:01,020 所以,如果你認出來冒泡排序,那麼你可以立即回答n的平方。 542 00:45:01,020 --> 00:45:05,470 但是,如果你只是來看看,你不甚至需要認識到它的冒泡排序; 543 00:45:05,470 --> 00:45:08,990 你可以說這是這樣做的,這。這是n的平方。 544 00:45:12,350 --> 00:45:14,710 [學生]有任何強硬的例子,你可以拿出, 545 00:45:14,710 --> 00:45:20,370 像類似的想法搞清楚? 546 00:45:20,370 --> 00:45:24,450 >> 我不認為我們會給你任何強硬的例子。 547 00:45:24,450 --> 00:45:30,180 冒泡排序的是艱難的,因為我們會去, 548 00:45:30,180 --> 00:45:36,280 甚至認為,只要你明白,你遍歷數組 549 00:45:36,280 --> 00:45:41,670 為每個數組中的元素,這將是東西的N平方。 550 00:45:45,370 --> 00:45:49,940 有一般的問題,比如在這裡,我們有 - 哦。 551 00:45:55,290 --> 00:45:58,530 就在幾天前,道格聲稱,“我已經發明了一種算法,可以排序的數組 552 00:45:58,530 --> 00:46:01,780 “n個數O(log n)的時間!” 553 00:46:01,780 --> 00:46:04,900 那麼,我們如何知道這是不可能的嗎? 554 00:46:04,900 --> 00:46:08,850 [聽不見的學生反應] >>呀。 555 00:46:08,850 --> 00:46:13,710 最起碼,你要摸每個數組中的元素, 556 00:46:13,710 --> 00:46:16,210 所以這是不可能的,對數組進行排序 - 557 00:46:16,210 --> 00:46:20,850 如果一切是在未排序的順序,那麼你將要接觸的數組中的一切, 558 00:46:20,850 --> 00:46:25,320 所以這是不可能做到這一點比O的n。 559 00:46:27,430 --> 00:46:30,340 [學生]您向我們展示了這個例子能夠做到這一點,在O n個 560 00:46:30,340 --> 00:46:33,920 如果你使用了大量的內存。 >>呀。 561 00:46:33,920 --> 00:46:37,970 而that's - 我忘了什麼that's - 計數排序? 562 00:46:47,360 --> 00:46:51,330 嗯。這是一個整數的排序算法。 563 00:46:59,850 --> 00:47:05,100 我一直在尋找這個特殊的名字,我不記得上週。 564 00:47:05,100 --> 00:47:13,000 是啊。這些類型的排序,可以完成的事情,大O的n。 565 00:47:13,000 --> 00:47:18,430 但也有局限性,你只能使用整數到了一定的數量。 566 00:47:20,870 --> 00:47:24,560 另外,如果你想的東西that's排序 - 567 00:47:24,560 --> 00:47:30,750 如果您的陣列為012,-12,151,400萬, 568 00:47:30,750 --> 00:47:35,120 然後,單元素要完全毀掉整個分揀。 569 00:47:42,060 --> 00:47:44,030 >> 有問題嗎? 570 00:47:49,480 --> 00:47:58,870 [學生]如果你有一個遞歸函數,它只是使遞歸調用 571 00:47:58,870 --> 00:48:02,230 在一個return語句,這是尾遞歸, 572 00:48:02,230 --> 00:48:07,360 這不使用更多的內存在運行時 573 00:48:07,360 --> 00:48:12,550 或至少​​使用可比較的記憶體作為一個迭代的解決方案嗎? 574 00:48:12,550 --> 00:48:14,530 波頓:是的。 575 00:48:14,530 --> 00:48:19,840 它可能會有點慢,但不是真的。 576 00:48:19,840 --> 00:48:23,290 尾遞歸是相當不錯的。 577 00:48:23,290 --> 00:48:32,640 再看看堆棧幀,讓我們說,我們有主 578 00:48:32,640 --> 00:48:42,920 我們有int酒吧(X)的東西。 579 00:48:42,920 --> 00:48:52,310 這不是一個完美的遞歸函數,但回報酒吧(X - 1)。 580 00:48:52,310 --> 00:48:57,620 所以,很顯然,這是有缺陷的。您需要基礎案例之類的東西。 581 00:48:57,620 --> 00:49:00,360 但這裡的想法是,這是尾遞歸, 582 00:49:00,360 --> 00:49:06,020 這意味著,當主調用酒吧,它會得到它的堆棧幀。 583 00:49:09,550 --> 00:49:12,440 在這個堆棧幀,將是一個小的內存塊 584 00:49:12,440 --> 00:49:17,490 對應其參數x。 585 00:49:17,490 --> 00:49:25,840 因此,讓我們說主要發生在調用酒吧(100); 586 00:49:25,840 --> 00:49:30,050 因此,x是要開始為100。 587 00:49:30,050 --> 00:49:35,660 如果編譯器認識到這是一個尾遞歸函數, 588 00:49:35,660 --> 00:49:38,540 然後在酒吧禁止遞歸調用, 589 00:49:38,540 --> 00:49:45,490 而不是製造新的棧幀,這是堆棧中開始增長在很大程度上, 590 00:49:45,490 --> 00:49:48,220 最終它會運行到堆,然後你得到的segfaults 591 00:49:48,220 --> 00:49:51,590 因為內存開始碰撞。 592 00:49:51,590 --> 00:49:54,830 >> 因此,而不是它自己的堆棧幀,它可以實現, 593 00:49:54,830 --> 00:49:59,080 哎,我從來沒有真正回來到這個堆棧幀, 594 00:49:59,080 --> 00:50:08,040 所以不是我就替換此參數與99,然後開始酒吧。 595 00:50:08,040 --> 00:50:11,810 ,然後它會再次將達到迴轉桿(X - 1), 596 00:50:11,810 --> 00:50:17,320 ,而不是一個新的堆棧幀,將剛剛替換其當前參數98 597 00:50:17,320 --> 00:50:20,740 然後跳回到最開始的吧。 598 00:50:23,860 --> 00:50:30,430 這些操作,更換,堆棧上的值,跳回到開始, 599 00:50:30,430 --> 00:50:32,430 是非常有效的。 600 00:50:32,430 --> 00:50:41,500 所以這不僅是一個單獨的函數相同的內存使用情況,這是迭代 601 00:50:41,500 --> 00:50:45,390 因為你只能使用1堆棧幀,但你沒有苦難的缺點 602 00:50:45,390 --> 00:50:47,240 調用函數。 603 00:50:47,240 --> 00:50:50,240 調用函數可能會有點昂貴,因為它需要做的這一切設置 604 00:50:50,240 --> 00:50:52,470 和拆卸,這一切的東西。 605 00:50:52,470 --> 00:50:58,160 因此,這尾遞歸還是不錯的。 606 00:50:58,160 --> 00:51:01,170 [學生]:為什麼不創建新的步驟? 607 00:51:01,170 --> 00:51:02,980 因為它意識到它並不需要。 608 00:51:02,980 --> 00:51:07,800 調用酒吧剛剛返回的遞歸調用。 609 00:51:07,800 --> 00:51:12,220 因此,它並不需要做任何的返回值。 610 00:51:12,220 --> 00:51:15,120 它只是將立即返回。 611 00:51:15,120 --> 00:51:20,530 因此,它只是要更換自己的參數,並重新開始。 612 00:51:20,530 --> 00:51:25,780 還有,如果你沒有尾遞歸版本, 613 00:51:25,780 --> 00:51:31,460 然後你會得到所有這些酒吧,這個酒吧返回 614 00:51:31,460 --> 00:51:36,010 它有這一個,然後返回它的值,酒吧立即返回 615 00:51:36,010 --> 00:51:39,620 ,並返回它的值這一個,那麼它只是將立即返回 616 00:51:39,620 --> 00:51:41,350 這一個,並返回它的值。 617 00:51:41,350 --> 00:51:45,350 因此,要保存彈出所有這些東西的堆棧 618 00:51:45,350 --> 00:51:48,730 因為返回值僅僅是將要通過所有的方式回到反正。 619 00:51:48,730 --> 00:51:55,400 那麼為什麼不直接取代我們的觀點與更新的參數,並重新開始嗎? 620 00:51:57,460 --> 00:52:01,150 如果該函數不是尾遞歸,如果你做這樣的事情 - 621 00:52:01,150 --> 00:52:07,530 [學生]如果酒吧(X + 1)。 >>呀。 622 00:52:07,530 --> 00:52:11,770 >> 所以,如果你把它的條件,那麼你正在做的事情的返回值。 623 00:52:11,770 --> 00:52:16,260 或者即使你只是做回2條(X - 1)。 624 00:52:16,260 --> 00:52:23,560 所以,現在巴( - 1)需要返回,以便它來計算該值的2倍, 625 00:52:23,560 --> 00:52:26,140 所以現在它需要有自己的獨立的堆棧幀, 626 00:52:26,140 --> 00:52:31,180 現在,無論你怎麼努力,你將需要 - 627 00:52:31,180 --> 00:52:34,410 這是不是尾遞歸的。 628 00:52:34,410 --> 00:52:37,590 [學生]我會盡量把一個遞歸的目標是一個尾遞歸 - 629 00:52:37,590 --> 00:52:41,450 鮑登在一個理想的世界,但在CS50你沒有。 630 00:52:43,780 --> 00:52:49,280 一般情況下,為了得到尾遞歸,成立一個額外的參數 631 00:52:49,280 --> 00:52:53,550 欄將採取整數X到Y 632 00:52:53,550 --> 00:52:56,990 y對應到極致的事情,你要返回。 633 00:52:56,990 --> 00:53:03,650 那麼你將要返回酒吧(X - 1),2 * Y。 634 00:53:03,650 --> 00:53:09,810 所以,這只是一個高層次的,你怎麼變換的事情是尾遞歸。 635 00:53:09,810 --> 00:53:13,790 但是,額外的參數 - 636 00:53:13,790 --> 00:53:17,410 然後在結束時你達到你的基本情況,你剛剛返回y 637 00:53:17,410 --> 00:53:22,740 因為你已經積累的全部時間,你想要的返回值。 638 00:53:22,740 --> 00:53:27,280 你這種已經這樣做迭代,但使用遞歸調用。 639 00:53:32,510 --> 00:53:34,900 有問題嗎? 640 00:53:34,900 --> 00:53:39,890 [學生]也許指針的算術運算,如在使用字符串。 “當然可以。 641 00:53:39,890 --> 00:53:43,610 指針的算術運算。 642 00:53:43,610 --> 00:53:48,440 使用字符串時,很容易因為字符串是char明星, 643 00:53:48,440 --> 00:53:51,860 字符是永遠的,始終是一個單字節, 644 00:53:51,860 --> 00:53:57,540 指針的算術運算相當於定期算術當你在處理字符串。 645 00:53:57,540 --> 00:54:08,790 遠的不說的char * s =“你好”。 646 00:54:08,790 --> 00:54:11,430 因此,我們有一個內存塊中。 647 00:54:19,490 --> 00:54:22,380 它需要6個字節,因為你總是需要空終止符。 648 00:54:22,380 --> 00:54:28,620 和char * s將要指向這個數組的開始。 649 00:54:28,620 --> 00:54:32,830 因此,S點。 650 00:54:32,830 --> 00:54:36,710 現在,這基本上是任何數組是如何工作的, 651 00:54:36,710 --> 00:54:40,780 無論它是否是一個由malloc或無論是在堆棧上的回報。 652 00:54:40,780 --> 00:54:47,110 任何數組基本上是一個指針陣列的開始, 653 00:54:47,110 --> 00:54:53,640 那麼任何數組操作,任何索引,只是進入該數組一定的偏移。 654 00:54:53,640 --> 00:55:05,360 >> 所以當我說類似[3]這是怎麼回事s和計數3個字符中。 655 00:55:05,360 --> 00:55:12,490 因此s [3],我們有0,1,2,3,因此s [3]將參考本升。 656 00:55:12,490 --> 00:55:20,460 [學生]我們可以達到相同的值,執行s + 3,然後括號明星的嗎? 657 00:55:20,460 --> 00:55:22,570 是。 658 00:55:22,570 --> 00:55:26,010 這是相當於*(+ 3); 659 00:55:26,010 --> 00:55:31,240 ,這是永遠總是相等的,無論你做什麼。 660 00:55:31,240 --> 00:55:34,070 你永遠需要使用括號的語法。 661 00:55:34,070 --> 00:55:37,770 您可以隨時使用*(+ 3)語法。 662 00:55:37,770 --> 00:55:40,180 人們往往喜歡括號語法。 663 00:55:40,180 --> 00:55:43,860 [學生]因此,所有的數組實際上是指針。 664 00:55:43,860 --> 00:55:53,630 有輕微的區別,當我說×[4] >> [學生]這是否創建內存嗎? 665 00:55:53,630 --> 00:56:03,320 鮑登,是要創建4個的整數堆棧上的,所以16個字節的整體。 666 00:56:03,320 --> 00:56:05,700 它會在棧上創建16個字節。 667 00:56:05,700 --> 00:56:09,190 x未存儲在任何位置。 668 00:56:09,190 --> 00:56:13,420 這僅僅是一個符號參照開始的事情。 669 00:56:13,420 --> 00:56:17,680 因為你聲明的數組裡面的這個函數, 670 00:56:17,680 --> 00:56:22,340 編譯器會做的僅僅是變量x的所有實例都替換 671 00:56:22,340 --> 00:56:26,400 與它發生在選擇把16個字節。 672 00:56:26,400 --> 00:56:30,040 它不能這樣做,因為用char * s是一個實際的指針。 673 00:56:30,040 --> 00:56:32,380 它是免費的,再點其他的事情。 674 00:56:32,380 --> 00:56:36,140 x是一個常數。你不能擁有它指向不同的數組。 >> [學生]好吧。 675 00:56:36,140 --> 00:56:43,420 但這樣的想法,這個索引是一樣的,不管它是否是一個傳統的陣列 676 00:56:43,420 --> 00:56:48,230 或者如果它是一個指針的東西,或者如果它是一個到malloced數組的指針。 677 00:56:48,230 --> 00:56:59,770 而事實上,它是相等的,這是同樣的事情。 678 00:56:59,770 --> 00:57:05,440 它實際上只是翻譯的括號裡面是什麼,什麼是左括號內, 679 00:57:05,440 --> 00:57:07,970 把它們加在一起,並取消引用。 680 00:57:07,970 --> 00:57:14,710 因此,這是一樣有效(+)或S [3]。 681 00:57:16,210 --> 00:57:22,090 [學生]你能有2維數組的指針指向? 682 00:57:22,090 --> 00:57:27,380 >> 它的難度。傳統上,沒有。 683 00:57:27,380 --> 00:57:34,720 一個二維數組是一維數組使用一些方便的語法 684 00:57:34,720 --> 00:57:54,110 因為當我說詮釋x [3] [3],這真的只是1陣列的9個值。 685 00:57:55,500 --> 00:58:03,000 因此,當I指數,編譯器知道我的意思。 686 00:58:03,000 --> 00:58:13,090 如果我說,X [1] [2],它知道我要到第二行,所以​​將跳過第3, 687 00:58:13,090 --> 00:58:17,460 那麼想的第二件事,所以它會得到這一個。 688 00:58:17,460 --> 00:58:20,480 但它仍然只是一個一維數組。 689 00:58:20,480 --> 00:58:23,660 所以,如果我想指定一個指向該數組的指針, 690 00:58:23,660 --> 00:58:29,770 我想說的* p = X; 691 00:58:29,770 --> 00:58:33,220 x的類型是 - 692 00:58:33,220 --> 00:58:38,280 粗略的說這是x的類型,因為它只是一個符號,它不是一個實際的變量, 693 00:58:38,280 --> 00:58:40,140 但它僅僅是一個int *。 694 00:58:40,140 --> 00:58:44,840 x是剛剛開始的指針。 >> [學生]好吧。 695 00:58:44,840 --> 00:58:52,560 因此,我將無法訪問[1] [2]。 696 00:58:52,560 --> 00:58:58,370 我認為是有特殊的語法來聲明一個指針, 697 00:58:58,370 --> 00:59:12,480 什麼可笑的,如int(* p [ - 這是絕對荒謬的。我什至不知道。 698 00:59:12,480 --> 00:59:17,090 但有語法聲明函數指針像括號和活動。 699 00:59:17,090 --> 00:59:22,960 它甚至有可能不會讓你這樣做。 700 00:59:22,960 --> 00:59:26,640 我回頭看的​​東西,將真相告訴我。 701 00:59:26,640 --> 00:59:34,160 我會尋找它以後,如果有一個語法點。但你永遠不會看到它。 702 00:59:34,160 --> 00:59:39,670 即使語法是過時的,如果你使用它,人們會感到困惑。 703 00:59:39,670 --> 00:59:43,540 多維數組是非常罕見的,因為它是。 704 00:59:43,540 --> 00:59:44,630 你幾乎 - 705 00:59:44,630 --> 00:59:48,490 好吧,如果你在做矩陣的事情,它不會是罕見的, 706 00:59:48,490 --> 00:59:56,730 但在C中,你很少會被使用多維數組。 707 00:59:57,630 --> 01:00:00,470 是啊。 >> [學生]:比方說,你有一個很長的陣列。 708 01:00:00,470 --> 01:00:03,900 >> 因此,在虛擬內存中,它似乎是所有連續, 709 01:00:03,900 --> 01:00:05,640 彼此旁邊的類似的元素, 710 01:00:05,640 --> 01:00:08,770 但在物理內存中,它有可能為被分裂了嗎? “是的。 711 01:00:08,770 --> 01:00:16,860 虛擬內存的工作原理是,它只是分離 - 712 01:00:19,220 --> 01:00:24,860 的分配單元是頁面,​​這往往是4千字節, 713 01:00:24,860 --> 01:00:29,680 所以說,當一個進程,哎,我想使用此內存, 714 01:00:29,680 --> 01:00:35,970 操作系統會分配它的那個小4千字節的內存塊。 715 01:00:35,970 --> 01:00:39,100 即使你只使用一個單字節的內存塊在整個不大, 716 01:00:39,100 --> 01:00:42,850 操作系統是要給它完整的4千字節。 717 01:00:42,850 --> 01:00:49,410 因此,這是什麼意思是,我可以 - 讓我們說這是我的籌碼。 718 01:00:49,410 --> 01:00:53,180 該協議棧可以被分開。我的堆棧可能是兆字節,兆字節。 719 01:00:53,180 --> 01:00:55,020 我的籌碼將是巨大的。 720 01:00:55,020 --> 01:01:00,220 但棧本身被分裂成單獨的頁面, 721 01:01:00,220 --> 01:01:09,010 如果我們看一下在這裡,讓我們說,這是我們的RAM, 722 01:01:09,010 --> 01:01:16,600 如果我有2 GB的RAM,這是我的第零個字節的RAM地址為0,如實際, 723 01:01:16,600 --> 01:01:22,210 這是2 GB一路下跌。 724 01:01:22,210 --> 01:01:27,230 因此,該頁面可能對應到這個塊在這裡。 725 01:01:27,230 --> 01:01:29,400 在這裡,該頁面可能與此塊。 726 01:01:29,400 --> 01:01:31,560 這可能對應於這一個在這裡。 727 01:01:31,560 --> 01:01:35,540 因此,操作系統是免費分配物理內存 728 01:01:35,540 --> 01:01:39,320 任何單獨的頁面隨意。 729 01:01:39,320 --> 01:01:46,180 這意味著,如果這條邊界發生跨越陣列, 730 01:01:46,180 --> 01:01:50,070 發生一個數組左和右以此順序一個頁面 731 01:01:50,070 --> 01:01:54,460 那麼該數組將被分割在物理內存中。 732 01:01:54,460 --> 01:01:59,280 然後當你退出程序,當進程結束時, 733 01:01:59,280 --> 01:02:05,690 這些映射將被刪除,然後它是免費的,使用這些小的塊,其他的事情。 734 01:02:14,730 --> 01:02:17,410 還有問題嗎? 735 01:02:17,410 --> 01:02:19,960 [學生]指針的算術運算。 >>哦,是的。 736 01:02:19,960 --> 01:02:28,410 字符串比較容易,但看著像int類型, 737 01:02:28,410 --> 01:02:35,000 使之恢復為int x [4]; 738 01:02:35,000 --> 01:02:41,810 這是否是一個數組無論是到malloced 4個整數的數組指針, 739 01:02:41,810 --> 01:02:47,060 它會以同樣的方式來對待。 740 01:02:50,590 --> 01:02:53,340 [學生]因此,數組的堆? 741 01:03:01,400 --> 01:03:05,270 [鮑登]數組是不是在堆上。 >> [學生]哦。 742 01:03:05,270 --> 01:03:08,320 >> [鮑登]這類型的磁盤陣列的傾向是在堆棧上 743 01:03:08,320 --> 01:03:12,220 除非你宣布它在, - 忽略全局變量。不要使用全局變量。 744 01:03:12,220 --> 01:03:16,280 裡面的功能,我說×[4]; 745 01:03:16,280 --> 01:03:22,520 這將在棧上創建一個整數4塊,這個數組。 746 01:03:22,520 --> 01:03:26,960 但是這個malloc(4 *表示sizeof(int));要去的堆。 747 01:03:26,960 --> 01:03:31,870 但在這一點上我可以在幾乎相同的方式,使用x和p 748 01:03:31,870 --> 01:03:36,140 其他比我說的例外,前行約,您可以重新分配p。 749 01:03:36,140 --> 01:03:40,960 從技術上講,它們的尺寸有所不同,但是這是完全不相干的。 750 01:03:40,960 --> 01:03:43,310 你從來沒有真正使用它們的大小。 751 01:03:48,020 --> 01:03:56,810 我可以說的p P [3] = 2;或×[3] = 2; 752 01:03:56,810 --> 01:03:59,680 您可以使用完全相同的方式。 753 01:03:59,680 --> 01:04:01,570 因此,指針的算術運算 - 是的。 754 01:04:01,570 --> 01:04:07,390 [學生]你沒有做P *如果你有括號? 755 01:04:07,390 --> 01:04:11,720 括號內是一個隱式的間接引用。 “好了。 756 01:04:11,720 --> 01:04:20,200 其實,你在說什麼的你可以得到多維數組 757 01:04:20,200 --> 01:05:02,650 的指針,你可以做的是一樣的東西,比方說,** PP = malloc的(如sizeof(*)* 5); 758 01:05:02,650 --> 01:05:06,900 我就寫了這一切第一。 759 01:05:37,880 --> 01:05:41,020 我不想要的那一個。 760 01:05:41,020 --> 01:05:42,550 好吧。 761 01:05:42,550 --> 01:05:48,910 我在這裡做的是 - 這應該是PP [I]。 762 01:05:48,910 --> 01:05:53,680 因此,PP是一種指向指針的指針。 763 01:05:53,680 --> 01:06:02,420 您正在mallocing的PP指向的陣列5整數星。 764 01:06:02,420 --> 01:06:10,950 因此,在內存中,你必須在棧上頁 765 01:06:10,950 --> 01:06:20,150 要5塊,這些都是自己的指針指向一個數組。 766 01:06:20,150 --> 01:06:28,210 然後,當我的malloc在這裡,我的malloc的那些個人,每個指針 767 01:06:28,210 --> 01:06:32,080 應該指向一個單獨的4個字節的堆塊。 768 01:06:32,080 --> 01:06:35,870 因此,這點到4個字節。 769 01:06:37,940 --> 01:06:40,660 而這一次不同的4個字節。 770 01:06:40,660 --> 01:06:43,200 >> 所有的人都指向自己的4個字節。 771 01:06:43,200 --> 01:06:49,080 這給了我做多維的事情的一種方式。 772 01:06:49,080 --> 01:06:58,030 我能說的PP [3] [4],但現在這是不一樣的東西,多維數組 773 01:06:58,030 --> 01:07:05,390 因為多維數組它翻譯[3] [4]到一個單一的偏移量x數組。 774 01:07:05,390 --> 01:07:14,790 這解引用,P,訪問的第三個指標,然後解引用 775 01:07:14,790 --> 01:07:20,790 訪問 - 將是無效的 - 第二個索引。 776 01:07:24,770 --> 01:07:31,430 而當我們的int x [3] [4]前一個多維數組 777 01:07:31,430 --> 01:07:35,740 和雙支架時,它真的只有一個解引用, 778 01:07:35,740 --> 01:07:40,490 你一個單一的指針和一個偏移量, 779 01:07:40,490 --> 01:07:42,850 這是真正的2D引用。 780 01:07:42,850 --> 01:07:45,840 你跟著2個獨立的指針。 781 01:07:45,840 --> 01:07:50,420 因此,這在技術上也是可以讓你有多維數組 782 01:07:50,420 --> 01:07:53,550 其中每個單獨的陣列是不同的尺寸。 783 01:07:53,550 --> 01:07:58,000 因此,我認為鋸齒狀的多維數組是它叫什麼 784 01:07:58,000 --> 01:08:01,870 因為真正的第一件事可能指向的東西,有10個元素, 785 01:08:01,870 --> 01:08:05,540 第二件事情可能指向的東西,有100個元素。 786 01:08:05,540 --> 01:08:10,790 [學生]:是否有任何限制數的指針,你可以有 787 01:08:10,790 --> 01:08:14,290 指向其他指針? >>序號 788 01:08:14,290 --> 01:08:17,010 您可以有int ***** p。 789 01:08:18,050 --> 01:08:23,760 返回指針的算術運算 - >> [學生]哦。 >>呀。 790 01:08:23,760 --> 01:08:35,649 [學生]如果我有int ** p,然後我做了一個間接引用和我說,P *是等於這個值, 791 01:08:35,649 --> 01:08:39,560 它只會做1級提領嗎? “是的。 792 01:08:39,560 --> 01:08:43,340 所以,如果我要訪問的最後一個指針指向的東西 - 793 01:08:43,340 --> 01:08:46,210 然後,你*** P。 “好了。 794 01:08:46,210 --> 01:08:54,080 因此,這是p點到1塊到另一個塊,點,點到另一個塊。 795 01:08:54,080 --> 01:09:02,010 然後,如果你做* P =別的東西,那麼你正在改變這 796 01:09:02,010 --> 01:09:13,640 到現在指向一個不同的塊。 “好了。 797 01:09:13,640 --> 01:09:17,649 >> [鮑登],如果這些malloced,那麼你現在已經洩漏的內存 798 01:09:17,649 --> 01:09:20,430 除非你碰巧有這些不同的參考 799 01:09:20,430 --> 01:09:25,270 因為你不能得到那些的,你只是扔掉了。 800 01:09:25,270 --> 01:09:29,550 指針的算術運算。 801 01:09:29,550 --> 01:09:36,310 ×[4];要分配4個整數的數組 802 01:09:36,310 --> 01:09:40,670 其中x是要指向的數組的開始。 803 01:09:40,670 --> 01:09:50,420 所以,當我說的東西,比如x [1],我想它的意思去的第二個整數的數組, 804 01:09:50,420 --> 01:09:53,319 這將是這一個。 805 01:09:53,319 --> 01:10:04,190 但實際上,這是4個字節到數組中,因為這個整數佔用4個字節。 806 01:10:04,190 --> 01:10:08,470 因此,偏移量為1的真正含義偏移量為1 807 01:10:08,470 --> 01:10:12,030 倍的大小的任何類型的數組。 808 01:10:12,030 --> 01:10:17,170 這是一個整數數組,所以它知道做1次為int的大小,當它想抵消。 809 01:10:17,170 --> 01:10:25,260 其他的語法。請記住,這是相當於*(X + 1); 810 01:10:25,260 --> 01:10:35,250 當我說指針+ 1,返回的地址指針存儲 811 01:10:35,250 --> 01:10:40,360 加1倍的大小的指針的類型。 812 01:10:40,360 --> 01:10:59,510 因此,如果x = ox100,那麼x + 1 = ox104。 813 01:10:59,510 --> 01:11:19,750 你可以濫用這一點,說什麼像char * C =(CHAR *)X; 814 01:11:19,750 --> 01:11:23,050 現在c將是相同的地址作為x。 815 01:11:23,050 --> 01:11:26,040 c是將是等於ox100, 816 01:11:26,040 --> 01:11:31,490 但C + 1將是等於ox101的 817 01:11:31,490 --> 01:11:38,030 因為指針的算術運算取決於您要添加的類型的指針。 818 01:11:38,030 --> 01:11:45,390 所以C + 1,它著眼於C,它是一個字符指針,所以它要增加1倍大小的char, 819 01:11:45,390 --> 01:11:48,110 總是為1,所以你得到101, 820 01:11:48,110 --> 01:11:54,890 而如果我這樣做,X + 1 x,它也仍然是100將是104。 821 01:11:56,660 --> 01:12:06,340 [學生]:你可以使用C + +,以推進指針加1呢? 822 01:12:06,340 --> 01:12:09,810 是的,你可以。 823 01:12:09,810 --> 01:12:16,180 你不能這樣做,因為x與x只是一個符號,它是一個常量,你不能改變x。 824 01:12:16,180 --> 01:12:22,610 >> 但C恰好是一個指針,所以C + +是完全有效的,這將增加1。 825 01:12:22,610 --> 01:12:32,440 如果c是一個int *,然後是C + + 104。 826 01:12:32,440 --> 01:12:41,250 + +指針的算術運算正如C +會做指針算術。 827 01:12:43,000 --> 01:12:48,870 其實,這是怎麼了很多事情,比如合併排序 - 828 01:12:49,670 --> 01:12:55,710 創建副本的事情,而不是相反,你可以通過 - 829 01:12:55,710 --> 01:13:02,400 就像如果我想通過這半年的數組 - 讓我們清除一些。 830 01:13:04,770 --> 01:13:10,520 比方說,我想通過這一邊的數組的功能。 831 01:13:10,520 --> 01:13:12,700 ,我會通過該功能是什麼? 832 01:13:12,700 --> 01:13:17,050 如果我通過X,我通過這個地址。 833 01:13:17,050 --> 01:13:23,780 不過,我想通過這個特定的地址。所以,我應該通過什麼嗎? 834 01:13:23,780 --> 01:13:26,590 [學生]指針+ 2? 835 01:13:26,590 --> 01:13:29,350 [鮑登]所以x + 2。是。 836 01:13:29,350 --> 01:13:31,620 這將是這個地址。 837 01:13:31,620 --> 01:13:42,810 您還可以經常看到它為x [2],然後在該地址。 838 01:13:42,810 --> 01:13:47,850 所以,你需要採取的地址,因為它的支架是一個隱式的間接引用。 839 01:13:47,850 --> 01:13:53,250 X [2]指的是在此框中的值,然後你要的那個盒子的地址, 840 01:13:53,250 --> 01:13:56,850 所以你說&X [2]。 841 01:13:56,850 --> 01:14:02,880 所以,如何在合併排序的東西,你想通過一半的東西的清單 842 01:14:02,880 --> 01:14:08,790 你真的只是通過X [2],而現在的遞歸調用, 843 01:14:08,790 --> 01:14:12,510 從那裡開始我的新數組。 844 01:14:12,510 --> 01:14:15,130 最後一分鐘的問題。 845 01:14:15,130 --> 01:14:20,050 [學生]如果我們不把一個符號或一個 - 那是什麼叫什麼名字? >>明星嗎? 846 01:14:20,050 --> 01:14:23,200 [學生]星。 “從技術上講,反引用運算符,但 - >> [學生]:取消引用。 847 01:14:23,200 --> 01:14:29,310 >> 如果我們不把一個明星或一個符號,會發生什麼,如果我只是說y = x和x是一個指針? 848 01:14:29,310 --> 01:14:34,620 y的類型是什麼? >> [學生]我只想說,它的指針。 849 01:14:34,620 --> 01:14:38,270 所以,如果你只是說y = x的,現在的X和Y點了同樣的事情。 >> [學生]點了同樣的事情。 850 01:14:38,270 --> 01:14:45,180 如果X是一個int的指針嗎? >>,它會抱怨,因為你不能分配的指針。 851 01:14:45,180 --> 01:14:46,540 [學生]好的。 852 01:14:46,540 --> 01:14:51,860 請記住,指針,即使我們把它們畫為箭頭, 853 01:14:51,860 --> 01:15:02,010 真的,他們店 - * X - 實際上所有的x存儲類似ox100, 854 01:15:02,010 --> 01:15:06,490 我們正好代表指向存儲在100塊。 855 01:15:06,490 --> 01:15:19,660 所以當我說詮釋* Y = X,我只是複製ox100到Y, 856 01:15:19,660 --> 01:15:24,630 我們只是要表示為y,也指向ox100。 857 01:15:24,630 --> 01:15:39,810 如果我說我=(int)的X,然後我將存儲任何的價值ox100是 858 01:15:39,810 --> 01:15:45,100 在它裡面,但現在它會被解釋為一個整數,而不是一個指針。 859 01:15:45,100 --> 01:15:49,310 但是,你需要的演員,否則,它會抱怨。 860 01:15:49,310 --> 01:15:53,300 [學生]:所以你的意思是投 - 861 01:15:53,300 --> 01:16:00,290 它是將要鑄造的y值的x或鑄造詮釋的? 862 01:16:00,290 --> 01:16:03,700 [鮑登什麼? 863 01:16:03,700 --> 01:16:07,690 [學生]好的。在這些括號將是一個x或AY? 864 01:16:07,690 --> 01:16:11,500 >> 鮑登]。 x和y是等效的。 >> [學生]好吧。 865 01:16:11,500 --> 01:16:14,390 因為他們是兩個指針。 >>呀。 866 01:16:14,390 --> 01:16:21,050 [學生]因此,它會存儲100的十六進制整數形式呢? >> [鮑登]是啊。 867 01:16:21,050 --> 01:16:23,620 但不是無論它指向的值。 868 01:16:23,620 --> 01:16:29,940 鮑登]是啊。 >> [學生]因此,只要整數形式的地址。好吧。 869 01:16:29,940 --> 01:16:34,720 [鮑登]如果你想一些奇怪的原因, 870 01:16:34,720 --> 01:16:38,900 你可以只處理指針和不會處理整數 871 01:16:38,900 --> 01:16:49,240 只是,如int * x = 0處。 872 01:16:49,240 --> 01:16:53,000 然後,你會得到真正的困惑,指針的算術運算後開始發生。 873 01:16:53,000 --> 01:16:56,570 因此,它們存儲的數字是毫無意義的。 874 01:16:56,570 --> 01:16:58,940 它只是你怎麼收場解釋它們。 875 01:16:58,940 --> 01:17:02,920 所以我複製ox100從int *為int, 876 01:17:02,920 --> 01:17:07,790 我是自由分配 - 你們可能會被罵不投 - 877 01:17:07,790 --> 01:17:18,160 我可以自由分配(*)ox1234到這個任意整數*類似。 878 01:17:18,160 --> 01:17:25,480 所以ox123是一樣有效的內存地址&Y。 879 01:17:25,480 --> 01:17:32,060 &Y發生,這幾乎是ox123返回的東西。 880 01:17:32,060 --> 01:17:35,430 [學生]:這是一個非常酷的方式,從十六進制到十進制的形式, 881 01:17:35,430 --> 01:17:39,230 一樣,如果你​​有一個指針,將其轉換成一個int類型的嗎? 882 01:17:39,230 --> 01:17:44,860 鮑登]你真的可以使用類似printf打印。 883 01:17:44,860 --> 01:17:50,300 比方說,我有int y = 100。 884 01:17:50,300 --> 01:18:02,700 因此我們知道printf(“%d個\ n - 你應該已經知道 - 打印為一個整數,%X。 885 01:18:02,700 --> 01:18:05,190 我們只需要打印十六進制的。 886 01:18:05,190 --> 01:18:10,760 因此,一個指針存儲為十六進制, 887 01:18:10,760 --> 01:18:12,960 和沒有存儲為十進制,整數。 888 01:18:12,960 --> 01:18:14,700 一切都以二進制形式存儲。 889 01:18:14,700 --> 01:18:17,950 只是我們往往顯示為十六進制的指針 890 01:18:17,950 --> 01:18:23,260 因為我們認為在這4個字節的塊的東西, 891 01:18:23,260 --> 01:18:25,390 和內存地址往往是熟悉的。 892 01:18:25,390 --> 01:18:28,890 我們是一樣的,如果它開始與BF,那麼它正好是在棧上。 893 01:18:28,890 --> 01:18:35,560 因此,這只是我們的解釋為十六進制的指針。 894 01:18:35,560 --> 01:18:39,200 好吧。最後還有什麼問題嗎? 895 01:18:39,200 --> 01:18:41,700 >> 我會在這裡了一下後,如果你還有什麼。 896 01:18:41,700 --> 01:18:46,070 這是該結束。 897 01:18:46,070 --> 01:18:48,360 >> [學生]耶! [掌聲] 898 01:18:51,440 --> 01:18:53,000 >> [CS50.TV]