[？ 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行會
循環之前已經執行 條件進行重新評估。
現在，在這一點上，我再次， 在這個程序結束。
我可以讓這種情況繼續 讓我的程序自然退出。
但有幾件事情 這是很重要的帶走
從這個特定的討論。
您需要評估 你自己的假設
有關如何代碼應表現。
任何時候你覺得有些片 你知道發生了代碼工作，
這可能是一個紅旗去 回顧和評估，並確保
你的假設 如何代碼運行
其實真到是怎麼回事 表現在你的源代碼。
>> 但更要的一點是， 當我們使用調試器，
你可以把斷點 不同的代碼行，
這將導致調試器 暫停執行在每個那些行
這樣就可以評估 內存甚至改變它在的地方。
再次，請記住，你可以 創建多個斷點，這樣你
也可以繼續執行，跳躍 以上代碼的大部分，
它會自動暫停 在下一個破發點。
>> 實際上有更先進 調試器的特性，以及。
但是，我們必須向您推薦 一些後續的視頻
要真正梳理出怎麼樣 使用這些特定的功能。
現在，謝謝 非常適合觀看。
祝你好運調試。