<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by MuLong PuYang on Medium]]></title>
        <description><![CDATA[Stories by MuLong PuYang on Medium]]></description>
        <link>https://medium.com/@racktar7743?source=rss-17111659ec5a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*GQ0rJS0lkFFMH-gDCFpmvQ.jpeg</url>
            <title>Stories by MuLong PuYang on Medium</title>
            <link>https://medium.com/@racktar7743?source=rss-17111659ec5a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 24 May 2026 21:04:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@racktar7743/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[[資料結構] 雙向環狀鏈結串列教學[4]: 完整程式碼]]></title>
            <link>https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-4-%E5%AE%8C%E6%95%B4%E7%A8%8B%E5%BC%8F%E7%A2%BC-f9183b6155f9?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9183b6155f9</guid>
            <category><![CDATA[c-language]]></category>
            <category><![CDATA[data-structures]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sun, 31 Dec 2023 11:14:44 GMT</pubDate>
            <atom:updated>2023-12-31T11:19:34.144Z</atom:updated>
            <content:encoded><![CDATA[<h4>雙向環狀鏈結串列的三個教程</h4><p><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-1-%E6%96%B0%E5%A2%9E%E8%88%87%E5%8D%B0%E5%87%BA-308ee6370e1c">雙向環狀鏈結串列教學[1]: 新增與印出</a></p><p><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-2-%E6%8F%92%E5%85%A5%E7%AF%80%E9%BB%9E-a4160f1ab159">雙向環狀鏈結串列教學[2]: 插入節點</a></p><p><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-3-%E5%88%AA%E9%99%A4%E7%AF%80%E9%BB%9E-91a31afc21c7">雙向環狀鏈結串列教學[3]: 刪除節點</a></p><h4>完整程式碼</h4><p>這裡呈現的程式碼與<a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-3-%E5%88%AA%E9%99%A4%E7%AF%80%E9%BB%9E-91a31afc21c7">雙向環狀鏈結串列教學[3]: 刪除節點</a>裡面的完整程式碼相同，此處提供github連結與github gitst連結以給讀者更方便觀看雙向環狀鏈結串列的程式碼</p><p><a href="https://github.com/RuoPuYang/doubly_linked_list/blob/main/doubly_circular_linked_list.c">doubly_linked_list/doubly_circular_linked_list.c at main · RuoPuYang/doubly_linked_list</a></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c25b37bc545fd7114c73eda84dd6d72f/href">https://medium.com/media/c25b37bc545fd7114c73eda84dd6d72f/href</a></iframe><h4>相關連結</h4><ul><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-1-%E6%96%B0%E5%A2%9E%E8%88%87%E5%8D%B0%E5%87%BA-308ee6370e1c">[資料結構] 雙向環狀鏈結串列教學[1]: 新增與印出</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-2-%E6%8F%92%E5%85%A5%E7%AF%80%E9%BB%9E-a4160f1ab159">[資料結構] 雙向環狀鏈結串列教學[2]: 插入節點</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-3-%E5%88%AA%E9%99%A4%E7%AF%80%E9%BB%9E-91a31afc21c7">[資料結構] 雙向環狀鏈結串列教學[3]: 刪除節點</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9183b6155f9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[資料結構] 雙向環狀鏈結串列教學[3]: 刪除結點]]></title>
            <link>https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-3-%E5%88%AA%E9%99%A4%E7%AF%80%E9%BB%9E-91a31afc21c7?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/91a31afc21c7</guid>
            <category><![CDATA[data-structures]]></category>
            <category><![CDATA[c-language]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sun, 31 Dec 2023 10:59:32 GMT</pubDate>
            <atom:updated>2023-12-31T11:28:30.954Z</atom:updated>
            <content:encoded><![CDATA[<p>在<a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-2-%E6%8F%92%E5%85%A5%E7%AF%80%E9%BB%9E-a4160f1ab159">雙向環狀鏈結串列教學[2]: 插入結點</a>的這一篇中，講述了如何在串列中的某一個結點之後插入結點，本篇介紹如何在串列中刪除結點</p><p><strong>完整程式碼</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c25b37bc545fd7114c73eda84dd6d72f/href">https://medium.com/media/c25b37bc545fd7114c73eda84dd6d72f/href</a></iframe><p><strong>刪除結點的函數: delete_node</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b6f078ece922cd00771b2eb5753e1671/href">https://medium.com/media/b6f078ece922cd00771b2eb5753e1671/href</a></iframe><p><strong>主函數</strong></p><p>首先這邊，我們調用delete_node的函數，首先刪掉第一個結點</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br>    insert_node(&amp;head, 5, 23);<br>    insert_node(&amp;head, 128, 57);<br>    insert_node(&amp;head, 41, 30);<br><br>    delete_node(&amp;head, 5);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>在delete_node函數這邊，會先去檢查第一個結點是否就是要刪除的數值，如果是的話，這裡會先把*start設定給第一個結點的下一個結點</p><p>這邊之所以要特別把第一個結點的處理與其他結點的處理分開的原因是如果第一個結點被釋放掉的話，需要再特別記錄目前的第一個結點的位置是什麼，如此程式碼在調用head的時候，可以正確地指出目前第一個結點的位置為何</p><pre>    if(value == current-&gt;data) {<br>        *start = current-&gt;next;<br>        do {<br>            current = current-&gt;next;<br>        }while(current-&gt;next !=ori_start);<br>        current-&gt;next = *start;<br>        (*start)-&gt;prev = current;<br>        free(ori_start);<br>        return;<br>    }</pre><p>接下來確認要刪除的數值是第一個結點，也就是if(value == current-&gt;data)，這裡會先把*start，設定給current-&gt;next，也就是讓目前第一個結點的下一個結點，成為新的第一個結點</p><p>接著使用do-while的迴圈，走到最後一個結點，而這邊ori_start的設定就是第一個結點，所以確保current會停留在最後一個結點</p><p>這時候，由於*start已經是新的第一個結點了，將最後一個結點，也就是current的next，指向*start</p><pre>current-&gt;next = *start;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZLQAwQb2e8xeZS4CljN0Zg.png" /></figure><p>而新的第一個結點*start的前一個結點，這時候會指向最後一個結點</p><pre>(*start)-&gt;prev = current;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*S5T5YnVFqa8p-e2x67E7LQ.png" /></figure><p>最後釋放舊的第一個結點，完成刪除第一個結點的動作</p><pre>free(ori_start);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TdgVSzaiYLm1jDpt06_Txw.png" /></figure><p>最後將示意圖變成更好讀的樣式</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hMaoVIS6c3ggrlhaR4Wofw.png" /></figure><p>正向的執行結果</p><pre>23 128 57 41 30 23</pre><p>反向的執行結果</p><pre>23 30 41 57 128 23</pre><p>這個時候，如果在執行刪除第一個結點前後，印出第一個結點的位址</p><pre>printf(&quot;Old first node address: %p\n&quot;, head);<br>delete_node(&amp;head, 5);<br>printf(&quot;New first node address: %p\n&quot;, head);</pre><p>可以看出head指向的位址的改變，注意這邊是使用筆者某一次的編譯結果，根據不同機器環境，不同次的執行結果，所被分配到記憶體位址的執行結果會不盡相同</p><pre>Old first node address: 0x563ae72472a0<br>New node address: 0x563ae7247300</pre><p>刪除數值為128的結點數值</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br>    insert_node(&amp;head, 5, 23);<br>    insert_node(&amp;head, 128, 57);<br>    insert_node(&amp;head, 41, 30);<br><br>    delete_node(&amp;head, 5);<br>    delete_node(&amp;head, 128);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>這時候，在delete_node函數中，由於不是第一個結點，所以執行的程式部分為以下這個區塊</p><p>當current的next的數值，如果等同於要刪掉的數值，就會開始執行相關的程式碼</p><pre>do {<br>    if(current-&gt;next-&gt;data == value) {<br>        temp = current-&gt;next;<br>        current-&gt;next = current-&gt;next-&gt;next;<br>        current-&gt;next-&gt;prev = current;<br>        free(temp);<br>        return;<br>    }<br>    current = current-&gt;next;<br>}while(current != *start);</pre><p>首先current的下一個結點，會被設定給temp，接著current的下下一個結點，會變成current的下一個結點</p><pre>current-&gt;next = current-&gt;next-&gt;next;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WQtGFFnlU5umf7Qq1x5KsQ.png" /></figure><p>接著current下一個結點的前一個結點，會變成current，注意這邊由於上一個程式碼的影響，所以current的下一個結點已經變成了數值為57的結點</p><pre>current-&gt;next-&gt;prev = current;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*12SNge42ix_c-b97wbBc9g.png" /></figure><p>最後就是釋放掉欲刪除的結點</p><pre>free(temp);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IJqP4okg4DFVPkPWYQKYiw.png" /></figure><p>正向輸出結果</p><pre>23 57 41 30 23</pre><p>反向輸出結果</p><pre>23 30 41 57 23</pre><p>刪除數值為30的結點</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br>    insert_node(&amp;head, 5, 23);<br>    insert_node(&amp;head, 128, 57);<br>    insert_node(&amp;head, 41, 30);<br><br>    delete_node(&amp;head, 5);<br>    delete_node(&amp;head, 128);<br>    delete_node(&amp;head, 30);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>輸出結果</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TU7wTkoMc3YTyLnTnjIc-g.png" /></figure><p>正向輸出結果</p><pre>23 57 41 23</pre><p>反向輸出結果</p><pre>23 41 57 23</pre><h4>相關連結</h4><ul><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-1-%E6%96%B0%E5%A2%9E%E8%88%87%E5%8D%B0%E5%87%BA-308ee6370e1c">[資料結構] 雙向環狀鏈結串列教學[1]: 新增與印出</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-2-%E6%8F%92%E5%85%A5%E7%AF%80%E9%BB%9E-a4160f1ab159">[資料結構] 雙向環狀鏈結串列教學[2]: 插入節點</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-4-%E5%AE%8C%E6%95%B4%E7%A8%8B%E5%BC%8F%E7%A2%BC-f9183b6155f9">[資料結構] 雙向環狀鏈結串列教學[4]: 完整程式碼</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=91a31afc21c7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[資料結構] 雙向環狀鏈結串列教學[2]: 插入結點]]></title>
            <link>https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-2-%E6%8F%92%E5%85%A5%E7%AF%80%E9%BB%9E-a4160f1ab159?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/a4160f1ab159</guid>
            <category><![CDATA[data-structures]]></category>
            <category><![CDATA[c-language]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Wed, 27 Dec 2023 14:17:11 GMT</pubDate>
            <atom:updated>2023-12-31T11:26:09.721Z</atom:updated>
            <content:encoded><![CDATA[<p>在<a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-1-%E6%96%B0%E5%A2%9E%E8%88%87%E5%8D%B0%E5%87%BA-308ee6370e1c">雙向環狀鏈結串列教學[1]: 新增與印出</a>這一篇中，講述了如何在雙向環狀鏈結串列中新增結點，這一篇會介紹插入結點的方法</p><p><strong>完整程式碼</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/53531e0063b5e270b509775f1a3b96ea/href">https://medium.com/media/53531e0063b5e270b509775f1a3b96ea/href</a></iframe><p><strong>插入結點的函數: insert_node</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a81cd7b2089588148195adf18677d9be/href">https://medium.com/media/a81cd7b2089588148195adf18677d9be/href</a></iframe><p><strong>主函數</strong></p><p>現在插入第一個結點，插在數值為45的結點之後</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>在insert_node中，如果找不到結點有這個數值，也就是if(insert_after_value == current-&gt;data)這個條件式不成立，那麼結點就會不斷的往下走一個，直到結點又走回第一個結點*start，就會離開迴圈</p><pre>do {<br>    if(insert_after_value == current-&gt;data) {<br>        Node *new_node = (Node*)malloc(sizeof(Node));<br>        new_node-&gt;data = value;<br>        new_node-&gt;next = current-&gt;next;<br>        current-&gt;next-&gt;prev = new_node;<br>        current-&gt;next = new_node;<br>        new_node-&gt;prev = current;<br>        break;<br>    }<br>    current = current-&gt;next;<br>}while(current!=*start);</pre><p>根據目前的鏈結串列，由於找不到數值為45的結點，所以這裡並不會插入數值為45的結點</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a-UGeG5XAeX8MDUrO5m80A.png" /></figure><p>新增數值為23的結點在數值為5的結點之後</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br>    insert_node(&amp;head, 5, 23);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>現在新增一個數值為23的結點</p><pre>Node *new_node = (Node*)malloc(sizeof(Node));<br>new_node-&gt;data = value;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vod-7er3Fi_NhmgZr4n30g.png" /></figure><p>接著目前結點的下一個結點，會變成新結點的下一個結點</p><pre>new_node-&gt;next = current-&gt;next;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PuA9_PBOHapK7E-UlzB85g.png" /></figure><p>目前結點的下一個結點的前一個結點，會是新結點</p><pre>current-&gt;next-&gt;prev = new_node;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IO7SXO5Y7DP7MTJTb16e4Q.png" /></figure><p>目前結點的下一個結點，會是新結點</p><pre>current-&gt;next = new_node;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kjFDYN61wxxwV9V4oEf_TA.png" /></figure><p>新結點的前一個結點，會是目前的結點</p><pre>new_node-&gt;prev = current;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fwU_QPXD2axrBaweGCSkKg.png" /></figure><p>重新整理成橫向的鏈結串列是意圖，整個串列的數值為5 23 128 41</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Nj9FO4yL9jS1VtXU-qinEw.png" /></figure><p><strong>執行結果</strong></p><p>正向輸出</p><pre>5 23 128 41 5</pre><p>反向輸出</p><pre>5 41 128 23 5</pre><p>新增數值為57的結點在數值為128的結點之後</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br>    insert_node(&amp;head, 5, 23);<br>    insert_node(&amp;head, 128, 57);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>輸出結果</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FjnFyJ2EYv-6XLM9GZDipw.png" /></figure><p>正向輸出</p><pre>5 23 128 57 41 5</pre><p>反向輸出</p><pre>5 41 57 128 23 5</pre><p>新增數值為30的結點在數值為41的結點之後</p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    insert_node(&amp;head, 45, 62);<br>    insert_node(&amp;head, 5, 23);<br>    insert_node(&amp;head, 128, 57);<br>    insert_node(&amp;head, 41, 30);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>輸出結果</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*laJGpMWuUXpdG471hVzcng.png" /></figure><p>正向輸出</p><pre>5 23 128 57 41 30 5</pre><p>反向輸出</p><pre>5 30 41 57 128 23 5</pre><h4>相關連結</h4><ul><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-1-%E6%96%B0%E5%A2%9E%E8%88%87%E5%8D%B0%E5%87%BA-308ee6370e1c">[資料結構] 雙向環狀鏈結串列教學[1]: 新增與印出</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-3-%E5%88%AA%E9%99%A4%E7%AF%80%E9%BB%9E-91a31afc21c7">[資料結構] 雙向環狀鏈結串列教學[3]: 刪除節點</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-4-%E5%AE%8C%E6%95%B4%E7%A8%8B%E5%BC%8F%E7%A2%BC-f9183b6155f9">[資料結構] 雙向環狀鏈結串列教學[4]: 完整程式碼</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a4160f1ab159" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[資料結構] 雙向環狀鏈結串列教學[1]: 新增與印出]]></title>
            <link>https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-1-%E6%96%B0%E5%A2%9E%E8%88%87%E5%8D%B0%E5%87%BA-308ee6370e1c?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/308ee6370e1c</guid>
            <category><![CDATA[c-language]]></category>
            <category><![CDATA[data-structures]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Tue, 26 Dec 2023 17:00:42 GMT</pubDate>
            <atom:updated>2023-12-31T11:24:13.823Z</atom:updated>
            <content:encoded><![CDATA[<p>在之前的篇章中，介紹了<a href="https://medium.com/p/bb881da97796">鏈結串列</a>、<a href="https://medium.com/p/5454b5190ab8">雙向鏈結串列</a>以及<a href="https://medium.com/p/adb583865726">環狀鏈結串列</a>，這篇文章將介紹雙向環狀鏈結串列。所謂的雙向鏈結串列，英文名稱為doubly circular linked list，在這個資料結構中，串列的每個結點是可以前後互相連通的，並且當遍歷整個串列後，最後會回到最源頭的那個結點</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5O8sa0OFfItyWRhc598KFg.png" /><figcaption>雙向環狀鏈結串列示意圖</figcaption></figure><p><strong>完整程式碼</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/067a1a3f830bada50d62b2bd3b505ffb/href">https://medium.com/media/067a1a3f830bada50d62b2bd3b505ffb/href</a></iframe><p><strong>新增結點的函數: add_node</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1ab24ebe962aa82c36b75d4bd7e0da28/href">https://medium.com/media/1ab24ebe962aa82c36b75d4bd7e0da28/href</a></iframe><p><strong>主函數</strong></p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>這裡我們先建立第一個結點，這是第一個結點，所以這個不管是往前指還是往後指，都會是自己，也就是new_node-&gt;next = new_node，new_node-&gt;prev = new_node，最後再去確認，如果是新增第一個結點，也就是*start還沒有被真正設定，就讓設定的new_node等同於*start</p><pre>Node *new_node = (Node*)malloc(sizeof(Node));<br><br>new_node-&gt;data = value;<br>new_node-&gt;next = new_node;<br>new_node-&gt;prev = new_node;<br><br>if(*start == NULL) {<br>    *start = new_node;<br>    return;<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/483/1*sWUXsyqUCT3I2qW90fDq1Q.png" /><figcaption>doubly circular linked list新增的第一個結點</figcaption></figure><p>這時候創造完第一個結點後，就可以印出來確認是否創造doubly circular linked list成功</p><p><strong>印出串列數值的函數: print_list</strong></p><p>這邊的print_list函數，會讓第一個node先印出數值，接著讓指向下一個node，然後進入迴圈，這個迴圈地跳出條件為當node為第一個node的時候就會跳出，要不然就會印出目前的訊息，然後再往下指，跳出後還會再印出目前結點的數值，其實就是要印出第一個結點的數值。</p><pre>void print_list(Node *node)<br>{<br>    Node *first_node = node;<br>    printf(&quot;%d &quot;, node-&gt;data);<br>    node = node-&gt;next;<br><br>    while(node != NULL) {<br>        if(node == first_node) break;<br>        printf(&quot;%d &quot;, node-&gt;data);<br>        node = node-&gt;next;<br>    }<br>    printf(&quot;%d\n&quot;, node-&gt;data);<br>}</pre><p>對於只有一個結點的情況，印出數值5之後，由於是第一個結點，所以在迴圈的判斷中就會跳出，跳出迴圈後，接著再印出第一個結點的數值5</p><p>輸出結果</p><pre>5 5</pre><p>反向印出串列數值的函數: inverse_print_list</p><p>其實調用的方法與print_list是一樣的，都是把第一個結點當作參數帶入到函數中，但是這邊將第一個結點命名為last_node，並且往前去走。這邊與print_list的方式一樣，先印出last_node的數值，接著將結點往前移，接著進入迴圈，如果是最後一個結點，就會跳出迴圈，如果不是的話，會印出結點內容，接著就會把結點往前移。</p><p>最後跳出迴圈的時候，會再印出最後一個結點的數值。</p><pre>void inverse_print_list(Node *node)<br>{<br>    Node *last_node = node;<br>    printf(&quot;%d &quot;, node-&gt;data);<br>    node = node-&gt;prev;<br><br>    while(node != NULL) {<br>        if(node == last_node) break;<br>        printf(&quot;%d &quot;, node-&gt;data);<br>        node = node-&gt;prev;<br>    }<br>    printf(&quot;%d\n&quot;, node-&gt;data);<br>}</pre><p>對於只有一個結點的情況，印出數值5之後，由於是最後一個結點，在迴圈的判斷中就會跳出，跳出迴圈後，會再印出最後一個結點的數值，其實數值就是5</p><pre>5 5</pre><p><strong>現在我們新增第二個數值為128的結點</strong></p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>新增第二個數值為128的結點後，此時在add_node的函數裡，因為不是屬於第一個結點，所以會執行else裡面的程式碼。</p><p>在else裡面的程式碼，其實就是宣告一個current的指標，並將*start設定為current，接下來就開始迭代這個鏈結串列，最後當迴圈走回到第一個結點的時候，就跳出迴圈。</p><p>這樣的程式碼就代表，經過迴圈的迭代之後，current會留在第一個結點的前一個結點</p><pre>void add_node(Node **start, int value)<br>{<br>    Node *new_node = (Node*)malloc(sizeof(Node));<br><br>    new_node-&gt;data = value;<br>    new_node-&gt;next = new_node;<br>    new_node-&gt;prev = new_node;<br><br>    if(*start == NULL) {<br>        *start = new_node;<br>        return;<br>    }<br>    else {<br>        Node *current;<br>        current = *start;<br>        while(current-&gt;next != *start) {<br>            current = current-&gt;next;<br>        }<br>        current-&gt;next = new_node;<br>        new_node-&gt;prev = current;<br>        new_node-&gt;next = *start;<br>        (*start)-&gt;prev = new_node;<br>    }<br>}</pre><p>此時就開始執行添加結點的第一個程式碼，將目前結點的下一個結點，指向new_node</p><pre>current-&gt;next = new_node;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/717/1*OgVzMkbHTorxAI9-uPyivg.png" /></figure><p>接著將這個數值為128的結點，往前指向數值為5的解點</p><pre>new_node-&gt;prev = current;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/717/1*VmYm5xnvnRxpgWA1_VuIig.png" /></figure><p>新結點的下一個結點，將會指向第一個結點</p><pre>new_node-&gt;next = *start;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*p_8tF1Q4vymYTyBYYAgtxg.png" /></figure><p>第一個結點的前一個結點，會指向新結點</p><pre>(*start)-&gt;prev = new_node;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/901/1*fPdvShG_Go6TXVEELoKB2Q.png" /></figure><p>最後執行程式碼，不管是正向印出，還是反向印出，都可以得到相同的結果</p><p>正向印出</p><pre>5 128 5</pre><p>反向印出</p><pre>5 128 5</pre><p><strong>新增第三個數值為41的結點</strong></p><pre>int main()<br>{<br>    Node *head = NULL;<br><br>    add_node(&amp;head, 5);<br>    add_node(&amp;head, 128);<br>    add_node(&amp;head, 41);<br><br>    print_list(head);<br><br>    inverse_print_list(head);<br><br>    free_list(head);<br><br>    return 0;<br>}</pre><p>新增完之後，doubly circular linked list的示意圖會如下</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a-UGeG5XAeX8MDUrO5m80A.png" /></figure><p>輸出結果為</p><p>正向印出</p><pre>5 128 41 5</pre><p>反向印出</p><pre>5 41 128 5</pre><p><strong>釋放掉記憶體的函數: free_list</strong></p><p>最後當所有鏈結串列都建置完成之後，就可以來釋放掉記憶體</p><p>這裡首先先設置一個total_node的變數，給予數值為1，接著開始使用迴圈迭代整個串列，以得到整個串列到底有多少結點</p><p>在確定有多少個結點之後，在這邊使用一個for迴圈，將current結點設定為第一個結點，並且讓current等同於temp，然後讓current變成下一個結點後，就釋放掉temp結點的記憶體，因為已經知道串列中到底有多少個結點，使用此方法讓迴圈整個走完之後，這樣就可以釋放掉整個雙向環狀鏈結串列的記憶體容量</p><pre>void free_list(Node *node)<br>{<br>    int total_node = 1;<br>    Node *first = node;<br>    node = node-&gt;next;<br>    while(node != first) {<br>        node = node-&gt;next;<br>        total_node++;<br>    }<br><br>    Node *current = first;<br>    Node *temp;<br>    int i;<br><br>    for(i = 0; i &lt; total_node; i++) {<br>        temp = current;<br>        current = current-&gt;next;<br>        free(temp);<br>    }<br>}</pre><h4>相關連結</h4><ul><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-2-%E6%8F%92%E5%85%A5%E7%AF%80%E9%BB%9E-a4160f1ab159">[資料結構] 雙向環狀鏈結串列教學[2]: 插入節點</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-3-%E5%88%AA%E9%99%A4%E7%AF%80%E9%BB%9E-91a31afc21c7">[資料結構] 雙向環狀鏈結串列教學[3]: 刪除節點</a></li><li><a href="https://medium.com/@racktar7743/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97%E6%95%99%E5%AD%B8-4-%E5%AE%8C%E6%95%B4%E7%A8%8B%E5%BC%8F%E7%A2%BC-f9183b6155f9">[資料結構] 雙向環狀鏈結串列教學[4]: 完整程式碼</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=308ee6370e1c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[工程師應知道的0x10個問題: 總覽]]></title>
            <link>https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-%E7%B8%BD%E8%A6%BD-970cc31f6b76?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/970cc31f6b76</guid>
            <category><![CDATA[c-programming]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sat, 26 Mar 2022 15:46:02 GMT</pubDate>
            <atom:updated>2022-03-26T15:46:02.508Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>英文參考網址</blockquote><blockquote><a href="https://rmbconsulting.us/publications/a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers/">A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers</a></blockquote><blockquote>中文參考網址</blockquote><blockquote><a href="https://creteken.pixnet.net/blog/post/24524138">C語言測試 應知道的0x10個基本問題</a></blockquote><h3>預處理器(Proprocessor)</h3><ul><li><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-1-%E7%94%A8-defince%E5%AE%9A%E7%BE%A9%E4%B8%80%E5%B9%B4%E7%9A%84%E7%A7%92%E6%95%B8-d147574d6782">工程師應知道的0x10個問題(1): 用#defince定義一年的秒數</a></li><li><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-2-%E7%94%A8macro%E5%AF%AB%E5%87%BD%E6%95%B8%E4%BE%86%E6%AF%94%E5%A4%A7%E5%B0%8F-7d5683b6edd4">工程師應知道的0x10個問題(2): 用macro寫函數來比大小</a></li><li><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-3-error%E6%8C%87%E4%BB%A4%E7%9A%84%E7%9B%AE%E7%9A%84-38fa98080ab4">工程師應知道的0x10個問題(3): #error指令的目的</a></li></ul><h3>無窮迴圈(Infinite Loops)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-4-%E7%84%A1%E7%AA%AE%E8%BF%B4%E5%9C%88-47a498122c55">工程師應知道的0x10個問題(4): 無窮迴圈</a></p><h3>資料宣告(Data declarations)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-5-%E8%B3%87%E6%96%99%E5%AE%A3%E5%91%8A-81f7b6faabf3">工程師應知道的0x10個問題(5): 資料宣告</a></p><h3>Static</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-6-static%E7%9A%84%E7%94%A8%E6%B3%95-d391dacb28a3">工程師應知道的0x10個問題(6): Static的用法</a></p><h3>Const</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-7-const%E7%9A%84%E7%94%A8%E6%B3%95-30414b4d43e7">工程師應知道的0x10個問題(7): Const的用法</a></p><h3>Volatile</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-8-volatile%E7%9A%84%E7%94%A8%E6%B3%95-e9238cfd38ff">工程師應知道的0x10個問題(8): Volatile的用法</a></p><h3>位元操作(Bit Manipulation)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-9-bit%E6%93%8D%E4%BD%9C-f119a38eeba6">工程師應知道的0x10個問題(9): Bit操作</a></p><h3>存取固定的記憶體位置(Accessing fixed memory locations)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-10-%E5%AD%98%E5%8F%96%E5%9B%BA%E5%AE%9A%E7%9A%84%E8%A8%98%E6%86%B6%E9%AB%94%E4%BD%8D%E7%BD%AE-f48fc960e70c">工程師應知道的0x10個問題(10): 存取固定的記憶體位置</a></p><h3>中斷(Interrupts)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-11-%E4%B8%AD%E6%96%B7-7c59ac7a10c4">工程師應知道的0x10個問題(11): 中斷</a></p><h3>程式範例(Code Examples)</h3><ul><li><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-12-%E7%A8%8B%E5%BC%8F%E7%AF%84%E4%BE%8B-b1fdb1cf7e2b">工程師應知道的0x10個問題(12): 程式範例</a></li><li><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-13-0%E7%9A%84%E4%B8%80%E8%A3%9C%E6%95%B8-4362a9c81423">工程師應知道的0x10個問題(13): 0的一補數</a></li></ul><h3>動態記憶體分配(Dynamic Memory Allocation)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-14-%E5%8B%95%E6%85%8B%E8%A8%98%E6%86%B6%E9%AB%94%E9%85%8D%E7%BD%AE-d974130fae2f">工程師應知道的0x10個問題(14): 動態記憶體配置</a></p><h3>Typedef</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-15-typedef-76151c5b9ec3">工程師應知道的0x10個問題(15): Typedef</a></p><h3>混淆的語法(Obfuscated syntax)</h3><p><a href="https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-16-a-%E7%9A%84%E5%95%8F%E9%A1%8C-867b66cdc9e1">工程師應知道的0x10個問題(16): a++的問題</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=970cc31f6b76" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[工程師應知道的0x10個問題(16): a++的問題]]></title>
            <link>https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-16-a-%E7%9A%84%E5%95%8F%E9%A1%8C-867b66cdc9e1?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/867b66cdc9e1</guid>
            <category><![CDATA[c-programming]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sat, 26 Mar 2022 15:45:29 GMT</pubDate>
            <atom:updated>2022-03-26T15:45:29.851Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>英文參考網址</blockquote><blockquote><a href="https://rmbconsulting.us/publications/a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers/">A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers</a></blockquote><blockquote>中文參考網址</blockquote><blockquote><a href="https://creteken.pixnet.net/blog/post/24524138">C語言測試 應知道的0x10個基本問題</a></blockquote><h4>原文翻譯</h4><p><em>16. C allows some appalling constructs. Is this construct legal, and if so what does this code do?</em></p><p>C語言允許一些可怕的結構。這個結構合法嗎? 如果合法的話這段程式碼會做什麼?</p><p>int a = 5, b = 7, c;</p><p>c = a+++b;</p><p>This question is intended to be a lighthearted end to the quiz, as, believe it or not, this is perfectly legal syntax. The question is how does the compiler treat it? Those poor compiler writers actually debated this issue, and came up with the “maximum munch” rule, which stipulates that the compiler should bite off as big a (legal) chunk as it can. Hence, this code is treated as:</p><p>這個問題是為這個測驗的一個愉快的結束。不管你相信或不相信，這是個完全的合法語法。這個問題是編譯器如何處理它? 那些不好的編譯器作者實際上爭論這個問題。根據 “maximum munch”規則，明確說明編譯器應該要盡可能地咬掉最大的一個(合法個)chunk。因此，這個程式碼要被處理為:</p><pre>注1: 這裡的came up with the “maximum munch” rule，雖然come up with是提出的意思，中文來源這裡是翻成根據，這邊若翻成根據的話整體文義會順很多，所以這裡採用中文來源的譯法</pre><pre>注2: “maximum munch” rule，這裡在中文來源是翻成最處理原則，這邊如果用google搜尋的話，會出現Maximal munch的維基頁面，而google的機器翻譯是翻成最大匹配度</pre><pre>注3: which stipulates that the compiler should bite off as big a (legal) chunk as it can。這邊我直接直譯成譯器應該要盡可能地咬掉最大的一個(合法個)chunk，而中文來源是翻成: 編譯器應當能處理儘可能所有合法的用法。當然事實上這句話的意思有可能是偏盡可能處理的意味在。</pre><pre>對於這段文字如果讀者認為有更好的譯法的話，歡迎留言跟我說</pre><p>c = a++ + b;</p><p>Thus, after this code is executed, a = 6, b = 7 &amp; c = 12;</p><p>因此，在這個程式碼執行之後，a = 6, b = 7 &amp; c = 12;</p><p>If you knew the answer, or guessed correctly — then well done. If you didn’t know the answer then I would not consider this to be a problem. I find the biggest benefit of this question is that it is very good for stimulating questions on coding styles, the value of code reviews and the benefits of using lint.</p><p>如果你知道這個答案，或者是猜對 — 那做得好。如果你不知道這個答案那麼我不會認為這是一個問題。我發現這個問題的最大益處是這是個非常好的激勵問題在於程式風格，程式碼審查的價值以及使用lint的益處。</p><pre>注1: 文章的lint我想應該是指一種C語言的分析工具，以下文章有對這個工具的簡介<br><a href="https://segmentfault.com/a/1190000040009402">代码的 Lint 是什么意思</a></pre><p>最後這段文字其實與這個問題無關，算是原作者對於這16個嵌入式工程師該應知道的問題所做的一個結尾</p><p>Well folks, there you have it. That was my version of the C test. I hope you had as much fun doing it as I had writing it. If you think the test is a good test, then by all means use it in your recruitment. Who knows, I may get lucky in a year or two and end up being on the receiving end of my own work.</p><p>好的大夥，你已經擁有它了。這是我的版本的C語言測試。我希望你當你在做的時候擁有跟我在寫的時候一樣多的樂趣。如果你認為這個測試是好的測試，那麼當然可以使用它在你的招聘。誰知道呢? 我可能會在一兩年內很幸運但最終我自己工作承受不愉快的事物</p><pre>注: being on the receiving end有承受不愉快事物的意思，所以Who knows, I may get lucky in a year or two and end up being on the receiving end of my own work.這句話這裡我就翻成: 誰知道呢? 我可能會在一兩年內很幸運但最終我自己工作承受不愉快的事物。這裡我想作者在這裡表達的意思應是日無千日好，花無百日紅的感慨，畢竟專業能力是一部分，職場的問題又是另外一部份<br>這邊同樣的如果讀者認為有更好的譯法，歡迎留言跟我說</pre><h4>自我實作以及理解</h4><pre>注1: 以下是我的自我實作以及理解的部分，不保證正確而且很有可能描述不清楚或者是有錯誤，讀者若發現有可以更正的地方也歡迎留言告訴我</pre><pre>注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異</pre><p>這裡我們照著原文宣告a = 6，b = 7，接著讓 c = a+++b。</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f7c17e008aa3b7cf25ef76d4ace250b/href">https://medium.com/media/8f7c17e008aa3b7cf25ef76d4ace250b/href</a></iframe><p>這裡實際上 a會先與b相加，所以是5+7=12，c的數值是12，b的數值不會變是 7，a跟b加完之後，接著會a++，所以a變成6，其實a++就是後做，先運算完之後再++，所以才會5加完7之後，a自身才++變成6</p><p>輸出結果</p><pre>a: 6, b: 7, c: 12</pre><h4>a++與++a</h4><p>a++與++a是個經典的問題，如果我們去google的話大都是寫成i++與++的比較</p><p>以下有兩篇文章讀者可以參考</p><pre><a href="https://www.delftstack.com/zh-tw/howto/c/prefix-vs-posfix-increment-in-c/">C 語言中的 i++ 與++i</a><br><a href="https://stackoverflow.com/questions/24853/what-is-the-difference-between-i-and-i">What is the difference between ++i and i++?</a></pre><p>這裡我們讓 c = a++的話，則c會等於5，接著a++再運算，a變成6</p><p>然後接著我們讓c = ++b，++b會先運算，所以b會等於8，而c當然接收8的數值，所以數值為8</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a0c582a03d1dec43ef3e094b09d96912/href">https://medium.com/media/a0c582a03d1dec43ef3e094b09d96912/href</a></iframe><p>輸出結果</p><pre>a: 6, b: 7, c: 5<br>a: 6, b: 8, c: 8</pre><p>接下來我們試試看 a++或++a這類的型態在printf的輸出強況</p><p>我們一開始先printf(“a: %d\n”, a++);，這時候a還沒有++，所以輸出的數值為5，接著我們再印一次，這時候a已經++過了，所以數值會變成6</p><p>而接著printf(“b: %d\n”, ++b);我們對++b的數值打印出來，這時候b已經++過了，所以數值為8，再印一次b，當然數值也是為8</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3056b715b43ddc65f1608b3e1ac6fa8b/href">https://medium.com/media/3056b715b43ddc65f1608b3e1ac6fa8b/href</a></iframe><p>輸出結果</p><pre>a: 5<br>After a++, a: 6<br>b: 8<br>After ++b: 8</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=867b66cdc9e1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[工程師應知道的0x10個問題(15): Typedef]]></title>
            <link>https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-15-typedef-76151c5b9ec3?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/76151c5b9ec3</guid>
            <category><![CDATA[c-programming]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sat, 26 Mar 2022 11:22:07 GMT</pubDate>
            <atom:updated>2022-03-26T15:21:53.848Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>英文參考網址</blockquote><blockquote><a href="https://rmbconsulting.us/publications/a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers/">A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers</a></blockquote><blockquote>中文參考網址</blockquote><blockquote><a href="https://creteken.pixnet.net/blog/post/24524138">C語言測試 應知道的0x10個基本問題</a></blockquote><p><strong>原文翻譯</strong></p><p><em>15. Typedef is frequently used in C to declare synonyms for pre-existing data types. It is also possible to use the preprocessor to do something similar. For instance, consider the following code fragment:</em></p><p>Typedef 頻繁的在C語言中使用來對之前存在的資料型態宣告為同義詞。這也是有可能的使用預處理器來做相似的事情。舉例來說，考慮下方的程式碼片段:</p><p>#define dPS struct s *</p><p>typedef struct s * tPS;</p><p><em>The intent in both cases is to define dPS and tPS to be pointers to structure s. Which method (if any) is preferred and why?</em></p><p>在這兩個案例的目的是去定義 dPS 與 tPS來當指向結構 s 的指標。哪個方法(如果有的話) 是比較偏向的並且解釋為什麼?</p><p>This is a very subtle question, and anyone that gets it right (for the right reason) is to be congratulated or condemned (“get a life“ springs to mind). The answer is the typedef is preferred. Consider the declarations:</p><p>這是一個非常微妙的問題，而且任何答對這題的人(要有正確的理由)是可以被恭喜或者是譴責(“找點有意思的事“浮現在腦中)。這個答案是 typedef 是比較好的。 思考下面的宣告:</p><pre>注1: This is a very subtle question, and anyone that gets it right (for the right reason) is to be congratulated or condemned(“get a life“ springs to mind).，這裡的condemn單字有是譴責的意思，而後面的括號 get a life 有找點有意思的的意味，sprins to mind 用google翻譯有湧現到心中的意思。總體來說，在condemned後面加上括號(“get a life“ springs to mind)這裡我感覺作者有點開玩笑的意味在說不要太專注於這類的C語言語法。當然開玩笑歸開玩笑，這裡其實我無法得知這單純是一個開玩笑的語氣還是其實這也算是個有用的語法知識。這裡如果讀者有更好的譯法或者對作者這段話有更好的見解，歡迎留言告訴我。</pre><p>dPS p1,p2;</p><p>tPS p3,p4;</p><p>The first expands to</p><p>第一個會被擴展成</p><p>struct s * p1, p2;</p><p>which defines p1 to be a pointer to the structure and p2 to be an actual structure, which is probably not what you wanted. The second example correctly defines p3 &amp; p4 to be pointers.</p><p>定義 p1 會變成指向結構的指標而 p2 會變成一個真正的結構，變成可能不是你想要的。第二個範例正確的定義 p3 &amp; p4 成為指標</p><h4>自我實作以及理解</h4><pre>注1: 以下是我的自我實作以及理解的部分，不保證正確而且很有可能描述不清楚或者是有錯誤，讀者若發現有可以更正的地方也歡迎留言告訴我</pre><pre>注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異</pre><p>這裡我們先宣告一個 struct s，裡面只有一個成員int a，接著我們也照原文中宣告#define dPS struct s * 與 typedef struct s * tPS;，並在主程式中用 struct s宣告了一個 s_data，並將成員 a 設為 5，接著我們也跟著原文一樣宣告了 dPS p1,p2; 與 tPS p3,p4;</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6e222e273f82fe1d1b64d02781d1afed/href">https://medium.com/media/6e222e273f82fe1d1b64d02781d1afed/href</a></iframe><p>我們來做第一個測試，我們讓p1與p2分別指向 s_data，p1 = &amp;s_data;<br> p2 = &amp;s_data;，然後編譯</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9c53f954a969ccb8469f02ed8471c646/href">https://medium.com/media/9c53f954a969ccb8469f02ed8471c646/href</a></iframe><p>編譯完之後我們發現出現錯誤</p><pre>Embedded_system_0x10_issues_0x0f_1.c: In function ‘main’:<br>Embedded_system_0x10_issues_0x0f_1.c:21:10: error: incompatible types when assigning to type ‘struct s’ from type ‘struct s *’<br>   21 |     p2 = &amp;s_data;<br>      |          ^</pre><p>看來 p2 不是指標，接著我們對p2的成員a給予值，然後印出p1的a數值與p2的a數值</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b6f36fd6e9b3426d6a53d4bfb5981eba/href">https://medium.com/media/b6f36fd6e9b3426d6a53d4bfb5981eba/href</a></iframe><p>我們就可以發現輸出結果為p1的成員a為5，p2的成員a為10。所以當我們宣告成: dPS p1,p2，會如原文所說的擴展成這樣 struct s * p1, p2;，p1還是指標，而p2是一個結構變數</p><pre>Value of a in p1: 5<br>Value of a in p2: 10</pre><p>接著我們將 p3 與 p4 指向s_data，發現都能指成功</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bdb124b70433c3e132afeef06beccfc5/href">https://medium.com/media/bdb124b70433c3e132afeef06beccfc5/href</a></iframe><p>接著我們將p3與p4的成員a也都印出來，會發現都是5，tPS p3,p4;這樣宣告確實可以讓p3與p4都是指標</p><p>輸出結果</p><pre>Value of a in p1: 5<br>Value of a in p2: 10<br>Value of a in p3: 5<br>Value of a in p4: 5</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=76151c5b9ec3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[工程師應知道的0x10個問題(14): 動態記憶體配置]]></title>
            <link>https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-14-%E5%8B%95%E6%85%8B%E8%A8%98%E6%86%B6%E9%AB%94%E9%85%8D%E7%BD%AE-d974130fae2f?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/d974130fae2f</guid>
            <category><![CDATA[c-programming]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sat, 19 Mar 2022 17:55:53 GMT</pubDate>
            <atom:updated>2022-03-19T17:55:53.172Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>英文參考網址</blockquote><blockquote><a href="https://rmbconsulting.us/publications/a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers/">A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers</a></blockquote><blockquote>中文參考網址</blockquote><blockquote><a href="https://creteken.pixnet.net/blog/post/24524138">C語言測試 應知道的0x10個基本問題</a></blockquote><h4>原文翻譯</h4><p><em>14. Although not as common as in non-embedded computers, embedded systems still do dynamically allocate memory from the heap. What are the problems with dynamic memory allocation in embedded systems?</em></p><p>雖然在非嵌入式系統上並不常見，嵌入式系統仍然在heap上做動態的配置記憶體。做動態記憶體配置在嵌入式系統上會有什麼問題?</p><p>Here, I expect the user to mention memory fragmentation, problems with garbage collection, variable execution time, etc. This topic has been covered extensively in ESP, mainly by Plauger. His explanations are far more insightful than anything I could offer here, so go and read those back issues! Having lulled the candidate into a sense of false security, I then offer up this tidbit:</p><p>這裡，我預期使用者描述到記憶體碎片，垃圾回收的問題，變數的執行時間等。這些議題已經被Plauger在ESP雜誌上廣泛的涉及。他的解釋遠是更深刻見解的遠超任何我在這裡可以提供的，所以去並且讀這些議題。緩和應試者進入一個虛假安全的感覺後，接著我會提供這個小題目</p><pre>注:原文這邊:<strong>&quot;I then offer up this tidbit&quot;</strong>，因為tidbit有美味小吃或者是小片珍饈的意思，所以這邊我使用中文來源的譯法將tidbit翻成<strong>小題目</strong></pre><p><em>What does the following code fragment output and why?</em></p><p>以下的程式片段輸出是什麼並且為什麼這樣輸出?</p><p>char *ptr;</p><p>if ((ptr = (char *)malloc(0)) == NULL) {</p><p>puts(“Got a null pointer”);</p><p>}</p><p>else {</p><p>puts(“Got a valid pointer”);</p><p>}</p><p>This is a fun question. I stumbled across this only recently, when a colleague of mine inadvertently passed a value of 0 to malloc, and got back a valid pointer! After doing some digging, I discovered that the result of malloc(0) is implementation defined, so that the correct answer is ‘it depends’. I use this to start a discussion on what the interviewee thinks is the correct thing for malloc to do. Getting the right answer here is nowhere near as important as the way you approach the problem and the rationale for your decision.</p><p>這是個有趣的問題。我在最近偶然發現，當一個我的同事不慎的傳入0的數值進入malloc，然後得到一個有效的指標!在做了一些挖掘之後，我發現這個malloc(0)的結果是實作定義的，所以正確的答案是&quot;要看情況&quot;。我使用這個來開啟一個討論來看應試者怎麼思考malloc所做的正確的事情。這裡得到正確的答案並不比你靠近這個問題以及你決定的原理闡述重要。</p><pre>注1:I discovered that the result of malloc(0) is implementation defined, so that the correct answer is ‘it depends’.<br>這裡implementation defined我覺得應該要譯成實作定義的，如果有讀者覺得有更好的譯法歡迎留言告訴我。另外後面的‘it depends’，我查了一下<a href="https://blake0714.pixnet.net/blog/post/44920967">It depends</a>這篇的解說，基本上是要看情況的意思，這裡其實我真的很不懂作者想表達的意思，如果有讀者理解這個作者想表達的意思，歡迎留言告訴我</pre><h4>自我實作以及理解</h4><pre>注1: 以下是我的自我實作以及理解的部分，不保證正確而且很有可能描述不清楚或者是有錯誤，讀者若發現有可以更正的地方也歡迎留言告訴我</pre><pre>注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異</pre><p>我們照著原文刻出以下的程式碼</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/042c1f761bcf7a5a7ed202b71d564bdf/href">https://medium.com/media/042c1f761bcf7a5a7ed202b71d564bdf/href</a></iframe><p>輸出結果為確實可以拿到有效的指標</p><pre>Got a valid pointer</pre><p>網路上搜尋malloc(0)可以得到不同的討論文章，由於我對這方面真的不了解所以我大約找了三個連結，有興趣的讀者也可以搜尋看看各種不同的答案</p><pre>以下兩個是用VC的，不是GCC，不過或許兩者的編譯器在處理這個問題上可能有相近之處<br>1) <a href="https://www.itread01.com/articles/1478587522.html">C語言中關於malloc（0）問題</a><br>2) <a href="https://blog.csdn.net/weibo1230123/article/details/82822698">ptr = (char *)malloc(0)</a><br>這一篇stack overflow就是純討論，似乎沒有限定在哪一個編譯器<br>3) <a href="https://stackoverflow.com/questions/2022335/whats-the-point-of-malloc0">What&#39;s the point of malloc(0)?</a></pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d974130fae2f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[工程師應知道的0x10個問題(13): 0的一補數]]></title>
            <link>https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-13-0%E7%9A%84%E4%B8%80%E8%A3%9C%E6%95%B8-4362a9c81423?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/4362a9c81423</guid>
            <category><![CDATA[c-programming]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sat, 19 Mar 2022 16:45:44 GMT</pubDate>
            <atom:updated>2022-03-19T16:45:44.052Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>英文參考網址</blockquote><blockquote><a href="https://rmbconsulting.us/publications/a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers/">A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers</a></blockquote><blockquote>中文參考網址</blockquote><blockquote><a href="https://creteken.pixnet.net/blog/post/24524138">C語言測試 應知道的0x10個基本問題</a></blockquote><h4>原文翻譯</h4><p><em>13. Comment on the following code fragment?</em></p><p>評論以下的程式碼片段?</p><p>unsigned int zero = 0;</p><p>unsigned int compzero = 0xFFFF; /*1’s complement of zero */</p><p>On machines where an int is not 16 bits, this will be incorrect. It should be coded:</p><p>當一個機器不是16位元的，這個會導致錯誤。它應該被寫成這樣:</p><p>unsigned int compzero = ~0;</p><p>This question really gets to whether the candidate understands the importance of word length on a computer. In my experience, good embedded programmers are critically aware of the underlying hardware and its limitations, whereas computer programmers tend to dismiss the hardware as a necessary annoyance.</p><p>這個問題真的可以知道應試者是否了解字組長度在電腦的重要性。在我的經驗中，好的嵌入式程式設計師會嚴謹的知道硬體的細節與它的限制，然後電腦程式設計師傾向忽視硬體並把它視為一個必要的煩擾。</p><pre>注1: 這裡的the underlying hardware我覺得中文來源翻得蠻好的，因為underlying本身有基本的與潛在的意思在，中文來源翻成硬體的細節我覺得是個好的翻法故在此採用</pre><pre>注2: dismiss the hardware as a necessary annoyance這裡中文來源翻成<strong>&quot;然而PC機程式往往把硬體作為一個無法避免的煩惱&quot;</strong>，但是dismiss本身有忽視的意思在，所以我這邊會傾向翻成忽視硬體並把硬體視為一個必要的煩惱，這裡如果讀者覺得有更好的譯法，歡迎再留言跟我說</pre><p>By this stage, candidates are either completely demoralized — or they are on a roll and having a good time. If it is obvious that the candidate isn’t very good, then the test is terminated at this point. However, if the candidate is doing well, then I throw in these supplemental questions. These questions are hard, and I expect that only the very best candidates will do well on them. In posing these questions, I’m looking more at the way the candidate tackles the problems, rather than the answers. Anyway, have fun…</p><p>到了這個階段，應試者會完全的沮喪我或者是連連獲勝以及有個好時光。如果明顯的應試者不是非常好，那麼這個測驗將在這裡結束。然而，如果應試者做得好，那麼我將丟出這些追加的問題。這些問題算難，而且我預期只有非常好的應試者會做好它們。提出這些問題後，我更側重的是應試者處理這些問題，而不是答案。不管怎樣，玩得開心…</p><h4>自我實作以及理解</h4><pre>注1: 以下是我的自我實作以及理解的部分，不保證正確而且很有可能描述不清楚或者是有錯誤，讀者若發現有可以更正的地方也歡迎留言告訴我</pre><pre>注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異</pre><p>原文中compzero被設為0xFFFF，但是事實上機器有可能不是16位元</p><pre>unsigned int compzero = 0xFFFF;</pre><p>像我這邊用的是64位元系統，int為32位元，我們用以下程式碼執行過後可以發現</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/53a6109243fcb7287744d1ccca156047/href">https://medium.com/media/53a6109243fcb7287744d1ccca156047/href</a></iframe><p>輸出結果我們可以看到在Ubuntu 64位元的系統上，我們可以發現0的一補數其實是0xffffffff，而不是0xfffff，所以要得到正確的一補數，用~0是個安全的做法</p><pre>copmzero: ffff<br>compzero_with_tilde: ffffffff</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4362a9c81423" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[工程師應知道的0x10個問題(12): 整型提升的問題]]></title>
            <link>https://medium.com/@racktar7743/%E5%B7%A5%E7%A8%8B%E5%B8%AB%E6%87%89%E7%9F%A5%E9%81%93%E7%9A%840x10%E5%80%8B%E5%95%8F%E9%A1%8C-12-%E7%A8%8B%E5%BC%8F%E7%AF%84%E4%BE%8B-b1fdb1cf7e2b?source=rss-17111659ec5a------2</link>
            <guid isPermaLink="false">https://medium.com/p/b1fdb1cf7e2b</guid>
            <category><![CDATA[c-programming]]></category>
            <dc:creator><![CDATA[MuLong PuYang]]></dc:creator>
            <pubDate>Sat, 12 Mar 2022 08:20:44 GMT</pubDate>
            <atom:updated>2022-03-12T08:25:47.749Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>英文參考網址</blockquote><blockquote><a href="https://rmbconsulting.us/publications/a-c-test-the-0x10-best-questions-for-would-be-embedded-programmers/">A ‘C’ Test: The 0x10 Best Questions for Would-be Embedded Programmers</a></blockquote><blockquote>中文參考網址</blockquote><blockquote><a href="https://creteken.pixnet.net/blog/post/24524138">C語言測試 應知道的0x10個基本問題</a></blockquote><h4>原文翻譯</h4><p><em>12. What does the following code output and why?</em></p><p>你認為下方的程式碼將會輸出什麼並且為什麼會這樣輸出?</p><p>void foo(void)</p><p>{</p><p>unsigned int a = 6;</p><p>int b = -20;</p><p>(a+b &gt; 6) ? puts(“&gt; 6”) : puts(“&lt;= 6”);</p><p>}</p><p>This question tests whether you understand the integer promotion rules in C — an area that I find is very poorly understood by many developers. Anyway, the answer is that this outputs “&gt; 6”. The reason for this is that expressions involving signed and unsigned types have all operands promoted to unsigned types. Thus –20 becomes a very large positive integer and the expression evaluates to greater than 6. This is a very important point in embedded systems where unsigned data types should be used frequently (see reference 2). If you get this one wrong, then you are perilously close to not being hired.</p><p>這個問題測試你是否了C語言的解整型提升規則 — 一個我發覺很多開發者都不太了解的領域。不管怎樣，這個答案會輸出“&gt; 6”。這個原因是因為這個有著singed與unsinged型態的表達式所有的運算元被提升為unsigned型態。因此–20變成了一個非常大的正整數並且這個表達式計算出大於6。這是個在嵌入式系統非常重要的點因為unsigned的資料型態應該會被頻繁的使用(看參考2)。如果你答錯了這一題，那麼你已經危險的靠近無法聘僱的邊緣。</p><pre>注1: integer promotion可以參考以下的維基頁面<br><a href="https://zh.wikipedia.org/wiki/%E6%95%B4%E5%9E%8B%E6%8F%90%E5%8D%87">整型提升</a><br>注2: Reference 2在英文來源裡是以下這個<br>2. Efficient C Code for Eight-Bit MCUs. ESP November 1988</pre><h4>自我實作以及理解</h4><pre>注1: 以下是我的自我實作以及理解的部分，不保證正確而且很有可能描述不清楚或者是有錯誤，讀者若發現有可以更正的地方也歡迎留言告訴我注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異</pre><pre>注2: 以下皆簡單的使用Ubuntu 20.04虛擬機做測試，並非真實的嵌入式系統，所以Ubuntu 20.04出來的成果可能會與嵌入式系統上的有差異</pre><p>這裡我們直接照著原文來看結果會是怎樣，是否都被提升為unsigned int</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5800d7e9b5d711e127ee4d9305ddc98f/href">https://medium.com/media/5800d7e9b5d711e127ee4d9305ddc98f/href</a></iframe><p>輸出結果真 &gt; 6，所以確實都被提升為正整數</p><pre>&gt; 6</pre><p>我們再多測一個項目，這裡我們將a改為整數，設成20，將b改成unsigned int，設成-30</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ece39f127b6ebe053b0238a98230169c/href">https://medium.com/media/ece39f127b6ebe053b0238a98230169c/href</a></iframe><p>輸出結果為 &gt; 20，代表確實都被設為正整數</p><pre>&gt; 20</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b1fdb1cf7e2b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>