[Powered by Google Translate] [評論] [測驗] [亞力克西斯·羅斯,湯米MacWilliam,盧卡斯·弗雷塔斯,王陽樂] [哈佛大學] 這是CS50。[CS50.TV] 嘿,大家好。 歡迎測驗0,這是本週三舉行的審查會議。 我們要做的今晚,我和其他3個轉錄因子, 和我們一起去了什麼,我們做的過程中,到目前為止,通過審查。 它不會是100%全面,但它應該給你一個更好的主意 你已經有什麼,你仍然需要研究(星期三)前。 而且感覺我們一起去提高你的手的問題, 但請記住,我們還會有一點點的時間結束時, 如果我們通過幾分鐘業餘做一般的問題, 所以記住這一點,所以我們要開始在0週開始。 [問答共0] [第0] [亞力克西斯·羅斯]但是,在我們這樣做,它可以讓談 物流的測驗。 [物流] [測驗發生在10月10日(星期三)代替演講] (見的詳細信息http://cdn.cs50.net/2012/fall/quizzes/0/about0.pdf)]這是10月10日(星期三)。 這是本週三,如果你去到這個URL, 這也是從CS50.net的訪問的鏈接 去哪裡的基礎上,你可以看到信息 您的姓氏或所屬學校以及 它講述了什麼測驗將涵蓋和類型的問題,你會得到。 請記住,你也有機會審查測驗部分, 所以你的的TFS應超過一些實際問題, 這是另一個很好的機會看到你仍然需要學習測驗。 讓我們從一開始位'N'字節。 請記住一個位是0或1, 和一個字節是8的那些位的集合。 讓我們來看看位在此集合在這裡。 我們應該能夠找出有多少位。 如果我們指望有8人,8個0或1個單位。 而且,由於有8位,這是1個字節, 讓我們把它轉換為十六進制。 十六進制的基數為16,這是很容易轉換 一個二進制數,這是這是一個十六進制數。 我們要做的就是我們期待在4組, 我們將其轉換為相應的十六進制數字。 我們從最右邊的4組,所以0011。 這將是一個1和一個2,這樣在一起,使得3。 然後讓我們來看看其他4塊。 1101年。這將是一個1,一個4,一個8。 在一起,將是13,這使得D。 我們會記住,在十六進制中,我們不只是從0到9。 我們去到F 0,所以在9,10對應到A, 11到B,等,其中F是15。 其中,圖13是一個D, 所以將其轉換為十進制,我們所做的一切是我們實際上 對待每一個位置為2的冪。 這是一個1,一個2,零4秒,零8秒,一個16,等等, 這是一個有點難以計算在你的腦袋,但如果我們去到下一張幻燈片 我們可以看到這個問題的答案。 從本質上講,我們要跨越右到左, ,我們將每個數字所對應的功率為2。 請記住,十六進制表示,這些數字以0x開始 因此,我們不要混淆一個十進制數。 繼續,這是一個ASCII表, 我們使用ASCII是從字符映射到的數值。 請記住,在密碼學的pset,我們廣泛使用的ASCII表 為了使用密碼學的各種方法, 凱撒和維瓊內爾的密碼,不同的字母轉換 在一個字符串中,根據由用戶給定的關鍵。 讓我們來看看在一點點的ASCII數學。 尋找在“P”以字符的形式,將是Q,+ 1, 記得,'5'≠5。 我們究竟如何轉換之間的2種形式? 它實際上不是太硬。 為了讓我們減去'0' 因為有5個地方之間的'0'和'5'。 為了走另外一條路,我們只是添加了0, 所以這有點像普通的算術。 請記住,有些事情時,周圍的引號字符 ,從而對應於ASCII碼表中的一個值。 移動到更一般的計算機科學課題。 我們了解到的算法是什麼,以及我們如何使用編程 實現算法。 算法的一些例子是很簡單的東西如 檢查是否一個數是偶數還是奇數。 為此,還記得我們國防部的數字2,檢查如果結果是0。 如果是這樣,它甚至。如果沒有,這是奇怪的。 這是一個非常基本的算法的一個例子。 一點點的一個更棘手的是二進制搜索, 後來我們就去了審查會議。 編程是長遠來說,我們使用的算法 和將其轉換為代碼的計算機可讀取。 2實例編程是零起步, 這是我們在0週。 即使我們沒有實際鍵入的代碼,它是一種實施 算法,這是印刷數字1到10, 在這裡,我們做同樣的在C編程語言。 這些功能相同,只是在不同的語言或語法編寫的。 然後,我們了解的布爾表達式, 和一個布爾值,或真或假的, 這裡常常布爾表達式 裡面去的條件下,所以如果(x≤5), 好了,我們已經設置X = 5,所以這個條件會評估為true。 如果這是真的,無論代碼是下面的條件 要由計算機進行評價,使字符串要打印 到標準輸出,和工作條件 是指無論是在括號內的if語句。 記住所有的運營商。 記住它的&&和| |,當我們試圖結合2個或更多的條件, ==不檢查,是否事情都是平等的。 請記住,=是賦值,而==是一個布爾運算符。 ≤,≥,然後在最後2是不言自明的。 這裡的布爾邏輯的一般審查。 和布爾表達式在循環中也是很重要的, 現在我們就去了。 我們學會了3種類型的循環迄今為止,CS50,同時,做,而。 重要的是要知道,對於大多數用途 我們實際上可以使用任何類型的循環 有一定的目的或共同的模式 在編程中特別呼籲這些循環 ,使它成為最有效的還是在這樣優雅的代碼。 讓我們在這些循環往往是最常見的。 在循環中,我們已經知道我們要重複多少次。 這就是我們提出的條件中。 對於,= 0,<10,例如。 我們已經知道,我們想要做的東西10倍。 現在,一個while循環中,我們一般不必然 我們要知道有多少次的循環運行。 但我們知道某種條件下,我們希望它是 始終是真實的,永遠是虛假的。 例如,雖然被設定。 比方說,這是一個布爾變量。 雖然這是真的,我們要評估的代碼, 有那麼一點點更多的可擴展性,多一點點普遍比一個for循環, 但任何的for循環也可以轉換為一個while循環。 最後,執行while循環,這可能是最棘手的理解, 經常使用,當我們要評估的代碼 之前我們第一次檢查的條件。 一個常見的用例的do while循環 當你想獲取用戶輸入的,你知道你要問的用戶 輸入至少一次,但如果他們不給你良好的輸入 你要不斷地問他們,直到他們給你良好的輸入。 這是最常見的使用whil​​e循環, 讓我們來看看在這些循環的實際結構。 他們通常總是按照這些模式。 在fo​​r循環內,你有3個組成部分: 初始化,通常的東西,如int i = 0,其中i是計數器, 條件,在這裡我們想說的運行循環,只要這種情況下仍持有, 像我<10,然後在最後,更新,這是我們增加 在循環中的每個點的計數器變量。 看到有一個共同的東西就是我+ +, 這意味著每次遞增i。 你也可以做類似的東西我+ = 2, 這意味著加2我每次去通過循環。 然後這樣做只是指實際運行循環的一部分的任何代碼。 一個while循環,這個時候,我們其實有外循環的初始化, 例如,讓我們說,我們正在試圖做的,因為我剛才所描述的相同類型的循環。 我們會說INT I = 0,在循環開始前。 然後,我們可以這樣說,而我做到這一點, 所以相同的代碼塊之前, 而這一次的更新部分的代碼,例如,我+ +, 其實裡面的循環。 最後,對於一個這樣做的同時,它類似於while循環, 但我們必須記住,代碼將評估一次 前檢查條件,所以它使很多更有意義 如果你看它在從上到下的順序。 在while循環中的代碼進行評估之前,你甚至看while條件, 而一個while循環,它會首先檢查。 報表和變量。 當我們要創建一個新的變量,我們首先要對其進行初始化。 例如,int酒吧初始化變量的酒吧, 但它並沒有給它一個值,所以現在欄的值是什麼? 我們不知道。 這可能是以前存儲在內存中有一些垃圾的價值, 我們不想使用該變量 直到我們真正給它一個值, 因此,我們在這裡聲明。 然後,我們把它初始化為42。 現在,當然,我們知道這是可以做到一條線,酒吧= 42。 但僅僅是明確的多個步驟,是怎麼回事, 聲明和初始化分別在這裡發生。 它發生在一個步驟,下一個,巴茲=酒吧+ 1, 這以下聲明,遞增的的巴茲,所以在這個代碼塊的結束 如果我們要打印的價值巴茲這將是44 因為我們聲明並把它初始化為1>酒吧, 然後我們增加一次+ +。 我們去了這個漂亮的簡要,但它有一個大致的 了解線程和事件是什麼。 我們主要是在刮, 所以你可以把多個線程的代碼序列 在同一時間運行。 實際上,它可能是運行在相同的時間, 但有點抽象,我們可以認為它以這種方式。 從無到有,例如,我們有多個精靈。 它可以在同一時間執行不同的代碼。 人們可以一邊走一邊說的東西 在一個不同的,在屏幕的一部分。 事件是另一種方式分離出來的邏輯 不同元素之間,你的代碼, 在Scratch中,我們能夠模擬活動,利用廣播, 這實際上是當我收到,而不是當我聽到, 但實質上,它是一個傳遞信息的方法 從一個精靈到另一個地方。 例如,您可能要傳輸遊戲, 另一個精靈,當比賽結束, 它以某種方式回應。 這是一個重要的編程模型,以了解。 只是去超過基本的週0,我們已經討論了這麼遠, 讓我們來看看這個簡單的C程序。 文字可能是從這裡有點小,但我會去非常快的。 我們包括2頭文件的頂部,cs50.h的和stdio.h中。 然後,我們定義一個常數,稱為限制為100。 然後,我們執行我們的主要功能。 由於我們沒有使用命令行參數,在這裡,我們需要把作廢 作為主要的參數。 我們看到上述主要的詮釋。這是返回類型,因此返回0,在底部。 我們使用的是CS50庫函數得到詮釋 要求用戶輸入,我們將其存儲在這個變量x, 因此,我們宣布上述X,和我們對它進行初始化,其中x =調用getInt。 然後我們檢查,看是否用戶給了我們很好的輸入。 如果我們要≥LIMIT返回一個錯誤代碼1和打印錯誤消息。 最後,如果用戶已經給了我們很好的輸入 我們要去的平方數,並打印出這個結果。 只是為了確保這些全部命中回家 你可以看到這裡的代碼的不同部分的標籤。 我提到不變,頭文件。 哦,詮釋x。請一定要記住,這是一個局部變量。 對比從一個全局變量,我們將討論 一點點後,在審查會議, 和我們調用庫函數printf, 因此,如果我們不包括stdio.h頭文件 我們將無法調用printf。 我相信,進行了切斷箭頭指向的%d, 這是在printf的格式化字符串。 它說一個數字,第%d打印出這個變量。 這是它第0週。 現在,盧卡斯繼續下去。 嘿,伙計們。我的名字是盧卡斯。 我是一個大二學生在校園裡,奧美最好的房子, 我要談一點,約1週和2.1週。 [1週和2.1週] [盧卡斯·弗雷塔斯] Lexi的說,當我們開始從頭開始你的代碼翻譯到C ,我們注意到的事情之一是,你不能只是 寫你的代碼,並運行它使用了一個綠色的標誌。 其實,你必須使用一些步驟,以使你的C程序 成為一個可執行文件。 基本上你做了什麼時,你所編寫的程序是, 你翻譯成一種語言,編譯器能夠理解你的想法, 所以,當你正在編寫一個程序,在C 你在做什麼,實際上是寫東西,你的編譯器是怎麼回事了解, 那麼編譯器會翻譯的代碼 到的東西,你的電腦就會明白。 的事情,您的計算機實際上是非常愚蠢的。 你的電腦只能理解“0”和“1, 所以實際上在第一台計算機的人通常編程 用“0”和“1秒,但現在不是了,感謝上帝。 我們沒有記憶0和1的序列 for循環或一個while循環等。 這就是為什麼我們有一個編譯器。 編譯器只是它基本上是翻譯的C代碼, 在我們的例子中,您的計算機就會明白的語言, 這是目標代碼,我們正在使用的編譯器, 被稱為鐺,所以這實際上是鐺的符號。 當你有你的程序,你必須做兩件事情。 首先,你必須編譯程序,然後你運行你的程序。 編譯你的程序,你有很多的選擇這樣做。 第一個是做鐺program.c 在該程序是你的程序的名稱。 在這種情況下,你可以看到,他們只是說“嘿,編譯我的程序。” 你不是說:“我想我的程序”或其他任何名稱。 第二個選項是給你的程序的名稱。 你可以說鐺-O和你想要的名稱 可執行文件被命名為,然後program.c。 而且你還可以做程序,以及如何在第2例 我把C,我只有在第三個節目嗎? 是啊,你不應該付諸表決。C時使用。 否則,編譯器實際上是要罵你的。 而且,我不知道,如果你們還記得, 但很多時候,我們也使用lcs50或-LM。 這就是所謂的鏈接。 它只是告訴編譯器,你將使用這些庫就在那裡, 所以如果你想使用cs50.h,你必須輸入 鐺program.c,lcs50。 如果你不這樣做,編譯器不會知道 你使用了這些功能cs50.h. 當你要運行你的程序,你有2個選擇。 如果你沒有鐺program.c你沒有給你的程序的名稱。 您必須運行使用。/ a.out的。 a.out是一個標準的名稱,鐺使您的程序,如果你不給它一個名字。 否則,你要做的/計劃,如果你在你的程序出了名的, ,如果你還做程序的名稱,程序會得到 已經進行編程的C文件相同的名稱。 然後,我們談到數據類型和數據。 數據類型基本上是同樣的事情,他們使用的小盒子 存儲值,所以數據類型實際上是一樣的小寵物。 他們有各種規模和類型。 我不知道這個比喻是有道理的。 數據的大小實際上是依賴於機器的體系架構。 ,我在這裡要告訴所有的數據大小 實際上是一個32位的機器,這是我們的設備的情況下, 但如果你是真正的編碼您的Mac或Windows 可能你有一個64位的機器, 所以請記住,數據的大小,我要在這裡展示 是為32位的機器上。 第一個,我們看到的是一個int, 這是非常簡單的。 您可以使用int來存儲一個整數。 我們也看到了字符,字符。 如果你想使用一個字母或一個小符號,你可能會使用一個char。 一個char 1個字節,這意味著8位,如樂喜說。 基本上我們有一個ASCII表有256個 可能的0和1的組合, 然後當你輸入一個字符,它的翻譯 的字符輸入你一個數字,你有ASCII表中,如樂喜說。 我們也有浮動,我們用它來存儲的十進制數。 例如,如果你想選擇3.14,你要使用浮動 或雙具有更高的精度。 一個浮動有4個字節。 雙有8個字節,所以,唯一的區別是精度。 我們也有很長的,用於整數, 你可以看到一個int和一個長為一個32位的機器具有相同的大小, 所以它不會真正有意義的使用在一個32位的機器。 但是,如果你使用的是Mac和64位的機器,實際上是一個長有大小8, 所以它確實依賴於體系結構。 對於32位的機器,它沒有意義的真正使用長。 再長長,另一方面,有8個字節, 所以這是非常好的,如果你想有一個較長的整數。 最後,我們有字符串,它實際上是一個char *, 這是一個指向字符。 這是很容易想到的字符串的長度將是 的字符數,你必須有, 但實際上本身的char * 有一個指針到一個字符,這是4個字節的大小。 一個char *的大小為4個字節。 這不要緊,如果你有一個小單詞或一個字母或任何東西。 這將是4個字節。 我們也學到了一點關於鑄造, 所以,你可以看到,如果你有,例如,一個程序,說: INT X = 3,然後輸出(“%d”,X / 2) 你們知道它會在屏幕上打印嗎? 有人嗎?>> [學生] 2。 1 >> 1,是的。 當你做3/2 1.5, 但由於我們使用的是一個整數,它會忽略的小數部分, 你將有1。 如果你不希望發生這種情況你可以做什麼,例如, 聲明持股量Y = X。 則X為3現在要在y是3.000。 然後你就可以打印的Y / 2。 其實,我應該​​有一個2。那邊。 它會做3.00/2.00, 你會得到1.5。 我們有這個.2 f只要求2的小數部分的十進制單位。 如果你有0.3 f實際上1.500。 如果它是2的為1.50。 我們也有這樣的情況在這裡。 如果你這樣做持股量X = 3.14,那麼你的printf x 你將得到3.14。 如果你做x = x的整數, 這意味著把X作為一個int,則在打印x現在 你將不得不3.00。 這是否有意義嗎? 因為你第一次治療x為整數,所以你忽略的小數部分, 然後你印刷。 最後,你也可以做到這一點, X = 65,那麼你聲明一個char C = X, 然後,如果你打印的C,你實際上是在將要得到的 A,所以基本上你在這裡做什麼 的整數轉換成字符, 就像ASCII表。 我們還談到數學運算符。 他們中的大多數都非常簡單,+, - ,*,/, 我們也談到關於MOD,這是剩下的一個部門,2個數字。 如果你有10%3,例如, 這意味著10除以3,其餘的是什麼? 這將是1,所以它實際上是非常有用的節目了很多。 對於維瓊內爾和凱撒,我敢肯定,如果大家都使用MOD。 關於數學運算符時,必須非常小心,將*和/。 例如,如果你這樣做(3/2)* 2,你會得到嗎? [學生] 2。 呀,2,因為二分之三是要為1.5, 但因為你是做2個整數之間的操作 其實你只是要考慮, 1 * 2,然後將是2,所以要非常非常小心 做數學運算時,整數,因為 你可能會得到2 = 3,在這種情況下。 也非常小心的優先級。 通常,你應該使用括號,要確保你知道你在做什麼。 一些有用的快捷鍵,當然,一個是我+ +或i + = 1 或使用+ =。 這是同樣的事情,做I = I + 1。 你也可以做我 - 我 - = 1, 這是同樣的事情I = -1, 東西你們使用了很多在for循環中,至少。 此外,*,* =,如果你這樣做了,例如,如果你使用, *的話說,I = I * 2 = 2是同樣的事情, 同樣的事情為師。 如果你做的I / = 2,I = I / 2,這是同樣的事情。 現在功能。 你們的經驗教訓,其功能是一個很好的策略,以節省代碼 而你編程,所以如果你要執行相同的任務 在代碼中一遍又一遍,可能您要使用的功能 只是讓你不必一遍又一遍的複製和粘貼代碼。 其實,主要是一個函數,當我告訴你一個函數的格式 你會看到,這是很明顯的。 我們還可以使用一些庫的功能, 例如,printf,進球,這是從CS50庫, 和其他功能,如TOUPPER。 所有這些功能實際上是實現其他圖書館, 當你把這些繫繩文件的開始你的程序 你說可以請你給我的代碼為這些功能 所以我沒有實現他們自己嗎? 你也可以編寫自己的函數,因此,當你開始編程 你會意識到,圖書館不具有的所有功能,你需要的。 例如,我們在過去的pset,寫,畫,加密和查找, 這是非常,非常重要的是要能寫功能 因為他們是有用的,我們使用他們所有的時間編程, 這樣可以節省大量的代碼。 函數的格式是這一個。 我們開始返回類型。返回類型是什麼? 這只是當你的函數會返回。 如果你有一個函數,例如,階乘, 是要計算的階乘的整數, 可能它會返回一個整數。 然後返回類型為int。 的printf實際上有一個返回類型為void 因為你不返回任何東西。 你只是在屏幕上打印的東西 和退出的功能之後。 然後,你的功能,你可以選擇的名稱。 您應該有點合理,如不選擇一個名稱,如某某 或像X2F。 嘗試彌補的名稱是有道理的。 例如,如果是因子,說階乘的。 如果要畫的東西,它是一個函數,將它命名畫。 然後我們有參數,也被稱為參數, 這是像你的函數所需要的資源, 從你的代碼來執行其任務。 如果你要計算一個數的階乘 可能你需要有一個數字來計算階乘。 的論點,你將有一個是這個數字本身。 那麼它會做一些事情,結束時,返回的值 除非它是一個void函數。 讓我們看一個例子。 如果我想編寫一個函數,總結一個整數數組中的所有數字, 首先,返回類型為int 因為我有一個整數數組。 然後我要的功能名稱,如sumArray, 然後是怎麼回事本身採取的陣列,為int NUMS, 然後長度的數組,所以我知道我有多少個數字來概括。 然後,我要初始化的變量稱為總和,例如,為0, 每次我看到一個數組中的元素,我把它添加到總和,所以我做了一個for循環。 就像樂喜說,你INT I = 0,I <長度和i + +。 數組中的每一個元素,我所做的次數總和+ = [I], 然後我又回到了一筆,所以這是很簡單的,這樣可以節省大量的代碼 如果您使用此功能了很多次。 然後,我們看看條件。 我們有,否則,如果和else if。 讓我們來看看者的區別是什麼。 看一看在這些代碼。它們之間的區別是什麼? 第一個基本的代碼要你告訴 一個數是否為+, - ,或0。 第一個說,如果> 0,則它的正面。 如果它是= 0,那麼它是0,並且,如果是<0,那麼它的負。 和其他人正在做的,如果,否則,如果,否則。 兩者之間的區別是,這一個實際上是要 如果> 0,<0或= 0三次, 所以,如果你有2號,例如,它會到這裡來,並說 如果(X> 0),它會說“是”,所以我打印陽性。 但是,即使我知道,這是> 0,它不會是0或<0 我仍然會做的是0,<0, 所以實際上,我要進去,如果我沒有到 因為我已經知道,它不是要滿足這些條件。 我可以使用,否則的話,else語句。 它基本上是說,如果X = 0我打印的積極。 如果不是的話,我也對此進行測試。 如果這是我要做到這一點。 基本上,如果我有X = 2,你會說 如果(X> 0),是的,打印本。 現在,我知道,這是> 0,它滿足了第一,如果 我什至要運行此代碼。 的代碼運行速度更快,實際上,3倍的速度,如果你用這個。 我們還了解到,和(或)。 我不會去,因為亞力克西斯已經談到他們。 這只是&&和| |運算符。 我唯一​​會說的時候要小心,有3個條件。 使用小括號,因為當你有一個條件,這是非常令人困惑的 和其他的一個或另一個。 使用括號只是為了確保你的條件是有意義的 因為在這種情況下,例如,你可以想像, 它可以是第一個條件和一個或另一個 或2中所組合的條件和 或第三人,所以,只是小心些而已。 最後,我們談到了開關。 交換機是非常有用的,當你有一個變量。 比方說,你有一個變量如:n 這些情況下,可以是0,1,或2,並且對於每個 你要去執行一項任務。 你可以說開關變量,它表明, 像值1的值,然後是我要做到這一點, 然後我打破,這意味著在任何其他情況下,我不會看 因為我們已經滿足這種情況下, 然後value2和等等,我也可以有一個默認的開關。 這意味著,如果它不能滿足的情況下,我 我做別的事情,但是這是可選的。 這一切對我來說。現在,讓我們湯米。 好吧,這將是第3週上下。 這些都是一些我們的主題將涵蓋,密碼,範圍,數組,等等。 一個快字上的密碼。我們不會敲定這個家。 我們這樣做的pset 2,但測驗,請確保您知道其中的差別 之間的凱撒密碼和維瓊內爾的密碼, 如何這些密碼的工作是什麼樣子的加密 和解密使用這些密碼的文本。 請記住,簡單的愷撒密碼的每個字符的旋轉相同的量, 確保你在字母表中的字母數模。 和維瓊內爾密碼,在另一方面,每個字符旋轉 不同的金額,而不是說 每一個字符3維瓊內爾旋轉,旋轉每個字符 由不同的金額,根據一些關鍵字 中的關鍵字,其中每個字母代表了一些不同的量 旋轉清晰的文本。 讓我們先說說變量的作用域。 有2種不同類型的變量。 我們有局部變量,而這些將要定義的 外的主要或以外的任何函數或塊, 和這些將在你的程序中的任何地方訪問。 如果你有一個函數,在該函數中是一個while循環 大的全局變量的訪問無處不在。 ,另一方面,是一個局部變量的作用域的地方,它被定義。 如果你有一個函數,例如,我們有這個函數g, 和內部的g是一個變量,在這裡稱為y, 這意味著,這是一個局部變量。 即使這個變量被稱為y 這個變量是所謂的Y這兩個函數 不知道對方的局部變量。 另一方面,在這裡,我們說X = 5, 這範圍以外的任何函數。 它的主要範圍以外的,所以這是一個全局變量。 這意味著,這些功能裡面,當我說X - 或x + + 我訪問相同的x,,這y和這家Y是不同的變量。 這是一個全局變量和局部變量之間的差異。 就設計而言,有時,它可能是一個更好的主意 保持局部變量時,你可能可以 因為有一堆全局變量可以得到真正的混亂。 如果你有一堆的功能,所有的修改同樣的事情, 你可能會忘記此功能,如果不慎修改, 這功能不知道這一點, 它變得相當混亂,因為你得到更多的代碼。 保持局部變量時,你可能可以 是剛剛好的設計。 陣列,請記住,僅僅是同一類型的元素的列表。 裡面的CI不能有一個列表,如1,2.0,你好。 我們不能做到這一點。 當在C我們聲明一個數組的所有元素必須是相同的類型。 在這裡,我有3個整數的數組。 在這裡,我有數組的長度,但如果我只是在此語法聲明 我指定所有的元素都是我並沒有從技術上需要這個3。 編譯器足夠聰明,找出數組應為多大。 現在,當我想獲取或設置一個數組的值 這是的語法來做到這一點。 這實際上修改的第二個元素的數組,因為記得, 編號從0開始,而不是1。 如果我想讀取該值,我可以這樣說X =數組[1]。 或者,如果我想設置該值,如我在這裡做什麼, 我可以說,數組[1] = 4。 這通過其索引訪問元素 或他們的位置,他們是在數組中, 從0開始,上市。 我們也可以有數組的數組 這就是所謂的多維數組。 當我們有一個多維數組 這意味著我們可以有類似的行和列, 而這僅僅是一個可視化的思考方式。 當我有一個多維數組,這意味著我要開始需要 超過1指數,因為如果我有一個網格 只是說你在哪個行並沒有給我們一個數字。 這真的只是給我們一個數字列表。 比方說,我有這樣的陣列。 我有一個數組稱為網格,和我說這是2行3列, 所以這是一個可視化的方式。 當我說我想要得到的元素[1] [2] 這意味著,因為這些行的第一和然後列 我要跳轉到第1行,因為我說了一句。 然後我到這裡來,到第2列,我要得到的值是6。 有意義嗎? 多維數組,請記住,在技術上是一個數組的數組。 我們可以有數組的數組的數組。 我們可以繼續下去,但一個真正的方式來思考 這是怎麼被解僱,這是怎麼回事,是形象化 在這樣的一個網格。 當我們通過陣列的功能,他們會表現 當我們通過定期的變量功能有點不同 像傳遞一個int或float。 當我們傳遞了一個int或char或任何其他數據類型 我們剛接過來一看,如果修改 該變量的值的變化不會傳播 到調用函數。 有了一個數組,在另一方面,這將發生。 如果我通過在陣列中的一些功能,該功能改變的一些內容, 我回來的時候調用它的函數 我的數組是不同的,為的詞彙 是數組是通過引用傳遞,我們將在後​​面看到。 這是關係到如何指針的工作,而這些基本數據類型, 另一方面,通過值傳遞。 我們可以認為那是一些變量的副本,然後通過在副本中。 不要緊,我們做什麼與該變量。 調用函數將不知道它被改變了。 數組是在這方面,不同的只是一點點。 例如,正如我們剛才看到的,主要是簡單的功能 可以在兩個參數。 第一個參數的主要功能是ARGC,或參數的個數, 第二個參數被稱為ARGV, 這些參數的實際值。 比方說,我有一個程序叫this.c, 和我說這一點,我要在命令行中運行此。 現在在某些參數傳遞到我的計劃,稱這 我可以這樣說,/這是CS 50。 這是我們想像的大衛每天都在做終端。 但是,現在該程序的主函數內的 這些值,因此argc是4。 這可能是有點混亂,因為我們真的只有通過在CS 50。 這是只有3個。 但請記住,第一個元素的argv的第一個參數 是函數本身的名稱。 因此,這意味著我們有4個東西在這裡, 及第一要素將是/這。 這將被表示為一個字符串。 那麼剩下的元素是我們的程序名後鍵入。 因此,正如順便說一句,因為我們在pset中2中所看到的, 記住該字符串50≠50的整數。 因此,我們不能說些什麼,“X = ARGV 3。 這只是不會是有道理的,因為這是一個字符串,這是一個整數。 所以,如果你要轉換之間的2,請記住,我們要 有這種神奇的功能,稱為ATOI。 這需要一個字符串並返回該字符串表示的整數內。 所以這是一個容易犯的錯誤的測驗, 只是在想,這會自動將正確的類型。 但我們知道,這將永遠是字符串 即使只包含字符串的整數或一個字符或一個浮子。 所以,現在讓我們來談談運行時間。 當我們做這些瘋狂的事情,所有這些算法, 它變得非常有用的,要問的問題,“他們需要多長時間?” 我們表示,所謂的漸近符號。 因此,這意味著 - 好,讓我們說,我們給我們的算法 一些真的,真的,真的很大的投入。 我們要問的問題,“如何是將要採取的嗎? 多少個步驟將需要運行我們的算法 作為輸入的函數的大小?“ 因此,第一種方式我們可以形容運行時間是大澳 這是我們的最壞情況下的運行時間。 因此,如果我們要對數組進行排序,我們給我們的算法的一個數組 時,應在升序降序排列, 那將是最壞的情況。 這是我們的最大長度的時間,我們的算法將採取的上限。 在另一方面,本Ω是要描述的最佳情況下的運行時間。 因此,如果我們給一個已排序的數組排序算法, 排序需要多長時間? 而這一點,然後,描述了一個運行時間的上下限。 因此,這裡有一些話,介紹一些常見的運行時間。 這些是按升序排列。 我們有最快的運行時間不變。 這意味著,無論有多少個元素,我們給我們的算法, 不管有多大,我們的陣列,整理 或做我們正在做的陣列將始終以相同的時間。 因此,我們可以表示,只需用1,這是一個常數。 我們也期待在數運行時間。 因此,類似二進制搜索是對數, 我們削減了問題的一半,每次 然後事情就從那裡獲得更高的。 如果你正在編寫一個O任何階乘的算法, 你可能不應該認為這是你的日常工作​​。 當我們比較的運行時間,重要的是要記住這些東西。 所以,如果我有一個算法是O(N),而其他人 有一個度為O(2n)的算法,這其實是漸近等價。 因此,如果我們想像Ň像一百十億元是一個很大的數字: 所以,當我們比較一百十億元的東西像一百十億元+ 3, 突然,3並沒有真正使一個很大的區別了。 這就是為什麼我們要開始考慮這些事情是相等的。 因此,這些常量在這裡的事情,比如,有這2個,或加入3, 這些僅僅是常數,而這些會下降。 所以這就是為什麼這些運行時間是相同的,說他們是O(n)的所有3。 同樣,如果我們有2個運行時間,比方說為O(n 3 + 2N²),我們可以添加 + N,+ 7,然後我們有另一種運行時,只是Ø(N³)。 再次,這些是相同的東西,因為這些 - 這些是不一樣的。 這是同樣的事情,對不起。因此,這些都是一樣的,因為 這n³將主宰這個2N²。 什麼是不一樣的事情是,如果我們的運行時間,如O(N³)和O(N 2) 因為這n³是遠遠大於這n 2。 因此,如果我們的指數,突然開始啦, 但是,當我們只是處理因素,因為我們是在這裡, 那麼它不會的問題,因為他們只是要輟學。 讓我們來看看到目前為止,我們已經看到的一些算法 並談談它們的運行時間。 第一種方法尋找一些在列表中,我們所看到的,是線性搜索。 而實施的是超級簡單的線性搜索。 我們只是有一個列表,我們要看看在列表中的每一個元素 直到我們找到的數量,我們要尋找的。 因此,這意味著,在最壞的情況下,這為O(n)。 和這裡,最壞的情況下可能是,如果該元素是 最後一個元素,然後使用線性搜索,我們來看看在每一個元素 直到我們得到的最後一個知道,它實際上是在列表中。 我們不能就這樣放棄半說,“這是可能不存在。” 我們來看看整個事情的線性搜索。 最好情況下的運行時間,在另一方面,是恆定的 因為在最好的情況下,我們要尋找的元素是列表中的第一個。 所以,我們要花費1步,不管有多大的列表 如果我們要找的第一個元素,每一次。 因此,當您搜索時,請記住,它不要求我們的列表進行排序。 因為我們只是去看看,每一個元素,它其實並不重要 什麼樣的順序,這些元素所在 一個更聰明的搜索算法是類似二進制搜索。 記住,是當你要執行的二進制搜索 在中間的列表中繼續尋找。 因為我們正在尋找的中間,我們需要對列表進行排序 否則,我們不知道在哪裡,中間是,我們來看看以上 整個列表中找到它,然後在這一點上,我們只是在浪費時間。 因此,如果我們有一個排序的列表中,我們發現中間,我們要比較的中間 的元素,我們要尋找的。 如果是太高,那麼我們就可以忘記的右半邊 因為我們知道,如果我們的元素已經過高 和一切該元素的權利甚至更高, 那麼我們就需要看看那裡了。 凡在另一方面,如果我們的元素是太低, 我們知道一切該元素的左側還太低, 所以它不是真正意義,看看有,。 通過這種方式,每一步,每一次我們看的列表中點, 我們要削減一半,因為我們的問題,我們突然知道 一大堆的數字,不能是一個我們要找的。 在偽代碼,這將是這個樣子, 而且,因為我們切割的列表中每一次的一半, 我們的最壞情況下的運行時間從線性到對數的跳躍。 因此,我們突然有記錄的步驟,以便找到列表中的元素。 最好的情況下的運行時間,不過,仍然是不變的 因為現在,讓我們只想說,我們正在尋找的元素是 原始列表總是精確中間。 因此,我們可以成長為大,因為我們希望我們的名單,但如果我們要尋找的是在中間元素, 那麼我們要花費1步。 所以這就是為什麼我們是O(log n)的Ω(1)或恆定。 讓我們實際運行在此列表中的二進制搜索。 因此,讓我們說,我們正在尋找的元素164。 我們要做的第一件事是找到這個列表的中點。 它只是發生的中點是要倒在這兩個數字之間, 所以我們就武斷地說,每次2號的中點之間, 讓我們圓了。 我們只需要確保我們這樣做的每一個步驟的方式。 因此,我們要圓了,和我們說,161是我們的名單中。 因此,161 <164,和161的每一個元素的左側 <164,所以我們不知道它會幫助我們在所有 開始尋找的元素,因為在這裡我們不能有。 所以,我們可以做的是,我們只是忘了,整個左半邊的列表, 現在只考慮從右邊的161起。 所以,再一次,這是中點;讓我們圓了。 現在175是太大了。 因此,我們知道它不會幫助我們期待在這裡或在這裡, 因此,我們就可以扔一邊去,和我們最終會達到了164個。 二進制搜索的任何問題? 讓我們從搜索通過一個已經排序的列表 實際以任何順序的號碼列表 該列表以升序排列。 我們看到在第一種算法被稱為冒泡排序。 這將是比較簡單的,我們看到的算法。 冒泡排序法說,當任意2個元素列表內的地方, 這意味著有一個更高的編號,以左側的一個較小的數字, 然後,我們將交換他們,因為這意味著,該清單將是 “更多排序”比以前。 我們只是打算再繼續這個過程中,一次又一次地 直到最後元素的的種泡到正確的位置,我們有一個排序的列表。 這是怎麼回事運行時間為O(N²)。為什麼呢? 好了,因為在最壞的情況下,我們採取的每一個元素,並 我們要結束了列表中的所有其他元素進行比較。 但是,在最好的情況下,我們有一個已排序的列表中,冒泡排序 只通過一次去,說:“不,我沒有做任何掉期,所以我所做的一切。” 因此,我們有最好的情況Ω(n)的運行時間。 讓我們來運行冒泡排序的列表。 首先,讓我們看一些偽真的很快。 我們想說,我們要跟踪的,在每一次迭代的循環, 我們是否改變任何元素的跟踪。 如此的原因是,我們要停下來的時候,我們沒有交換任何元素。 因此,在我們的循環的開始,我們還沒有交換任何東西,所以我們會說這是假的。 現在,我們要去列表,並比較i個元素的元素i + 1 如果是的情況下,有一個更大的編號,以左側的一個較小的數字, 然後,我們只是來交換他們。 然後,我們要記住,我們交換元素。 這意味著,我們需要在列表中至少1個或更多的時間去 因為我們停止的條件,其中已排序的整個列表時, 這意味著我們還沒有作出任何掉期。 所以這就是為什麼我們的條件,在這裡是“,而一些元素已被調換。 所以,現在就讓我們看一看在此名單上的運行。 我的名單5,0,1,6,4。 要開始冒泡排序的方式在左側,和它的比較 的第i個元素,所以0到i + 1,它是元件1。 它說,5> 0,但現在是向左, 所以我需要換5和0。 當我換,我突然得到這個不同的列表。 5> 1,所以我們要來交換他們。 5是6,所以我們不需要在這裡做任何事情。 但6> 4,所以我們需要交換。 同樣,我們需要貫穿整個名單,最終發現 這些是為了,我們交換, 在這一點上,我們需要更多的時間運行在列表中 以確保一切都在它的順序,並在這一點上冒泡排序已經完成。 採取一些元素,不同的算法和排序,選擇排序。 選擇排序背後的想法是,我們要建立一個排序的列表部分 在一個時間的1個元素。 而要做到這一點的方式,我們是通過建立列表中的左部。 基本上,每 - 每一步,我們將要採取的最小元素,我們已經離開 尚未排序,我們將它移動到該排序段。 這意味著我們需要不斷發現的最小的未分類的元素 然後,最小的元素交換的任何一種 最左邊的元素進行排序。 運行時間為O(N 2),因為在最壞的情況下 我們需要比較每一個元素的所有其他元素。 因為我們說,如果我們在左半邊的列表,我們需要 整個右段去尋找最小的元素。 然後,再次,我們需要去整個右段和 繼續一遍又一遍,再次。 這為n²。我們將需要一個for循環內的另一個循環 這表明N²。 在最好的情況下思想,讓我們說,我們給它一個已排序的列表; 我們其實並不比n²做的更好。 由於選擇排序有沒有辦法知道 最小的元素只是我正好要尋找的。 它仍然需要確保,這實際上是最低的。 只有這樣,才能確保它的最低限度,使用這種算法, 再看看每一個元素。 所以,真的,如果你給它 - 如果你給一個已排序的列表中選擇排序, 它不會做任何比給它一個列表,該列表還沒有排序。 順便說一下,如果真的發生的情況下,有什麼是O(的東西) 及的歐米茄的東西,我們只是說,它是θ的東西更簡潔。 所以,如果你看到在任何地方,這是什麼,僅僅表示。 如果事情是THETA的n²,它既是大O(N 2)和Ω(N ​​2)。 因此,最好的情況和最壞的情況下,它不會有所作為, 該算法是每次都做同樣的事情。 因此,這是選擇排序的偽代碼可能看起來像。 基本上,我們會說,我想遍歷列表 由左到右,並在每個迭代循環,我要移動 到這部分的列表中最小的元素。 有一次我移動的東西,我從來沒有需要再看看該元素。 因為只要我換的左部的列表中的一個元素,它的排序 因為我們正在做的一切都在按升序排列使用最小值。 所以我們說,好了,我們在i位置上,我們需要的所有元素 i的右邊的,以便找到最低。 因此,這意味著,我們想看看從i + 1到列​​表末尾。 而現在,如果我們目前正在觀察的元素是低於我們的最低到目前為止, 請記得,我們​​開始只是最小關斷 任何元素,我們目前在我假設這是最低的。 如果我找到比這更小的元素,然後我會說,好吧, 好了,我已經找到了新的最低。 我要記住,最低為。 所以,現在,我已經經歷了一次該權利未分類的分類, 我可以說,我要交換的最小元素的位置i的元素是。 這是要建立我的清單,我的排序部分,由左到右的名單, 我們永遠不需要看一個元素,再一次在該部分。 一旦我們交換了。 因此,讓我們在此列表中選擇排序的運行。 這裡的藍色元件將是在i,和紅色的元件將是最小元素。 所以,我開始一路在左側的列表,所以在5。 現在,我們需要找到最小的未分類的元素。 所以我們說0,所以0是我的新的最低。 但我不能停止,因為即使我們能夠識別出0是最小的, 我們需要運行通過列表以確保所有其它元素。 因此,1是更大的,6是更大的,是更大的。 這意味著,在所有這些元素後,我已經決定0是最小的。 所以,我要交換5和0。 一旦我換,我會得到一個新的列表,我知道,我從來沒有需要再次看,0 因為一旦我交換吧,我已經整理它,我們就大功告成了。 現在,碰巧的是​​,藍色的元素又是5, 我們需要在1%,6和4,確定1 是最小最小的元素,所以我們交換1和5。 同樣,我們需要看看 - 比較5〜6和4, 我們交換4和5,最後,比較 這2個數字,並交換它們,直到我們得到我們的排序列表。 選擇排序的任何問題嗎? 好吧。讓我們繼續上次的話題,那就是遞歸。 遞歸,請記住,這是真的薈萃東西的功能 反复調用自身。 因此,在某些時候,而我們的機能的反复調用本身, 需要有一些點,我們不再稱自己。 因為如果我們不這樣做,那麼我們只是要繼續這樣下去,永遠, 我們的計劃是不會終止。 我們將這種情況的基本情況。 說,而不是再次調用一個函數的基本情況, 我只是返回一些值。 因此,一旦我們返回一個值,我們稱自己已經停止了, 至今,我們已經取得了其餘的電話也可以返回。 的鹼情況下,與此相反的是遞歸的情況下。 這是當我們想要撥打另一個電話的功能,我們目前所處的 雖然並非始終如此,我們可能要使用不同的參數。 所以,如果我們有一個稱為F的函數,且f稱為1個參數, ,我們只是調用f(1),F(1),F(1),和它碰巧的是, 參數1分為遞歸的情況下,我們仍然永遠不會停止。 即使我們有一個基礎的情況下,我們需要確保,最終我們要達到這一基本情況。 我們不只是保持在這個遞歸的情況下。 通常情況下,當我們調用自己的時候,我們可能有不同的觀點。 這是一個非常簡單的遞歸函數。 因此,這將計算出一個數的階乘。 在這裡往上頂,我們有我們的基本情況。 的情況下,N≤1,我們不會再次打電話因子。 我們要停止,我們只是將返回一定的價值。 如果這是不正確的,那麼我們要達到我們的遞歸的情況。 請注意,在這裡,我們不只是調用的階乘(N),因為那將是非常有用的。 我們會打電話給別的東西的階乘。 所以你可以看到,最終,如果我們通過一個階乘(5)的東西, 我們要調用階乘(4)等,最終我們要達到這一基本情況。 因此,這看起來不錯。讓我們看看會發生什麼,當我們真正運行這個。 這是堆棧,讓我們說,主要是要調用這個函數的參數(4)。 因此,一旦的階乘看到和= 4,階乘將調用本身。 現在,突然之間,我們的階乘(3)。 因此,這些功能都將繼續保持增長,直到最終,我們打我們的基本情況。 在這一點上,這是,則返回值返回(nx的的返回值), 的返回值,這是NX的返回值。 最後,我們需要打一些數字。 我們在上方在這裡,說返回1。 這意味著,一旦我們回到這個數字,我們可以彈出堆棧。 因此,這階乘(1)就完成了。 1時返回時,這個階乘(1)返回,返回1。 返回值,請記住,這是NX的返回值。 突然,這傢伙知道,我想回到2。 所以請記住,返回值,這是NX的返回值。 所以,現在我們可以說,3×2,最後,在這裡,我們可以說, 這將是4×3×2。 而一旦這種回報,我們得到一個整數內的主要。 遞歸有任何疑問? 好的。因此,有更多的時間回答大家的提問結束時, 但現在約瑟夫將支付餘下的主題。 王陽樂]。所以,現在,我們已經談到遞歸, 讓我們來談談合併排序是一點點。 合併排序是基本的數字排序的列表的另一種方式。 它的工作原理是,歸併排序,你有一個列表,我們要做的是 我們說,讓我們將其劃分為兩半。 我們將首先運行再次合併排序的左半邊, 然後我們會遇到合併排序的右半​​, 這給了我們兩半進行排序,和現在我們要結合這些半在一起。 這是一個有點難以看到沒有一個例子,所以我們走走過場,看看會發生什麼。 所以,你開始這個列表中,我們把它分為兩半。 我們經營的第一個合併排序的左半邊。 所以這是左前衛,和現在我們再通過這個列表 被傳遞到合併排序,然後我們看, 在此列表的左側,我們運行它的合併排序。 現在,我們得到了2號的列表, 現在的左半邊長僅1元,我們不能 分裂一個列表,其中只有1成半的元素,所以我們只是說,一旦我們有50個, 這僅僅是1元,它已經排序。 一旦我們完成了,我們可以看到,我們可以 移動至右半此列表, 3排序,所以現在這個列表進行排序的兩半 我們可以將這些數字重新走到一起。 因此,我們期待在50和3,三是小於50,所以它在第一,然後50用武之地。 現在,這樣做了,我們回去這是正確的一半,列表和排序。 42是它自己的號碼,所以它已經排序。 所以,現在我們比較這些2和圖3是小於42,因此,被放在第一, 現年42​​歲的被提出,和50被放進去。 現在,排序,我們去所有的方式回到頂端,1337年和15。 好吧,我們現在看這個名單的左半邊; 1337本身,所以它的排序,並同15。 所以,現在我們結合這2個數字進行排序,原單,15 <1337, 所以在第一位,然後是1337去英寸 現在我們整理的兩半原始列表的頂部。 所有我們需要做的是結合這些。 我們期待在該列表中的第2號,3 <15,所以先進行排序的數組。 15 <42,所以它去了。現在,42 <1337,去英寸 50 <1337,所以去英寸注意到了我們僅僅花了2個號碼,這個列表。 所以,我們不能簡單地交替之間的列表。 我們只是在尋找一開始,我們正在採取元素 這是更小的,然後把它到我們的數組。 現在,我們已經合併了所有的一半就完成了。 有任何疑問,歸併排序?是嗎? [學生]:如果它分裂成不同的群體,為什麼他們不只是分裂一次 你有3個和2組中的嗎? [其他問題不知所云] 原因 - 所以,問題是,為什麼我們不能只是把它們合併的第一步後,我們有嗎? 我們之所以能做到這一點,雙方在最左邊的元素, 然後採取較小的一個,並把它放在,是因為我們知道,這些 個人的名單中排序的訂單。 所以,如果我在最左邊的元素的兩個部分, 我知道他們將這些列表中的最小元素。 所以,我可以把它們放到這個大名單的最小元素點。 另一方面,如果在第二個層次那邊,我看這2列出了 50,3,42,1337和15,這些都是沒有排序。 所以,如果我在50和1337,我要放50到我的清單。 但是,這並不真正有意義,因為是最小的元素的所有這些。 所以我們可以做到這一點結合步驟的唯一原因是因為我們的名單已經排序。 這就是為什麼我們得到了所有的方式向底部 因為當我們只是一個單一的號碼,你知道,一個單一的數字 在其本身已經是一個排序的列表。 有什麼問題嗎?不是嗎? 複雜性?好了,你可以看到,在每一步的最終數字, 我們可以將一個列表中的一半log N次, 這是我們得到這個N X日誌n的複雜性。 你會看到最好的情況下,歸併排序是n日誌n,它只是恰巧 最壞的情況下,或Ω那邊的,也是n日誌n。 要記住的東西。 移動,讓我們去到一些超級基本的文件I / O。 如果你看,你會發現我們在爭奪某種系統 在那裡你可以寫入到日誌文件中,如果你讀通過的代碼。 讓我們來看看你怎麼可能做到這一點。 好了,我們有fprintf,你能想到的只是輸出, 只是打印到一個文件中,而不是,因此在開始時的f。 這種代碼在這裡,它是什麼,你可能已經看到在爭奪, 它通過你的二維數組打印出來行由行的數字是什麼。 在這種情況下,輸出打印到您的終端或我們所說的標準輸出部分。 而現在,在這種情況下,我們要做的是與fprintf的printf取代, 告訴您要打印的文件,在這種情況下,它只是它打印輸出到該文件 而不是把它打印出來到你的終端。 好了,那麼這引出了一個問題:我們從哪裡得到這類型的文件,對不對? 我們通過在這fprintf機能的,但我們不知道它是從哪裡來的。 好了,早在代碼中,我們有什麼是在這裡,這個代碼塊 基本上說,打開該文件要求log.txt中。 我們做什麼後,我們必須確保該文件實際上是打開成功。 因此,它可能會失敗的原因有多種,你沒有足夠的空間在您的計算機上,例如。 因此,它始終是重要的,之前你做任何操作的文件 我們檢查該文件是否被成功打開。 那麼,什麼是一個,這是一個爭論的FOPEN,好了,我們可以打開一個文件,在許多方面。 我們可以做的是,我們可以通過它瓦特,這意味著覆蓋的文件,如果它退出了, 我們可以通過一個一個,這是他們附加的文件,而不是覆蓋它, 或者我們可以指定R,這意味著,讓我們打開的文件為只讀。 因此,如果程序試圖進行任何更改的文件, 罵他們,不要讓他們這樣做。 最後,一旦我們完成的文件,完成執行操作就可以了, 我們需要確保我們關閉文件。 因此,在你的程序,你要通過他們再次 您打開這個文件,只是將其關閉。 因此,這是重要的事情,你必須確保你做。 所以請記住,你可以打開一個文件,然後就可以寫入到文件中, 操作中的文件,但你必須在年底關閉該文件。 任何問題,基本的文件I / O?是嗎? [學生提問,不知所云] 就在這裡。現在的問題是,這log.txt文件出現在哪裡? 好吧,如果你只要給它log.txt中,它會創建在同一目錄下的可執行文件。 所以,如果讓隱私無處藏 - >> [學生提問,不知所云] 是。在同一個文件夾中,或在同一個目錄下,如你所說的話。 現在,內存,堆棧和堆。 因此,如何在計算機的內存嗎? 那麼,你可以想像內存塊的排序。 而在內存中,我們有什麼所謂的堆卡在那裡,棧,在那裡。 和堆向下增長的堆棧是向上增長的。 因此,作為托米提到的 - 哦,好了,我們這些其他4段,我會在第二 - 湯米剛才說,你知道他的功能是如何稱呼自己和稱呼對方? 他們建立這種堆棧幀。 那麼,如果主調用foo,foo的被放在堆棧中。 foo調用了酒吧,酒吧將在堆棧上,並因此獲得在堆棧中。 當他們返回,他們各拿採取的堆棧。 什麼這些地方,保持記憶的? 那麼,頂部,這是文本段包含程序本身。 的存在,所以本機代碼,一旦你編譯的程序。 其次,任何初始化的全局變量。 所以,你必須在你的程序中的全局變量,和你說的一樣,A = 5, 得到段,下, 您有任何未初始化的全局數據,它只是詮釋一個, 但你不說,它等於任何東西。 實現這些都是全局變量,所以他們在外面的主。 因此,這意味著任何的已宣告但不會被初始化的全局變量。 那麼,是什麼在堆嗎?分配的內存使用malloc,我們將在一點點。 最後,與堆棧您有任何局部變量 任何功能,你可以調用他們的任何參數。 的最後一件事,你不真正了解的環境變量做什麼, 但只要你運行的程序,有一些相關的,如 這是用戶名的人誰跑的程​​序。 這就是將要排序的底部。 的內存地址,這是十六進制值, 值的頂部從0開始,和他們走一路下滑到了谷底。 在這種情況下,如果你在32位系統上, 在底部的地址將是0x開頭,然後自動對焦,因為這是32位, 它是8個字節,並且在這種情況下,8個字節對應於8個十六進制數字。 所以,在這裡你將有一樣,0xFFFFFF具有,和在那裡,你將有0。 那麼,什麼是指針?你們有些人可能不涉及這部分之前。 但我們沒有去,所以在課堂上的指針只是一個數據類型 店,而不是某種類型的值,如50,它存儲在內存中的某個位置的地址。 這樣的記憶[不知所云]。 因此,在這種情況下,我們所擁有的,我們有一個指針,指向一個整數或一個int *, 它包含這個十六進制的0xDEADBEEF地址。 那麼,我們有什麼,現在,該指針指向在內存中的某個位置, 這只是一個,值50是在此內存位置。 在32位系統中,所有32位系統上,指針佔用32位或4個字節。 但是,例如,在64位系統中,指針是​​64位。 所以,你要記住的東西。 因此,在結束位系統,指針是結束位長。 指針是一種難以消化的,沒有多餘的東西, 所以,讓我們通過一個例子來動態內存分配。 動態內存分配為你做,或者我們調用malloc, 它可以讓你分配某種形式的設置之外的數據。 因此,此數據是一種程序的持續時間更永久的。 因為你知道,如果你裡面的一個函數,該函數返回x聲明, 你不再需要訪問的數據存儲在x。 讓我們做什麼指針,是他們讓我們存儲記憶體或存儲值 在不同的內存段,即堆。 現在,一旦我們返回的功能,只要我們有一個指針 內存中該位置,那麼我們能做些什麼,我們就可以看的值。 讓我們看一個例子:這是我們的內存佈局。 我們有這個功能,主要。 它所做的是 - 好了,就這麼簡單,對不對? - 詮釋第X = 5,這只是一個變量在堆棧中的主。 另一方面,現在我們宣派指針調用函數giveMeThreeInts。 所以現在我們進入這個功能,我們創建了一個新的堆棧幀。 然而,在這個堆棧幀中,我們聲明int *溫度, 這對我們的mallocs 3個整數。 因此,大小的int會給我們帶來多少字節,int是, 和malloc為我們提供了多少字節的空間在堆中。 因此,在這種情況下,我們已經建立了足夠的空間,3個整數, 和堆在那裡,這就是為什麼我畫更高。 一旦我們完成了,我們回來在這裡,你只需要3個int返回, ,它返回的地址,在這種情況下,內存是的。 我們設置指針開關,在那裡,我們只是一個指針。 但該函數返回被堆積在這裡消失。 因此,臨時消失,但我們仍然保持的地址在哪裡 這3個整數內的電源。 因此,在這組中,指針的範圍,為本地的堆疊框架, 但他們指的是在堆中的內存。 這是否有意義嗎? [學生]:你能重複一次嗎? >> [約瑟夫]是的。 所以,如果我回去只是一點點,你會看到該臨時分配 一些內存的堆在那裡。 所以,此功能時,giveMeThreeInts收益,該協議棧在這裡會消失。 而與它的任何變量,在這種情況下,該指針被分配在層疊幀。 這是怎麼回事消失,但由於我們返回臨時 我們設定指針= temp中,指針現在指向相同的內存位置溫度。 所以,現在,即使我們失去了溫度,即本地指針, 我們仍保留什麼該變量的指針指向內部的內存地址。 有問題嗎?這可以是種一個令人困惑的話題,如果你還沒有看過它在部分。 ,你的TF我們可以肯定會去,當然,我們可以回答問題 在年底的審查會議。 但,這是一個複雜的話題,我有更多的例子,是要顯示 這將有助於澄清指針實際上是什麼。 在這種情況下,指針是相當於陣列, 同樣的事情作為一個int數組,這樣我就可以使用這個指針。 所以我索引為0,和不斷變化的第一個整數為1, 改變所述第二至2的整數,和第三至3的整數。 因此,更多的指針。好了,記得Binky。 在這種情況下,我們分配了一個指針,或我們宣布一個指針, 但最初,當我剛剛宣布的指針,它不指向在內存中的任何地方。 這只是它裡面的垃圾值。 所以,我不知道該指針所指向的。 它有一個地址,只是充滿了0和1的地方,它最初宣布。 我不能做任何事情,直到我調用malloc 然後它給了我一個很小的空間就堆在那裡我可以把內部的值。 再說,我不知道,此內存裡面有什麼。 所以我必須做的第一件事是檢查系統是否有足夠的內存 給我1個整數擺在首位,這就是為什麼我在做此檢查。 如果指針是空的,這意味著,它沒有足夠的空間,或某些其他錯誤發生, 所以我要退出,我的計劃。  但是,如果它沒有成功,現在我可以使用這個指針 *指針的地址在哪裡 該值的地方是,它設置它等於1。 因此,在這裡,我們檢查,如果該內存存在。 一旦你知道它的存在,你可以把它 你要投入什麼樣的價值,在這種情況下,1。 一旦我們完成它,你需要釋放該指針 因為我們需要的系統內存,你提出的要求擺在首位。 因為電腦不知道什麼時候,我們已經完成了它。 在這種情況下,我們明確地告訴它,好吧,我們就大功告成了與記憶。 如果其他應用程序需要它,其他一些程序需要它,感覺自由地前進,並把它。 我們還可以做的是,我們就可以得到局部變量上設置的地址。 所以int x是裡面堆放的主要框架。 而當我們使用這個符號,這和運營商,它是什麼 它需要的x,和x是只是一些數據在存儲器中,但它有一個地址。 它位於什麼地方。因此,通過調用&X,這是什麼做的是它給了我們x的地址。 通過這樣做,我們正在做的指針指向其中x是在內存中。 現在,我們只是做一些事情,如* X,我們會得到5回。 這顆恆星被稱為提領。 按照地址,你會得到它的價值,存放在那裡。 有什麼問題嗎?是嗎? [學生]:如果你不這樣做的三尖的東西,它仍可以編譯嗎? 是。如果你不這樣做的3指針的東西,它仍然要進行編譯, 但我會告訴你發生了什麼在第二,並沒有這樣做, 這就是我們所說的內存洩漏。你不給系統 支持它的記憶,所以一段時間後程序會積累 內存,它的使用,並沒有其他人可以使用它。 如果你見過有150萬字節在您的計算機上的Firefox, 在任務管理器,這是怎麼回事。 你有內存洩漏的程序,他們沒有處理。 那麼,如何指針的算術運算的工作嗎? 好了,指針的算術運算是有點像到一個數組中的索引。 在這種情況下,我有一個指針,我做的是我的第一個元素的指針指向 此數組中的3個整數,我已經分配好了。 所以現在我做什麼,明星的指針只是改變列表中的第一個元素。 星級指針+1點在這裡。 因此,指針是在這裡,指針+1是在這裡,指針+2是在這裡。 因此,只要加1是沿著這個數組同樣的事情。 我們做的是,當我們這樣做的指針+1,你的地址在這裡, 中獲得的價值在這裡,你把一個明星從整個表達式 取消對它的引用。 所以,在這種情況下,我這個數組中的第一位置設置為1,則 第二位置為2〜3中的第三位置。 我在做什麼在這裡是我打印的指針+1, 這只是給了我2。 現在,我遞增指針,所以指針等於指針+1, 向前移動。 所以現在如果我打印出來的指針+1 +1指針現在是3, 在這種情況下,打印出3。 而以免費的東西,我給它的指針 必須指出的數組,我回來了從malloc的開始。 因此,在這種情況下,如果我在這裡呼籲3,這不會是正確的, 因為它是在中間的數組。 我必須減去到原來的位置 最初的第一點,我才可以釋放它。 因此,這裡是一個更複雜的例子。 在這種情況下,我們7個字符,一個字符數組分配。 在這種情況下,我們正在做的是,我們在第6循環, 我們將它們設置為Z。 因此,對於int i = 0,I> 6,我+ +, 所以,指針+我只是給我們,在這種情況下, 指針,指針1,指針2,指針3,依此類推等等迴路中。 它要做的是獲取該地址,解引用獲得的價值, 和變化值到Z。 那麼,在年底記住這是一個字符串,對不對? 所有的字符串結束的空終止字符。 所以,我要做的就是在指針6,我把空終止符中。 現在我基本上是做什麼在這裡實現輸出一個字符串,對不對? 所以,當輸出現在,當它達到一個字符串的結束嗎? 當它擊中的空終止字符。 因此,在這種情況下,我原來的指針指向該數組的開始。 我的第一個字符打印出來。我將它移到1。 我打印的字符。我移動過來。 我一直這樣做,直到我到達終點。 而現在的結束*指針解引用,並得到空終止字符。 所以我的while循環運行,只有當該值不是空終止字符。 所以,現在我退出這個循環。 所以,如果我從這個指針減去6, 我回去的方式開始。 請記住,我這樣做是因為我去的開始,以釋放它。 所以,我知道這是一個很多。有什麼問題嗎? 請,是嗎? [學生提問不知所云] 你能說大聲嗎?抱歉。 [學生]:最後一張幻燈片之前釋放的指針, 你改變指針的值嗎? [約瑟夫]所以,就在這裡。 >> [學生]:哦,好吧。 [約瑟夫]所以,我有一個指針減減,右, 移動的東西回來,然後我釋放它, 因為這個指針指向的數組的開始。 [學生]:但是,這不會需要你停止了之後的所有行。 [約瑟夫]所以,如果我停止後,這將被視為內存洩漏, 因為我沒有運行免費的。 [學生]:我後的第一個三線指針+1 [不知所云] [不知所云]。 [約瑟夫]嗯。那麼,什麼是那裡的問題? 抱歉。不,不。走,走,請。 [學生]:所以,你就不會改變指針的值。 你會不會有,做指針減減。 [約瑟夫]是的,沒錯。 所以,當我做指針+1和+2指針, 我不這樣做指針等於指針+1。 所以,只是停留指針指向的數組的開始。 這是只有當我做加再加,它的值設置裡面的指針, 它實際上移動一起。 好的。 還有問題嗎? 同樣的,如果這是鋪天蓋地的,這將覆蓋在會議上。 問問你的教學研究員,它結束時,我們可以回答的問題。 通常我們不喜歡做這減去的事情。 這要求我跟踪我多少數組中的偏移。 所以,總的來說,這是只是為了解釋如何指針運算。 但是,我們通常喜歡做的是什麼,我們要創建的副本的指針, 然後,我們將使用該副本,當我們走動的字符串。 因此,在這些情況下,您使用的整個字符串複製到打印, 但我們沒有這樣做指針減6跟踪我們搬到了多少, 因為我們知道,我們仍然指向原來的點開始的列表 我們改變的是這個副本。 因此,在一般情況下,改變你原來的指針的副本。 不要試圖有點像 - 不要改變原來的副本。 試圖改變你原來的只讀副本。 所以,你會注意到當我們通過串入的printf 你不必在它前面放一個明星,像我們一樣與所有其他指針引用,對不對? 所以,如果你打印出整個字符串的%s需要一個地址, 在這種情況下一個指針,或在這種情況下,像一個字符數組。 字符,字符*和數組同樣的事情。 指針是字符,字符數組同樣的事情。 所以,我們要做的是通過指針。 我們沒有通過,如*指針或類似的東西。 因此,數組和指針是同樣的事情。 當你正在做的事情,比如x [Y]在這裡的數組, 它在做什麼引擎蓋下的是它說,沒關係,這是一個字符數組, 所以這是一個指針。 因此,x是同樣的事情, 所以它做什麼是Y到X, 這是同樣的事情向前發展在內存中。 而現在X + Y為我們提供了某種形式的地址, 我們解引用地址或箭頭 內存中該位置在哪裡,我們得到的價值,在內存中的位置。 所以,所以這兩個是完全一樣的東西。 這只是一個語法糖。 他們做同樣的事情。他們只是對彼此的不同句法。 那麼,什麼可能出錯的指針嗎?一樣,有很多。好吧。所以,不好的事情。 你可以做一些不好的事情不檢查,如果您的malloc調用返回null,正確的嗎? 在這種情況下,我要求給我的系統 - 這個數字是什麼? 2億次4一樣,因為一個整數的大小為4個字節。 我要求它像8十億字節。 當然,我的電腦是不是能夠給我這麼大的內存回。 而我們沒有檢查,如果這是空的,所以,當我們試圖取消對它的引用在那裡 - 按照箭頭的地方的去 - 我們沒有這方面的記憶。 這就是我們所說的釋放空指針。 這基本上使你出現段錯誤。 這是你可以segfault錯誤的方式之一。 其他不好的事情可以做 - 哦,好的。 這是一個空指針解引用。好吧。 其他不好的事情 - 嗯,要解決,你只要把在那裡的檢查 檢查指針是否為空 和退出的程序,如果它發生了,malloc返回一個空指針。 這是XKCD漫畫。人們理解了。排序的。 因此,記憶體。我去了這一點。 我們在一個循環中調用malloc,但我們每次調用malloc 我們正在失去這個指針指向的軌道, 因為我們弄錯了。 因此,初始調用malloc給我的記憶在這裡。 我的指針的指針。 現在,我不釋放它,所以現在我調用malloc。 現在,在這裡。現在,我的記憶中指出在這裡。 指著在這裡。指著在這裡。 但我已經失去所有的記憶,在這裡,我分配的地址。 所以現在我沒有任何參考了。 所以,我不能讓他們自由這個循環之外。 因此,為了解決這樣的事情, 如果你忘了空閒內存,你會得到此內存洩漏, 你必須釋放內部的存儲器中,這個循環一旦你用它做。 那麼,這是什麼情況。我知道很多你不喜歡這一點。 但現在 - 耶!你得到這樣的44,000千字節。 所以,你釋放它的循環結束時, 而這只是每次釋放內存。 從本質上講,你的程序沒有內存洩漏了。 現在,別的東西你可以做的是釋放一些內存,你問過兩次。 在這種情況下,你的malloc東西,你改變它的值。 您可以免費一次,因為你說你用它做。 但後​​來我們再釋放它。 這是非常糟糕的東西。 它不會到最初出現段錯誤, 但經過一段時間這樣做是雙重釋放這會破壞你的堆結構, 你將學習多一點點,如果你選擇一個類CS61。 但本質上一段時間後你的電腦會感到困惑 什麼樣的內存位置和它的存儲 - 在數據被存儲在內存中。 因此,兩次釋放一個指針是一個壞的事情,你不想做。 其他的東西,可以去錯了不使用sizeof。 因此,在這種情況下,你的malloc 8個字節, 這是為兩個整數同樣的事情,對不對? 所以,這是絕對安全的,但它呢? 那麼,作為盧卡斯談到不同的體系, 整數是不同長度。 因此,在您正在使用的電器,整數是4個字節, 但其他一些系統上,他們可能是8個字節,也可能是16個字節。 所以,如果我只是在這裡使用這個號碼, 這個程序可能會在設備上工作, 但它不會在其他一些系統分配足夠的內存。 在這種情況下,這是si​​zeof運算符用於。 當我們調用的sizeof(int),這樣做是什麼  它為我們提供了一個程序正在運行的系統上的整數的大小。 所以,在這種情況下,表示sizeof(int)將返回4類似器具上, 現在這個意願,4 * 2,8, 這僅僅是為兩個整數的必要的空間的量。 在不同的系統中,如果一個int是16個字節或8字節一樣, 它只是將返回足夠的字節來存儲量。 最後,結構。 所以,如果你想存儲在內存中的數獨板,怎麼可能我們做到這一點呢? 你可能會想到的第一件事像一個變量, 一個變量的第二件事情,第三件事情是一個變量, 第四件事 - 壞,右一個變量? 所以,你可以在此之上的一種改進是一個9×9陣列。 這很好,但是如果你想其他事物關聯的數獨板 喜歡的難度董事會, 或者,例如,你的分數是什麼,或你解決這個板多少時間呢? 好了,你可以做的是,你可以創建一個結構。 我基本上可以說是在這裡,我定義這個結構, 我定義的板9×9的數獨板組成。 它所擁有的,它具有的水平的名稱的指針。 它還具有X和Y,這是我現在的坐標。 還花費的時間[不知所云],它有到目前為止,我已經輸入的總數的移動。 因此,在這種情況下,我可以分組一大堆的數據整合到一個結構 而不是它像飛舞著像不同的變量 ,我真的不能跟踪的。 這讓我們有很好的語法形式的引用不同的結構,這裡面的東西。 我可以做board.board,我得到的數獨板。 Board.level,我是多麼艱難。 ,Board.x和board.y給我,我可能會在董事會的坐標。 因此,我訪問就是我們所說的結構體中的字段。 這定義sudokuBoard,這是一個類型,我。 現在,我們在這裡。我有一個變量稱為“板”的類型sudokuBoard。 因此,現在就可以訪問這個結構在這裡的所有領域。 任何關於結構的問題嗎?是嗎? [學生]:對於整數X,Y,你宣布一個行嗎? >> [約瑟夫]嗯。 [學生]:所以,你可以做,所有的人? 喜歡在x,y的逗號倍,總? [約瑟夫]是的,你可以做到這一點,但我之所以把x和y在同一行 - ,問題是我們為什麼能做到這一點在同一行嗎? 我們為什麼不把所有這些在同一行上 x和y是彼此相關的, 而這僅僅是風格上更正確的,在一定意義上, 因為它的分組在同一行上的兩件事情 ,像那種同樣的事情。 而我只是分裂分開。它只是一種風格的東西。 在功能上並沒有任何差別。 對結構的任何其他問題? 您可以定義一個圖鑑與結構。 寵物小精靈有一個數字,它有一個字母,一個老闆,一個類型。 然後,如果你有一個數組的神奇寶貝,你可以彌補圖鑑,對不對? 好了,爽。因此,結構的問題。這些都是相關的結構。 最後,GDB。 GDB讓你做什麼呢?它可以讓你調試你的程序。 如果你還沒有使用GDB,我建議看短 只是在GDB是什麼,你如何使用它,你會如何使用它, 和測試程序。 因此,讓你做什麼GDB是它讓暫停[不知所云]你的程序 和一個實際線。 例如,我想在我的計劃,如3號線暫停執行, 而我在第3行,我可以打印出所有的值有。 因此,我們所說的像行暫停 我們稱這種放一個斷點,在該行 然後我們就可以打印出當時的變量在程序狀態的。 然後,我們可以從那裡通過的程序行由行一步。 然後我們就可以看的堆棧狀態的時間。 因此,為了使用GDB,我們所做的就是我們稱之為鐺上的C文件, 但我們有通過-ggdb標誌的。 一旦我們做,我們只是運行gdb生成的輸出文件。 所以你得到一些像這樣質量的文本, 但真的所有您需要做的是輸入命令的開頭。 在主要突破主要把一個斷點。 列表400列出了400行左右的代碼行。 因此,在這種情況下,你可以環顧四周,說,哦, 我想設置一個斷點,在397行,這條線, 那麼你的程序運行到這一步,這將打破。 這將暫停在那裡,您可以打印出來,例如,價值高或低。 因此,有一堆你需要知道的命令, 該幻燈片將在網站上, 所以,如果你只是想引用這些還是喜歡把它們放在你的備忘單,感覺很自由。 酷。這是測試複習0,如果您有任何問題,我們將堅持圍繞。 好的。  [掌聲] [CS50.TV]