[? DAN ARMADARAS:?]你好, 我[?丹Armadaras?]。 今天,我們要 在看調試。 我們不僅要 談一些技巧, 而且我們要看看 一些特性包含 在CS50 IDE允許範圍內 您可以輕鬆地調試程序。 只是一個例子, 東西可以去錯 它實際上是什麼 我們已經看到了。 在這種情況下,這是一個C程序 接受來自用戶的整數, 除以它由兩個,並提供了 輸出給用戶。 現在從我們所看到的 在前面講課, 我們知道,這實際上會導致 特定類型的劃分問題 當我們有奇數。 具體來說,我們就扔掉 小數點後的任何東西。 現在,我們知道,這 恰好是這種情況。 如果我們運行它,我們可以確認 我們的懷疑,首先,通過編譯。 然後,通過運行和 輸入奇數。 這是什麼新鮮事。 但是,這實際上是一個 例如一個錯誤的 可以在一個更大的計劃存在 這變得更難追查。 儘管我們知道是什麼問題 是,事情的真正癥結所在 可能會試圖確定 具體在哪裡出現錯誤, 確定是什麼問題 是,然後將其固定。 因此,提供這作為一個例子 的可能是什麼東西 我們已經知道,但可以埋 內的代碼的其他元素。 所以打開這個其他來源 代碼文件作為例子, 這種劃分問題是現在 一個較大的程序的一部分。 不過可能有點 有點做作,和我們 可能能夠容易地 識別它,特別是 因為我們剛才談到的這一點。 但是,我們可以計算出,這 問題可以在更大的範圍存在。 如果我編譯這個和現在 運行它,輸入一個奇數, 我們可以看到,我們沒有得到準確 我們可能預期的輸出。 在這種特殊情況下, 我們可以說,我們 要計算所有號碼 從一個到某個特定數量。 我們可以看到,我們 有各種各樣的問題 在這裡,如果我們輸,簡單地說,0 和1時,我們提供的5輸入。 因此,我們已經知道, 有一個問題在這裡。 但是大家可能不知道準確 其中,這個問題確實存在。 現在的方法之一是 我們可以嘗試解決這個問題 是,我們的東西 已經被引入。 我們可以只使用它在更大的規模。 在第14行,我們有 這個printf函數, 這使我們能夠打印出狀態 的各種信息。 這是東西,你 應在程序中利用 要盡量弄清楚到底是什麼 發生在各行代碼。 因此,即使這不是 我們實際上最終的輸出 要生產出 這個計劃,我們仍然 可能有一些調試 聲明我們 可以揣摩正是 正在發生的事情對我們的代碼中。 因此,在這種情況下,我會 printf輸出調試標籤。 在這種情況下,這是 只是一個調試字符串 說我了,把使之成為 在我的代碼的輸出非常明確 它是什麼,我想展示。 而這裡輸出的數量 我們已計算。 在這種情況下,我可能會 想知道準確 發生了什麼之前和 經過一些特定的計算。 所以,我可能會使用前一個printf 與該行代碼後。 在這種情況下,我連 使其多一點點清晰 通過之前說的調試 並經過調試等等 我不混淆自己 多行看起來完全相同。 現在,如果我們重新編譯這個和運行 它,再輸入一個數字到五, 我們可以看到,我們有 現在,前後輸出 並且發現,我們沒有做明確的 數師或明確有 我們真正想要做的。 現在,在這種情況下,這是 不是一個真正的清晰輸出。 這不是一個真正的明確的結果是 我們想從這個特定的程序。 這是,再等 有點做作。 但是,也許的事情之一 我們可以做,如果說明書說 我們希望通過劃分這 2,並添加1--所以換句話說, 我們要舍up--然後 我們能知道我們能 這樣做特別的事情,在這種情況下。 現在,在這裡,我們知道,我們將 能加1到我們的一半數量。 讓我們重新編譯這個 並確認此 行為是我們想要的方式。 我們現在才看到, 有,我們有數字5。 有後,我們有3號, 它根據我們的說明書中, 就是我們想做的事。 但是,如果我們看一下 輸出這裡,我們可以 看到我們可能有另一個 完全錯誤,這是 我們是從0開始計數了。 現在再次,這是一件 我們已經看到在過去 我們可以很容易解決。 但在這種情況下,我們 也有益處 使用printf語句的 直接在for循環 準確地知道在哪裡 該錯誤發生。 所以printf的聲明 在幫助非常有用 你確定, 正是在你的源代碼, 一個特定的錯誤發生。 而且這也是很重要的實現 如此,當我們在寫代碼, 大家可能都假設 約的節目的狀態。 或者我們可能有假設 關於什麼是計劃的一部分 實際上是正確或不正確時, 後來,我們建立在該程序 並使其一部分 複雜的大型項目 我們認識到,某些方面 那其實是馬車。 用printf可以真正幫助 縮小並確定 程序的區域可能不 要準確地行為的方式,我們 預計,基於我們的假設。 但是,還有其他工具 可用,還有, 這使我們能夠揣摩 出在哪裡發生異常 而且,具體而言,有什麼事情 正在發生的程序裡面。 因此,用printf非常 有用當我們要 以確定的特定區域 一個程序,有一定的缺陷。 但它也變得 一段時間後,乏味。 在這種情況下,這是一個 比較簡單的程序 只有一個或兩個變量。 而且它變得非常容易讓我們 打印出這些變量的值 在較大的程序的情況下。 但是,我們可能有不同的 程序,有很多變數。 並且它可能不是很 這麼好用的printf 嘗試評估正在發生什麼 對這些變量中的每一個 作為上述程序的執行。 有一個程序存在 所謂調試程序。 在這種情況下,一個我們將 使用的是GNU調試器或GDB, 這使我們能夠檢查內部 一個程序的在一個更運作 詳細方法。 事實上,我們可以執行 GDB的命令行 在這裡,只需鍵入GDB和 我們要調試命令。 在這種情況下,指望。 現在,在這種情況下,我們可以看到,它 給我們帶來了一個提示GDB的說。 而我們實際上可以 執行命令GDB 實際開始執行的 計劃,停止在某些點, 評估的變量和 檢查變量 存在於程序狀態 在該特定時刻, 等,等等。 它提供了大量的電力給我們。 但它只是恰巧 該CS50 IDE還 提供了一個GUI或用戶 接口GDB的 使我們能夠做到這一點,而無需 命令行界面任何 或甚至全部。 我可以訪問的方法 是通過使用調試按鈕 在CS50 IDE的最頂端。 現在,在過去,我們所擁有的 可見的是,我們使用命令 行編譯,然後運行程序。 調試按鈕的功能 二者的那些步驟。 但它也帶來了 最右邊的調試器選項卡 這使我們能夠檢查各種 該方案的性能的 因為它正在執行。 如果我點擊調試,在此 情況下,它會彈出 在控制台中的新選項卡 窗口在最底層。 你可以看到這個選項卡 一些信息在最高層。 我們可以在很大程度上忽略了這一點。 不過的事情之一 我們要注意 是,它輸出 同樣的事情,我們 會得到,如果我們試圖運行make在 C程序的終端窗口。 在這裡,我們可以看到它的運行鐺, 它有各種標誌, 並且它編譯我們count.c文件, 這在當時所選標籤 我打的調試。 因此,這是因為非常有用的 現在用這個調試按鈕, 我們可以同時編譯,然後 執行程序,我們實際上 要運行。 之一是標誌 重要的是,在這種情況下, 我們實際使用過 時間最長 但也只是做了一些手 揮手[聽不清],其中 這是一個正確的位置。 在鏗鏘,它說-ggdb3。 在這種情況下,我們都 告訴鐺,我們的編譯器, 就是我們要編譯我們的節目。 但也提供了什麼 所謂的符號信息 從而使編譯器實際訪問 來了很多底層信息的 包含在程序中。 更具體地,數 對我有作用, 這些函數的名稱, 變量,其種類 這些變量是,和各種 其他的事情,幫助調試器 執行它的操作。 現在有別的東西 這是重要的提 當我們討論運行 一個程序以這種方式。 請注意,它實際上已經 提出了一個新的標籤在我們的控制台 沿底部。 我們不再需要互動 直接與終端窗口。 但這個新選項卡 實際上是一個終端窗口。 它只是特定於運行 我們已經創建的程序。 注意,在底部,在 一些輸出組合 通過鐺編譯器和GDB, 我們可以在很大程度上忽略了, 它實際上顯示的輸出 我們的節目在最底層。 現在,實現重要 這一個窗口實際上 會告訴你 從你的程序輸出 但也可以接受輸入 該程序,也是如此。 因此,通知,上面寫著 請輸入一個數字, 這是我們有相同的輸出 曾在終端窗口前。 但它現在在這個新的選項卡中顯示。 我可以輸入一個數字。 它實際上 如我們預期的功能 向我們展示了我們的調試輸出, 輸出可能是越野車, 正如我們之前看到的。 而在最底層,它 實際上有一些額外的輸出 從GDP中只是說 這一計劃已完成。 現在,當你在這個看到的 特別是貫穿, 這是沒有特別 有用的,因為即使是 雖然我們已經調試器菜單來 起來,這仍然是一個正在運行的程序。 在任何時候,它實際上 暫停執行對我們 要能夠檢查所有的 內包含的變量。 還有別的東西 我們必須做的,為了 讓GDB認識到,我們要 暫停程序的執行 而不是只允許它繼續 通常,我們會在任何其他情況下。 為了暫停執行, 在一些具體的線路, 我們需要創建什麼 叫一個破發點。 而一個破發點很容易產生 在這CS50 IDE通過利用鼠標 並直接點擊向左 的一些具體的行號。 一旦我做到這一點,一個紅點 出現,這表明 即該行現在是一個破發點。 而下一次我運行GDB,它 將在該斷點停止執行 當它到達該行代碼。 現在,這是一個重要的 事情來實現 這並不一定是 情況下每行代碼 實際上是訪問。 如果我要創建一個函數 在這裡,對於example--空F-- 而只是做一個打印線這裡 - 你好 天下 - 如果我從來沒有調用這個函數, 它會是這樣的情況, 如果我在這裡設置一個破發點, 功能將永遠不會被調用。 因此,這 尤其是破發點 將實際上從未暫停 程序的執行。 所以我們可以說,我正確地創建 在編寫一些代碼行一個破發點 實際上將被執行。 現在,在這種情況下,這是 在主函數中第一行。 因此,這將肯定是這樣的 即,只要我開始執行, 在第一行必達。 廣發行將暫停執行。 然後,我就可以 與調試器進行交互。 您可以設置多條線路為 斷點,如果你想。 我們也可以創建一個排隊 在這裡這段代碼中 永遠不會到達。 而且我們還可以設置一個另外的下面。 究其原因,我們將 要做到這一點,我們將 進入多一點點 詳細一會兒就好了。 所以現在,我只想禁用 這些額外的破發點 這樣我們就可以看看會發生什麼 當我有一個單一的突破 點在我的計劃。 我已經取得了一些 改變這一計劃。 所以,我要保存它。 我會點擊調試,這樣我就可以 開始編譯,然後 執行調試器。 我們將看到,時刻,後 我們選擇作為斷線 點以黃色突出顯示。 我們還可以看到,在 右上角的調試面板 該暫停圖標已經變成 進入一個小播放圖標。 這意味著,我們必須暫停 執行,在該特定情況下。 而且打的播放按鈕會 讓我們繼續執行 在該特定的點。 請注意,還有幾個其他的 在此調試面板可用按鈕, 為好。 步過,這讓我 執行該一行代碼 並加強了該行的 下一個,其中,在這種情況下, 將意味著printf的 被執行的語句。 它將然後暫停 執行第13行,像這樣。 而且還有一個步驟 進入功能, 如果我創建了其他非常有用 功能在源代碼中其他地方。 我想踏進 這些功能,而不是 執行該功能為一體。 但是,我們會看到更多的步驟 成在短短的一瞬間功能。 現在注意到一些其他的東西, 此調試面板中實際存在。 我們有這個小組被稱為 調用堆棧,它向我們展示了 到底在哪我們。 在這種情況下,我們都在裡面 的主要功能。 我們的腳本被稱為count.c。 而我們正好是在 線13,列中的一個,其 正是高亮區域 的源代碼指示,以及。 現在請注意,這也顯示了 在局部變量節 所有的變量是 這個函數中存在。 要注意這一點很重要 所有的變量的 將出現在這個局部變量 一個函數內部分, 甚至在它們被定義。 在這裡我們可以看到,我們有一個變量 中名為num,擁有默認值為0, 它是int類型的。 現在擺在我們實際初始化 所有這些變量, 我們不一定 保證看到的值為0。 和取決於其他處決 已執行 和你的內存時的狀態 你真正運行這個程序, 你可能會發現你 看不到的0值 和,相反,一些其它瘋狂的數字。 但不要擔心。 它不會是相關的,直到 你居然初始化值。 現在,在這種情況下,我們可以看到, 我已經進行了一些輸出。 而我,現在,暫停執行。 但在這種情況下,什麼 我真正想做的事情 就是到現在跨過這條線 的代碼,這樣我實際上可以 查詢該INT用戶的 我們希望在我們的程序中使用。 現在,在這種情況下,當 我打了一步,通知 該暫停或者說恢復 按鈕已更改為這個暫停按鈕 因為這段代碼實際上執行。 怎麼了 現在的問題是,它是 等待我們輸入一些信息 因為我們可以通過我們的輸出文本見 在最底層。 所以,現在,這是 實際上沒有暫停, 即使它,排序,出現 是因為什麼也沒有發生。 但它只是恰巧,在 我對13號線的具體情況, 我在等待用戶輸入。 所以GDB不能檢查 一個程序,因為它正在運行。 現在,我進入了一些,下一次 input--所以我會輸入數字5, 正如我們所看到的 past--按回車,我們 請注意,立即暫停GDB 並再次強調了下一行。 但現在發現,作為 我們的輸入值的結果, 我們裡面更新的價值 我們的局部變量,哪個 為準確地知道非常有用 是什麼數為在內存中。 現在,我可以允許此程序繼續運行 玩到其執行結束 擊中恢復。 我們可以看到,非常快 請問程序執行完畢 具有相同的輸出,我們 收到,調試器關閉, 現在這個計劃 完全停止。 我表明,只有在 用途看什麼 發生在我們居然打簡歷。 但是實際上我們要 要返回到該程序 這樣我們就可以嘗試調試 正是正在發生的事情。 現在,我使用調試器,我可能 並不需要這些調試printf的語句。 所以,我可以將其刪除,因為我會做 現在只是回到我們的簡單的代碼 我們過會兒前。 現在,當我保存 編程並執行它, 它將再次進入初始 突破一點,我對11行。 而我就可以檢查 我的變量我想做的事情。 它只是恰巧,這 部分是不是很有趣, 我知道,我要去 打印出這個聲明。 請輸入一個數字。 然後,我知道我要去 索要該整數用戶。 所以,或許,其實我是想動我的 向下突破點得遠一點。 您可以刪除斷點 通過點擊,再次,直接 到的該行編號的左側。 這紅點消失時表示 這是破發點現在已經沒有了。 現在,在這種情況下, 執行已暫停。 所以它實際上沒有打算 恢復在該特定實例。 但是,我可以設置一個斷點 在稍後一點。 當我現在恢復 代碼,它會繼續,並告訴 如此地步,斷點。 同樣,我打了簡歷。 似乎不喜歡什麼正在發生的事情。 但是,這是因為我的 代碼等待輸入。 我將進入5號,敲回車,和 現在,下一個斷點將受到打擊。 現在,在這種情況下,這 是代碼行 ,在此之前,我們就知道 正好是馬車。 因此,讓我們評估發生了什麼 在這一時代的特殊點。 當行被突出顯示,該 線尚未被執行。 所以在這種情況下,我們可以看到 我有一個數字,它 我有一個名為一個整數 NUM具有值為5。 而我要表演 一些數學上的那個數字。 如果我跳過了,就可以 請注意,對於NUM值 按照已經改變 算術,我們實際上已經完成。 而現在,我們 這個循環裡面 還是現在的for循環 本身是突出, 我們可以看到,我們有一個新的 變量調用我的 將被用在該for循環。 我現在才記 提到,有時你 會看到某種瘋狂 數字作為默認該號碼 或者變量 實際上初始化。 我們可以看到,正是 在這裡的這個可變 稱為I,其具有不 尚未初始化 在突出的時間。 但是,我們可以看到,它有一定的數量 我們不會真正期望的。 沒關係。 別擔心 因為我們有沒有真正 初始化的數量,直到我 跨過這條線與價值 我已經被初始化為值1。 所以一看就知道這其實 的情況下,讓我們跳過。 現在我們可以看到,這 線已經被執行。 而我們現在強調 這個printf的線。 我們現在可以看到我們是如何價值觀 i和3隨時間而變化。 這是非常有用的事,事實上, 是重複步過線。 你可以找到真正是什麼 碰巧你對循環內 並會發生什麼變化 變量內,對於環 作為程序執行 發生一步一個腳印的時間。 現在,在這一點上,我 跨過剛好夠用 那我現在在我的程序結束。 如果我跨過,它會 實際上停止執行 正如我們已經看到在過去。 讓我重新啟動此,再一次,所以 我可以點別的東西出來, 為好。 在這種情況下,它是 現在問我,再次, 為一個數字,其 我會再次進入。 但是這一次,我會在進入 數量較多,使得循環 將重複多次。 在這種情況下,我要去 輸入值11。 現在,再次因為我設置 在第15行一個破發點, 它會高亮顯示該行。 我們可以看到,我們的 11號是正確的 代表我們的局部變量。 現在跨過這一點,我們可以 看著發生在我們的I值是什麼 當我們著手這裡面的for循環。 它被遞增每次我們 達到了頂部循環。 現在,可能的事情之一 是有用的執行過程中做 這一計劃是對我來說,其實 改變變量中游看 發生在我的計劃是什麼。 在這種情況下,其實我可以 雙擊該值。 請注意,它變成了文本字段。 現在我可以進入不同的 價值共 怎麼看我的程序的行為 當我改變了這一切變化。 現在,在這種情況下,可變 我現在包含值10。 但該計劃仍是 在暫停執行。 當我踏上了過來,我看到 我的價值,我輸入為10, 不大於num的值越大, 這立即引起了循環 停止執行。 現在,這不是唯一的 你之所以會 要修改的變量的地方。 你可能真的想 嘗試修改它, 您可以繼續 執行一個循環 或者,讓你可以修改 之前,一些價值 達到某些特定的算術 你是要執行。 所以,現在,我們實際上改變 i的值作為程序執行, 它造成的for循環退出 ,過早地因為突然之間,我 正好是大於該值 NUM的,這意味著,對於循環 不再需要被執行。 此外,它正好是 情況下,我們改變了我的價值 該行17強調的時候, 這是在時間點 該循環執行 實際上正在評估。 如果我改變的價值 我在不同的線路,比如19, 我們會看到不同的 問題是因為19行會 循環之前已經執行 條件進行重新評估。 現在,在這一點上,我再次, 在這個程序結束。 我可以讓這種情況繼續 讓我的程序自然退出。 但有幾件事情 這是很重要的帶走 從這個特定的討論。 您需要評估 你自己的假設 有關如何代碼應表現。 任何時候你覺得有些片 你知道發生了代碼工作, 這可能是一個紅旗去 回顧和評估,並確保 你的假設 如何代碼運行 其實真到是怎麼回事 表現在你的源代碼。 但更要的一點是, 當我們使用調試器, 你可以把斷點 不同的代碼行, 這將導致調試器 暫停執行在每個那些行 這樣就可以評估 內存甚至改變它在的地方。 再次,請記住,你可以 創建多個斷點,這樣你 也可以繼續執行,跳躍 以上代碼的大部分, 它會自動暫停 在下一個破發點。 實際上有更先進 調試器的特性,以及。 但是,我們必須向您推薦 一些後續的視頻 要真正梳理出怎麼樣 使用這些特定的功能。 現在,謝謝 非常適合觀看。 祝你好運調試。