<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="/blog/" rel="alternate" type="text/html" /><updated>2023-12-21T14:15:14+08:00</updated><id>/blog/feed.xml</id><title type="html">Fumitsuki’s magic box</title><subtitle>keep calm and eat eight Plates.</subtitle><entry><title type="html">RubyConf Taiwan 2023 心得</title><link href="/blog/ruby-conf-2023" rel="alternate" type="text/html" title="RubyConf Taiwan 2023 心得" /><published>2023-12-18T17:00:00+08:00</published><updated>2023-12-18T17:00:00+08:00</updated><id>/blog/ruby-conf-2023</id><content type="html" xml:base="/blog/ruby-conf-2023">&lt;p&gt;上次的實體 RubyConf 是在 2019，今年久違的舉辦了實體研討會。過了四年，除了我的工作經驗讓心境有很大的不同，台灣的 Ruby 社群圈也有非常大的變化。
手上沒有實際上的統計數據，但從參加的感受上會覺得台灣的參與者減少了許多，外國的參與者倒是增加了。外國會眾之所以會這麼多，是各方努力讓台灣的能見度變高了嗎（誤）&lt;/p&gt;

&lt;p&gt;關於台灣會眾萎縮的部分，我覺得有點小小的擔心。在這幾年我待過的公司裡，有兩家都在「有 Rails 祖產(X)專案(O)但是希望可以替換他」的狀況，原因大概有兩個，第一個是覺得 Rails 在越長越龐大的時候維護變得複雜而困難，這個部分相當感同身受。今年的議程「Rethink Rails Architecture」也有在討論這部分的議題。&lt;/p&gt;

&lt;p&gt;第二個原因則是覺得市場上的 Ruby 開發人員不夠，就算有也太 junior。但這就有點陷入惡性循環的感覺，公司覺得沒有 Ruby 工程師選擇換 tech stack，Ruby 工程師覺得沒有工作機會選擇換 tech stack，陷入沒有雞就沒有蛋、沒有蛋就沒有雞的情況中XD&lt;/p&gt;

&lt;p&gt;所幸大家還是把 L405 填滿了（感動）&lt;/p&gt;

&lt;p&gt;在開場 Matz 的 Keynote 中，Matz 大大也提到，Ruby 也 30 歲了，不再是一個閃亮亮的語言（也沒有一個程式語言可以永遠閃亮），但是他持續為這個世界創造價值。而 Matz 問道「第一次來 RubyConf 的人有哪些？」台下舉手的人們，正是這個社群的希望。&lt;/p&gt;

&lt;p&gt;關於台灣的 Ruby 圈欠缺 senior 的議題，在 official party 時跟其他講者、會眾們討論時，覺得聽到一個很棒的觀點：「沒有人從一開始就是 senior」比起抱怨市場上沒有 senior，不如自己創造 senior。
Okura Masafumi 桑在日本辦了 &lt;a href=&quot;https://growrb.doorkeeper.jp/events/past&quot;&gt;Grow.rb&lt;/a&gt; 的活動，每次的主題讓大家試著自己實作平常在用的 Data、Struct 等等，讓參與者從這些實作中學到 Ruby 的技巧與精髓。這次的議程「&lt;a href=&quot;https://speakerdeck.com/okuramasafumi/writing-minitest-clone-in-30-minutes&quot;&gt;Writing Minitest clone in 30 minutes&lt;/a&gt;」也是透過 30 分鐘 live coding，帶大家寫一個自己的 Minitest。
覺得這個部分也帶給了我許多啟發，未來台灣 Ruby 社群還有很多有趣的事情可以做。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-minitest.jpg&quot; alt=&quot;Minitest 實作 live coding&quot; /&gt;&lt;/p&gt;

&lt;p&gt;和朋朋們也討論到現代人學習新事物的方式正在變化。從疫情以來不只是 Ruby 社群圈，其他社群圈也在面對社群萎縮、參加研討會的人變少的窘況。有可能新一代的人們更常看線上課程、youtube 頻道、抖音來學習新知。而實體的研討會不見得對這些人來說有吸引力。但我自己覺得實體研討會的互動交流是無可取代的，一方面聽到許多我沒有碰過的領域（eg. Ruby Parser）的議程，都讓我覺得 Ruby 圈有這些人做這些有趣的事情真是太好了。也對於其中一些領域想要做看看 side project （PicoRuby 好像很好玩！），躍躍欲試。另一方面，我也在互動中真實地感受到「The Ruby community is the most precious treasure」這句話，因為有大家的存在，Ruby 圈才有源源不絕的活力繼續往前走。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-treasure.jpg&quot; alt=&quot;The Ruby community is the most precious treasure&quot; /&gt;&lt;/p&gt;

&lt;p&gt;image from &lt;a href=&quot;https://twitter.com/hasumikin/status/1735914984906101140/photo/1&quot;&gt;hasumikin@twitter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不過這幾年直播等等的開始越來越盛行了，是不是應該要弄個台 V 紅寶石娘之類的推廣 Ruby 呀（腦洞大開）&lt;/p&gt;

&lt;p&gt;另外過程中也跟其他會眾討論起了為什麼喜歡 Ruby、非 Ruby 不可的理由。某方面來說，我覺得喜歡 Ruby 的人們也是有著相當偏執的一面XD
那時候也有聽到一個會眾說，大部分的語言很安全，就像是在限制小朋友似的告訴開發者「不可以這樣」「Type 要好好發樓！」。
但是 Ruby 卻是把開發者當成充分具有自由與責任的大人，在 Ruby 的世界裡沒有這麼多限制，讓我們充滿發揮空間，但是我們同樣也有義務要用適當的方式去使用 Ruby 給我們的自由。Ruby 不只是一個無機的工具，而是能夠帶給開發者快樂的朋友。比方說 Ruby 就很適合拿來做 quine（自產生程式）XD&lt;/p&gt;

&lt;p&gt;其中日本有一個很厲害的 mame 桑非常擅長做 quine，覺得相當厲害&amp;gt;&amp;lt;”&lt;/p&gt;

&lt;p&gt;附幾個 mame 桑的 quine：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mame/all-ruby-quine&quot;&gt;https://github.com/mame/all-ruby-quine&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tric/trick2022/blob/master/06-mame/entry.rb&quot;&gt;https://github.com/tric/trick2022/blob/master/06-mame/entry.rb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;真的非常厲害哪XD&lt;/p&gt;

&lt;h2 id=&quot;畫面集錦&quot;&gt;畫面集錦&lt;/h2&gt;

&lt;p&gt;今年有松江市的官員（？）來宣傳松江市，台北市產發局也有人來致詞。第一次知道原來台北市跟松江市有備忘錄，還有建國花市會有來自松江市牡丹花展出XD
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-matsue.jpg&quot; alt=&quot;松江市工商&quot; /&gt;&lt;/p&gt;

&lt;p&gt;開場 Keynote 的結論，為了避免 boring pitfall，語言要一直前進。但同時也不能整個打掉重練，版本之間欠缺相容性的話會分裂社群（反觀隔壁 P 開頭語言？）
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-matz-conclusion.jpg&quot; alt=&quot;Matz 30 years of Ruby 結論&quot; /&gt;&lt;/p&gt;

&lt;p&gt;中午在活動中心二樓吃便當，總覺得漢字序順不影響讀閱呢XD
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-garbage-can.jpg&quot; alt=&quot;活動中心二樓的垃圾桶&quot; /&gt;&lt;/p&gt;

&lt;p&gt;4 年前講者帶來了跑在 Dreamcast 上的 mruby 程式，今年又加上了 Wii support！
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-mruby-wii.jpg&quot; alt=&quot;Wii Support of MRuby&quot; /&gt;&lt;/p&gt;

&lt;p&gt;來自永和システムマネジメント的工程師似乎對於看到永和非常開心XD
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-yonghue.jpg&quot; alt=&quot;永和！&quot; /&gt;&lt;/p&gt;

&lt;p&gt;星際大戰風格的投影片
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-pico-ruby.jpg&quot; alt=&quot;PicoRuby 之於星際大戰&quot; /&gt;&lt;/p&gt;

&lt;p&gt;非常棒的現場 Demo！雖然由於中途一些小事故沒辦法看到完整的 Production Ready 實作 &amp;gt;&amp;lt;”
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-pico-ruby-demo.jpg&quot; alt=&quot;PicoRuby Demo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;LLM 做小遊戲，要想辦法搞定保全的闖入建築物，非常有趣的 Demo！
雖然 LLM 很厲害，但是沒有加諸處理與約束的話很可能會在玩家玩遊戲的途中開始出戲XD
怎麼用做好約束也是很有趣的議題&amp;gt;&amp;lt;”
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-llm-game.jpg&quot; alt=&quot;用 LLM 做的遊戲&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The forgotten web 帶大家走過一遍 web development 發展史，從 Web Master 開始職責越分越細
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-forgotten-web.jpg&quot; alt=&quot;Developer 發展史&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Tim 大大的 ending keymote 非常棒！整個議程的安排跟美術都很用心（已被圈粉XD）
用非常有趣的方式介紹 Ruby 工程師如何從好的開發方式、團隊合作擊敗 bugs 並持續前進。
對於 Tim 大大提到的 Hanami2 features 也非常有興趣，覺得職責分離設計的很精巧
&lt;img src=&quot;/blog/assets/images/rubyconftw-2023-tim-riley-journey.jpg&quot; alt=&quot;Tim Riley 的 ending keynote&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;其他部分&quot;&gt;其他部分&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;整體來說這次認識好多新朋友，跟好多人都有聊到天，非常開心！這次和國外講者聊天深感英文會話的重要！能夠用英文對話的話多了很多可以互動的對象。從外國會眾中的交談取得許多靈感！&lt;/li&gt;
  &lt;li&gt;有時候日本會眾蹦出日文的時候好像大概只能聽懂三成至七成，還是有點難理解跟會話呢…是不是也要來學日文了呢XD&lt;/li&gt;
  &lt;li&gt;看到國外會眾到台北各處觀光、吃東西覺得很有趣XD 有時候也會有會眾問「推薦去哪裡呢？」「推薦買什麼伴手禮回家？」頓時發現自己也滿不知道台北有什麼有趣的地方好去的。可惡啊下次要準備好清單推薦好推薦滿XD&lt;/li&gt;
  &lt;li&gt;意外發現台灣茶好像對日本會眾接受度很高，下次多帶幾包來推廣（欸） 也有喜歡咖啡的國外會眾，推銷台灣咖啡機不可失！&lt;/li&gt;
  &lt;li&gt;再度參加 RubyKaraoke，覺得聽到許多有趣的歌，其中「みかんのうた」讓人印象深刻&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;這次研討會玩得相當開心，也讓人有一種充電了可以繼續前進的感覺，非常希望還可以一直有 RubyConf 可以參加 &amp;gt;&amp;lt;”&lt;/p&gt;</content><author><name>文月</name></author><category term="rubyconf" /><category term="rubyconf" /><category term="community" /><summary type="html">上次的實體 RubyConf 是在 2019，今年久違的舉辦了實體研討會。過了四年，除了我的工作經驗讓心境有很大的不同，台灣的 Ruby 社群圈也有非常大的變化。 手上沒有實際上的統計數據，但從參加的感受上會覺得台灣的參與者減少了許多，外國的參與者倒是增加了。外國會眾之所以會這麼多，是各方努力讓台灣的能見度變高了嗎（誤）</summary></entry><entry><title type="html">2023 南港茶酒咖啡展紀行</title><link href="/blog/int-coffee-expo-2023" rel="alternate" type="text/html" title="2023 南港茶酒咖啡展紀行" /><published>2023-11-19T04:00:00+08:00</published><updated>2023-11-19T04:00:00+08:00</updated><id>/blog/int-coffee-expo-2023</id><content type="html" xml:base="/blog/int-coffee-expo-2023">&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2023-coffee-expo1.jpg&quot; alt=&quot;戰利品&quot; /&gt;&lt;/p&gt;

&lt;p&gt;忘記我第一年去茶酒咖啡展是哪一年的事情（似乎是 2017 年的樣子），應該是因為公館 1:12 咖啡的老闆的推薦才去茶酒咖啡展逛逛。&lt;/p&gt;

&lt;p&gt;前幾年去的時候發生了各式各樣有趣的事情，在圓石攤位瘋狂蹭翡翠莊園藝妓跟 Ninety plus，買了麻布工坊用咖啡麻袋做的包包，體驗到杯測活動，遇到藝妓村莊園主…&lt;/p&gt;

&lt;p&gt;另外這幾年前前後後也添購了好多設備，在咖啡展搬了定溫壺跟小富士回家。&lt;/p&gt;

&lt;p&gt;除此之外，也看著台灣精品咖啡區冒出，現在發展得越來越大。以前說到台灣精品咖啡大家只知道鄒築園，到現在阿里山山脈東西南北都有實力強大的咖啡莊園，用絕妙的風味擄獲大家的心。而各縣市也都開始有越來越大的咖啡種植面積。今年也發現越來越多莊園都有藝伎種植，大部分現在風味都還是太過稚嫩青澀，接下來也會越來越好喝。&lt;/p&gt;

&lt;h2 id=&quot;咖啡展&quot;&gt;咖啡展&lt;/h2&gt;

&lt;p&gt;以往展場都只有在一館兩層樓，這次規模更大了，一二館都有展場分佈，咖啡展直接佔據二館的一樓跟四樓。感覺台灣咖啡發展得越加蓬勃成熟了，但也小小的擔心未來是不是會有衰退期的到來。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2023-coffee-expo2.png&quot; alt=&quot;咖啡展四樓樓層簡介&quot; /&gt;&lt;/p&gt;

&lt;p&gt;早上一開始先直衝四樓台灣咖啡區，喝到很喜歡的是台南東山的大鋤花間，除此之外還有印象深刻，並且一直推銷朋友喝喝的科子林！&lt;/p&gt;

&lt;p&gt;科子林的 SL34 水洗跟 SL34 日曬都很棒。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/2023-coffee-expo3.jpg&quot; alt=&quot;科子林咖啡莊園攤位&quot; /&gt;&lt;/p&gt;

&lt;p&gt;後來有買青葉的蜜處理，覺得想要來點甜感。&lt;/p&gt;

&lt;p&gt;接著逛逛看看非台灣產區的咖啡豆，這次第一次看到彰化的簡豆咖啡，試喝了墨西哥阿里歐（我應該沒記錯 🤔）是很棒的熱帶水果風味，聽老闆說沖泡已經拉到 1:18 了，卻還是濃郁水果味襲來，可感其味道之強烈。很少喝到墨西哥咖啡，這也是令我印象深刻的一隻。&lt;/p&gt;

&lt;p&gt;中午午餐吃可可區的巧克哈克做的咖哩牛腩飯。可能因為咖哩加了巧克力，比較沒有辛辣的味道，只留下香料的氣味。巧克力料理蠻有趣的呢。&lt;/p&gt;

&lt;h2 id=&quot;茶業展&quot;&gt;茶業展&lt;/h2&gt;

&lt;p&gt;下午到一館買了茶葉跟茶具。雖然身為每天都必須喝茶才會感到心神安寧的族群，但我沒什麼跟茶莊買過茶。茶業展的攤位每攤前面都是可以坐下來聊天的座位，反而讓我覺得有點卻步XD&lt;/p&gt;

&lt;p&gt;鼓起勇氣（？）到攤位上是著品茶買茶，發現我還真的不知道該怎麼買茶XD&lt;/p&gt;

&lt;p&gt;「你要買什麼價位的，你要一斤 500 還是一斤 2000 我們都有。」&lt;/p&gt;

&lt;p&gt;一斤？一斤是多少我一點概念也沒有XD 後來回去才回想起來一台斤是 600 克。&lt;/p&gt;

&lt;p&gt;我指著桌上的茶葉包裝：「我要像這種的。」&lt;/p&gt;

&lt;p&gt;「喔，那是四兩。」老闆說道。&lt;/p&gt;

&lt;p&gt;兩？兩又是什麼？頓時腦袋一片空白。回去想想成語「半斤八兩」似乎是個一斤 = 十六兩的提示。&lt;/p&gt;

&lt;p&gt;「你是要送禮還是自己喝？平常在喝哪一種的茶？」老闆繼續問。&lt;/p&gt;

&lt;p&gt;我只知道我家好像有一些東方美人、一些包種，還有一些杉林溪烏龍等等，我都會喝。這次想買那種清香、口感比較淡比較甘甜的高山茶，卻不知道怎麼回答他才不會貽笑大方。&lt;/p&gt;

&lt;p&gt;我在另一間製茶廠試茶的時候也是腦袋一片空白、講得支支吾吾，老闆還忍不住問我你是不是學生嗎，總覺得行為舉止很青澀呀。看著旁邊來試茶的另一個客人，好像很有經驗的樣子，看起來更知道關於茶要問些什麼，像是這是冬茶嗎、海拔多少…我喝茶的時候也是沒在注意這些。頓時覺得我還是來做點功課好了。&lt;/p&gt;

&lt;p&gt;除此之外，從來沒有買過茶壺的我，買了第一把手捏柴燒茶壺，是個有點南瓜又有點茶壺的形狀。老師其實做了很多惟妙惟肖的仿生茶具，但我有點想說怎麼捨得拿來用，要是縫縫沒洗乾淨生細菌我會哭吧，所以第一把壺還是買了比較樸素的款式。壺蓋的密合度做得很好，唯一小困擾是茶壺在很滿的時候倒茶還是會壺嘴流口水（這是不是很難避免呀）但整體來說感覺都很棒。&lt;/p&gt;

&lt;h2 id=&quot;其他部分&quot;&gt;其他部分&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;二館的 1 樓跟 4 樓之間的移動，除了外側手扶梯以外，還有開放展場內搭乘貨梯。貨梯好大，感覺可以停個兩輛一般轎車。&lt;/li&gt;
  &lt;li&gt;在歐客佬看到要價 8888 台幣的翡翠莊園競標藝妓生豆禮盒，真是高級夢幻逸品呀。另外歐客佬攤位賣的可頌超香超誘人，雖然沒有不小心敗下去，但覺得香氣太邪惡逼人了。&lt;/li&gt;
  &lt;li&gt;在四樓是喝到無乳糖鮮奶，覺得相當好喝，馬上被圈粉。雖然攤位上的人說全聯也買得到，但我在全聯一次也沒看過，是我家附近的全聯太小間嗎？&lt;/li&gt;
  &lt;li&gt;這次也試吃了台灣巧克力，覺得非常好吃，像水果的酸味和以往吃過得巧克力都不同。以前吃的巧克力都是 % 數越高越苦，台灣巧克力卻是 % 數越高越有酸味。這次還有吃到咖啡展主題的咖啡巧克力，非常特別。&lt;/li&gt;
  &lt;li&gt;友人 aka. 京都念慈菴大戶好像買到銷售人員龍心大悅（咦） 拿到小山一樣多的試吃包跟許多華國美學美感的月曆，我也被硬塞了幾個。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;逛展心滿意足，期待著明年茶酒咖啡展的到來。&lt;/p&gt;</content><author><name>文月</name></author><category term="coffee" /><category term="coffee" /><category term="tea" /><summary type="html">前言</summary></entry><entry><title type="html">關於在 Ruby 中 unicode string 切成指定 bytes</title><link href="/blog/slice-uincode-string-to-bytes" rel="alternate" type="text/html" title="關於在 Ruby 中 unicode string 切成指定 bytes" /><published>2023-04-25T21:00:00+08:00</published><updated>2023-04-25T21:00:00+08:00</updated><id>/blog/slice-uincode-string-to-bytes</id><content type="html" xml:base="/blog/slice-uincode-string-to-bytes">&lt;p&gt;在 Ruby 裡面如果要把字串切成最接近且小於 N bytes，大家可能會看到網路上提到 &lt;a href=&quot;https://www.rubydoc.info/stdlib/core/String:byteslice&quot;&gt;byteslice&lt;/a&gt; 這個 method。但是 byteslice 是沒在管 encoding 的，例如我想切一個 utf8 string，有機會切出 invalid characters。&lt;/p&gt;

&lt;p&gt;我用 byteslice 來把 string 切成 9 bytes，先來切字串 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;跳摟下殺價&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'跳摟下殺價'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;byteslice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &quot;跳摟下&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;結果看起來非常正常。接著改切 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;限時9折起&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'限時9折起'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;byteslice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &quot;限時9\xE6\x8A&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;折&lt;/code&gt;直接被切爛了。為什麼會這樣呢？&lt;/p&gt;

&lt;p&gt;utf8 每個字元的 byte 長度從 1 byte 到 4 bytes 不等，絕大多數的中文字是 3 bytes。在全部的字元都是漢字的時候切 3 倍數的 bytes 數可能不會注意到問題。但 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;限時9折起&lt;/code&gt; 中出現了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9&lt;/code&gt; 這個只有 1 byte 長度的字串，才導致&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;折&lt;/code&gt;被切一半。&lt;/p&gt;

&lt;p&gt;有一種做法是，把 byteslice 切完以後尾巴切爛的字元清除，透過 &lt;a href=&quot;https://www.rubydoc.info/stdlib/core/String:valid_encoding%3F&quot;&gt;valid_encoding?&lt;/a&gt; 可以去檢查每個字元是不是 valid 的字元。&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;byteslice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:valid_encoding?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;或者是計算過到最接近 n byte 的字元時的 bytesize 後再來做 bytesclice&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;largest_valid_bytesize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bytesize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bytesize&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;byteslice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;largest_valid_bytesize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果是 Rails 的話，Rails 當中直接有 &lt;a href=&quot;https://api.rubyonrails.org/classes/ActiveSupport/Multibyte/Chars.html&quot;&gt;ActiveSupport::Multibyte::Chars&lt;/a&gt; 可以讓操作者不用理解 encoding 也能安全地對他們做操作。&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mb_chars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Rails 真的是什麼都有呢。&lt;/p&gt;</content><author><name>文月</name></author><category term="ruby" /><category term="ruby" /><category term="rails" /><summary type="html">在 Ruby 裡面如果要把字串切成最接近且小於 N bytes，大家可能會看到網路上提到 byteslice 這個 method。但是 byteslice 是沒在管 encoding 的，例如我想切一個 utf8 string，有機會切出 invalid characters。</summary></entry><entry><title type="html">關於生成式 AI 的心情雜談</title><link href="/blog/about-ai" rel="alternate" type="text/html" title="關於生成式 AI 的心情雜談" /><published>2023-03-24T06:30:00+08:00</published><updated>2023-03-24T06:30:00+08:00</updated><id>/blog/about-ai</id><content type="html" xml:base="/blog/about-ai">&lt;h3 id=&quot;被-ai-嚇到的世界&quot;&gt;被 AI 嚇到的世界&lt;/h3&gt;

&lt;p&gt;從去年迸出一堆 AI 產圖，以及 chatGPT 推出以來，覺得大家對未來的想像產生天翻地覆的改變。&lt;/p&gt;

&lt;p&gt;以前的我一直覺得 AI 只不過是個拿來炒作的 buzzword，看虛擬實境、元宇宙等等的被炒得這麼兇，結果雷聲大雨點小，就覺得那些宣稱拿 AI 做 OO 做 XX 的說不定背後都是外包給便宜印度人工人智慧而已。&lt;/p&gt;

&lt;p&gt;但 chatGPT 完全讓人看到新的威脅與新的機會。雖然 GPT-3 聊起來數學很爛又愛瞎扯，但他產出人類買單的內容的能力真的非常強，有些我們以為是「智力密集」或是有門檻的事情，突然變得容易了。像是寫 code、翻譯等等，chatGPT 都可以給人很不錯的回覆。&lt;/p&gt;

&lt;p&gt;心底真的覺得，天啊！未來寫 code 這行飯，大概是會變難吃 XD （difficult 的難吃而非 tastes bad XD）&lt;/p&gt;

&lt;h3 id=&quot;未來的工程師環境想像&quot;&gt;未來的工程師環境想像&lt;/h3&gt;

&lt;p&gt;現在感受下來，如果善用生成式 AI 工具，像是網頁後端開發、DevOps 之類的一些工作都會變容易。對有經驗者來說很多程式可以透過 AI 產生再來檢驗修正，開發時間會縮短，產能隨之提升。對於入門者來說，AI 可以帶著自己學習不會的工具，甚至一步一步帶領自己寫出想寫的功能。&lt;/p&gt;

&lt;p&gt;就上面的敘述來說，自己覺得未來的工程師環境說不定會有底下的變化：&lt;/p&gt;

&lt;h4 id=&quot;1利用工具增加產能變成工作門檻&quot;&gt;1.「利用工具增加產能」變成工作門檻：&lt;/h4&gt;

&lt;p&gt;當工具可以讓一個工程師當兩、三個人用的時候，沒辦法當兩個人用的人在就業市場上就會岌岌可危。&lt;/p&gt;

&lt;p&gt;舉例來說，如果同一個功能，員工甲不打算用任何生成式 AI 工具，總是獨自寫完功能，翻文件翻半天才把東西寫出來，跟員工乙善用工具產出再修正調整成可以用的 code。員工甲跟員工乙的產能可能會有非常大的差距，這個差距可能大到公司沒辦法接受員工甲的效率。&lt;/p&gt;

&lt;p&gt;當工具可以榨出更多的人力，榨不出這個產能來就會很有問題。這讓我蠻警惕的，讓我開始要求自己從現在開始就要多試試看像是 GitHub Copilot 之類的工具，還有多問問 ChatGPT 問題，學習怎麼下咒語得到自己需要的東西。&lt;/p&gt;

&lt;h4 id=&quot;2理解與檢驗能力變得重要&quot;&gt;2.理解與檢驗能力變得重要：&lt;/h4&gt;

&lt;p&gt;覺得有硬底子固然很好，但未來可能懂得透過 AI 學習理解會比成為一個知識豐富的人更有優勢。因此，理解能力的重要性就大大增加了。說不定未來的面試，比起越問越刁鑽來證明一個人的實力，記得這些人各種知識記得清不清楚，會更重視丟出不會的東西時能不能迅速理解、找到解方。&lt;/p&gt;

&lt;p&gt;再來檢驗 AI 給的東西有沒有問題也很重要。現在用 GPT-3 問問題，還是真假參半，例如常常會拿到一段大致上可以用的 code，但裡面有幾個 method 是 chatGPT 捏造出來的之類的。AI 給出來的資訊不一定正確的狀況下，辨別能力就變得相當重要。&lt;/p&gt;

&lt;h4 id=&quot;3產生新的鄙視鏈咦&quot;&gt;3.產生新的鄙視鏈（咦&lt;/h4&gt;

&lt;p&gt;現在我就已經覺得工程師鄙視鏈蠻嚴重的，例如本科歧視非本科，自學仔歧視上課仔等等。未來從碰 AI 開始入門寫程式的人們跟本來就從事這個產業的工程師，可能又會開始有互看不順眼的相輕行為也說不定。&lt;/p&gt;

&lt;p&gt;至於會不會被 AI 取代，我覺得可能 ChatGPT 出現以後各行各業都擔心了起來。程式能力如此厲害的 ChatGPT 應該也讓許多工程師感受到了威脅。我自己覺得應該會讓這個行業出現很大的變化，有可能以後不在需要這麼多開發人力，我預期是薪資跟環境會變嚴峻。只能多保持學習新知，讓自己有競爭力跟價值XD&lt;/p&gt;</content><author><name>文月</name></author><category term="ai" /><category term="ai" /><summary type="html">被 AI 嚇到的世界</summary></entry><entry><title type="html">好淺好淺的談談訊息驗證碼 MAC</title><link href="/blog/message-authentication-code" rel="alternate" type="text/html" title="好淺好淺的談談訊息驗證碼 MAC" /><published>2022-09-23T00:00:00+08:00</published><updated>2022-09-23T00:00:00+08:00</updated><id>/blog/message-authentication-code</id><content type="html" xml:base="/blog/message-authentication-code">&lt;h2 id=&quot;前言閒聊&quot;&gt;前言閒聊&lt;/h2&gt;
&lt;p&gt;在串各種金流交易的時候，常常會聽到 MAC 跟 HMAC。以前第一次聽到的時候不知道 MAC 是什麼、HMAC 跟 MAC 差異在哪裡，直接問同事說「MAC 是什麼啊？」，結果被同事鄙視（誤）了一番。同事一邊說著「你不會查 wiki 嗎？」一邊翻了 wiki 頁面給我，結果他打開的是「Minimum Alveolar Concentration」的頁面（最小肺泡分壓之類的，我也不太清楚）。打了這麼長的篇幅，其實只是想笑他 owo （但其實受到同事的照顧很多啦）&lt;/p&gt;

&lt;p&gt;但如果有記得他的英文全名 Message authentication code，其實就會比較直觀地知道，有個 code，是個用來做訊息驗證用的資訊，比較清楚他的角色是什麼。&lt;/p&gt;

&lt;h2 id=&quot;mac&quot;&gt;MAC&lt;/h2&gt;
&lt;p&gt;訊息驗證碼（Message authentication code，MAC）是一種常見驗證訊息來源、資料完整性（確保訊息沒有被竄改）的方式。&lt;/p&gt;

&lt;p&gt;sender 在傳送訊息時會根據與 receiver 約定好的方法，用金鑰跟傳輸資料產出驗證碼，除了要送過去的資料以外帶上這個驗證碼。receiver 收到訊息以後，可以根據之前約定好的方法用同一把金鑰跟傳輸資料檢驗這個驗證碼是不是按照說好的方式產生的，來驗證送訊息過來的人就是 sender，不是別人。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;assets/images/mac_usage.png&quot; alt=&quot;The example usage of MAC&quot; /&gt;&lt;/p&gt;

&lt;p&gt;「約定好的方法」可以有很多種，HMAC 就是一種產出驗證碼可以使用的方式。&lt;/p&gt;

&lt;h2 id=&quot;範例&quot;&gt;範例&lt;/h2&gt;

&lt;p&gt;比方說 A 公司 server 和 B 公司 server 要互相傳送訊息，傳輸過程中經過大海般茫茫又不安全的網路，所以他們約定好一把 secret key，每次互送 request 的時用 key 和 payload 用 HMAC-SHA256 算出訊息驗證碼，在 HTTP header 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X_HMAC&lt;/code&gt; 帶上（實務上似乎是放 query string 也有）。收到 request 方會需要用同一把 secret key 跟 payload 在產一次 mac，驗證和 header 上帶來的 mac 是否一樣，如果一樣才當作是可以信任的訊息。&lt;/p&gt;

&lt;h2 id=&quot;變動的-iv-值&quot;&gt;變動的 IV 值&lt;/h2&gt;

&lt;p&gt;有些合作廠商可能是使用像是 AES-256-GCM、AES-256-CBC 之類的方式產生訊息驗證碼，產出驗證碼的過程中，除了 key 和  payload 還需要動態產生一組 IV 值，一起帶過去給對方做驗證。如果這個 IV 值每次都送同一組的話，會怎麽樣呢？&lt;/p&gt;

&lt;p&gt;我對於密碼學不太熟悉，比較多的說明這裡附上 &lt;a href=&quot;https://crypto.stackexchange.com/questions/57645/is-using-the-same-iv-in-aes-similar-to-not-using-an-iv-in-the-first-place&quot;&gt;stack overflow&lt;/a&gt; &amp;gt;&amp;lt;&lt;/p&gt;

&lt;p&gt;但簡言之，帶同一組 IV 是有風險的。如果攻擊者可以找到明文類似的訊息，或是攻擊者有辦法製造出他想要的明文內容的訊息，有可能可以破解出 key 或是可以竄改訊息，讓訊息驗證碼失去其效用。因此，上述的情境裡不應該使用同一把 IV。&lt;/p&gt;</content><author><name>文月</name></author><category term="authentication" /><category term="authentication" /><summary type="html">前言閒聊 在串各種金流交易的時候，常常會聽到 MAC 跟 HMAC。以前第一次聽到的時候不知道 MAC 是什麼、HMAC 跟 MAC 差異在哪裡，直接問同事說「MAC 是什麼啊？」，結果被同事鄙視（誤）了一番。同事一邊說著「你不會查 wiki 嗎？」一邊翻了 wiki 頁面給我，結果他打開的是「Minimum Alveolar Concentration」的頁面（最小肺泡分壓之類的，我也不太清楚）。打了這麼長的篇幅，其實只是想笑他 owo （但其實受到同事的照顧很多啦）</summary></entry><entry><title type="html">工作雜談：多餘的 DB 欄位跟關聯</title><link href="/blog/single-source-of-truth-and-event-sourcing" rel="alternate" type="text/html" title="工作雜談：多餘的 DB 欄位跟關聯" /><published>2022-06-23T18:23:00+08:00</published><updated>2022-06-23T18:23:00+08:00</updated><id>/blog/single-source-of-truth-and-event-sourcing</id><content type="html" xml:base="/blog/single-source-of-truth-and-event-sourcing">&lt;p&gt;最近在工作上遇到很困擾的事情之一，就是在資料的架構上，前人建了很多重複、多餘的關聯跟欄位。&lt;/p&gt;

&lt;h2 id=&quot;多餘的關聯&quot;&gt;多餘的關聯&lt;/h2&gt;

&lt;p&gt;例如系統中有很多使用者（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;users&lt;/code&gt;），每個使用者一定會屬於一間店家（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stores&lt;/code&gt;），但這些店家之間不會共用使用者資料，使用者上會有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store_id&lt;/code&gt; 欄位去紀錄這個多對一的關聯。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-order-store.png&quot; alt=&quot;DB diagram of orders and stores&quot; /&gt;&lt;/p&gt;

&lt;p&gt;接者，每個使用者都有他綁定的支付方式（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payment_methods&lt;/code&gt;），一個支付方式只屬於一位使用者，沒有共用的狀況。支付方式上會有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_id&lt;/code&gt; 紀錄他屬於哪一個使用者。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-store-order-payment_method.png&quot; alt=&quot;DB diagram of orders, stores, and payment-methods&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如果今天我想在支付方式列表上看見這是哪個店家底下的支付方式，我應該會從支付方式找到關聯的使用者，再找到所屬的店家。但前人可能覺得「一直 JOIN 好麻煩哪」之類的，於是錢包上也多了一個 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store_id&lt;/code&gt; 去紀錄關聯到的店家。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-storeid-redundant.png&quot; alt=&quot;DB diagram with redundant store_id&quot; /&gt;&lt;/p&gt;

&lt;p&gt;整個資料庫多了好幾條關聯看起來都是為了少幾條 JOIN 建的，卻搞得撈資料的人不知道多個來源到底哪一個才是對的。這個時候如果錢包的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store_id&lt;/code&gt; 跟所屬 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user&lt;/code&gt; 身上的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;store_id&lt;/code&gt; 不同的時候，就會相當懊惱我到底該相信誰。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-user-payment-method-problem.png&quot; alt=&quot;store_ids are not same&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;多餘的欄位&quot;&gt;多餘的欄位&lt;/h2&gt;

&lt;p&gt;舉例來說，訂單（orders）底下會有很多刷卡紀錄（payments）。例如訂單有可能刷卡失敗，最後終於刷成功時，整張訂單才算是付款成功了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-order-payment.png&quot; alt=&quot;DB diagram with orders and payments&quot; /&gt;&lt;/p&gt;

&lt;p&gt;或者是，訂單可能會有退款紀錄，可能部分退款，也可能是全額退款。可能退款 10 元，也可能退款 20 元。訂單上有付款狀態（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payment_state&lt;/code&gt;）、退款金額（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refund_amount&lt;/code&gt;）這樣的欄位在紀錄付款結果、退款金額。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-order-payment-problem.png&quot; alt=&quot;payment_state and refund_amount are not same&quot; /&gt;&lt;/p&gt;

&lt;p&gt;原本另開欄位可能是圖個方便直接拿欄位的數值來使用，但當 code 寫爛了的時候，就會發生一些狀態不一致，不知道哪個欄位才是正確的問題。例如，當付款狀態（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payment_state&lt;/code&gt;）是的「訂單等待付款（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pending&lt;/code&gt;）」，但訂單卻有付款成功的紀錄時，我應該相信誰？如果訂單有一筆成功退 10 元的退款紀錄，但這筆訂單的退款金額（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refund_amount&lt;/code&gt;）卻還是 0 的時候，是不是我拿訂單的退款金額（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refund_amount&lt;/code&gt;）去做後續的判斷跟分析時，會大錯特錯？&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-order-payment2.png&quot; alt=&quot;DB diagram with orders and payments, and there are payment_state and refund_amount on orders&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;single-source-of-truth&quot;&gt;Single Source of Truth&lt;/h2&gt;

&lt;p&gt;關於以上的例子，第一個想要談談的概念是 Single Source of Truth。單一事實來源（Single Source of Truth，SSOT）大致上的意思是說，資料應該要由同一個來源讀取跟計算數值。&lt;/p&gt;

&lt;p&gt;在以上讓我困擾的例子中，很大的問題是我會有兩個以上的 data source，讓我不知道應該要依循哪一個。如果今天寫 SQL 時是用 A 來源，同事卻是用 B 來源，有可能資料不一致時會帶來錯誤跟困擾。&lt;/p&gt;

&lt;h2 id=&quot;event-sourcing&quot;&gt;Event Sourcing&lt;/h2&gt;

&lt;p&gt;再來看看付款紀錄的例子，其實，付款狀態可以用這張訂單的「付款紀錄」的狀態去獲得，例如：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;有付款成功的付款紀錄 =&amp;gt; 訂單付款成功&lt;/li&gt;
  &lt;li&gt;沒有任何付款紀錄 =&amp;gt; 訂單等待付款&lt;/li&gt;
  &lt;li&gt;有付款紀錄但沒有付款成功的 payment =&amp;gt; 訂單付款過但失敗了&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;退款金額在可以直接用訂單底下的退款紀錄去得到目前退過多少錢，把退款成功的退款紀錄的金額加總，就會是目前退款的金額。&lt;/p&gt;

&lt;p&gt;我覺得會是用類似 event sourcing 的方式來得到訂單的付款狀態跟資訊，每個付款紀錄、退款紀錄其實相當於一個個 event，將這些 event aggregate 起來，我就可以拿到當前訂單的狀態。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/blog/assets/images/20220623-event-sourcing.png&quot; alt=&quot;event sourcing&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;performance&quot;&gt;performance&lt;/h2&gt;

&lt;p&gt;我覺得前人的架構之所以會設計成這樣，可能是有 SQL 效能上的迷思。例如，如果把一些需要 JOIN 兩次以上的關聯變成 JOIN 一次就好，是不是就可以讓 SQL 效能變好了？或者是原本需要關聯到 payments 去看付款狀態跟退款金額的方式需要 JOIN payments 這張表，如果把我要的資訊放在 orders 的欄位上是不是可以少一個 JOIN 造成的負擔？&lt;/p&gt;

&lt;p&gt;但我自己覺得這會是很大的效能迷思。首先，如果 JOIN 了資料，下了 WHERE，結果資料撈很久，應該先 EXPLAIN 一下，看看 SQL 到底慢在哪裡。常常很大一部分都是沒有 index，沒吃到 index 造成的問題。沒有吃到 index 的時候，資料庫可能會用逐行掃描的方式 seq scan 過整張表去找資料，&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-&amp;gt; Seq Scan on orders (cost=0.00..504250.77 rows=11831677 width=267)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;加好了 index 以後，如果撈取資料時有正常吃到 index，會使用 index scan 的方式去撈資料。在資料量大的時候，效能的差異會有很明顯的差別。我會覺得如果覺得 JOIN 表時， SQL 就變得好慢，應該先檢查一下 foreign key 跟 WHERE 使用的欄位有沒有好好的下到 index。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-&amp;gt; Index Scan using index_payments_on_order_id on payments (cost=0.43..5.80 rows=1 width=1376)
Index Cond: (order_id = orders.id)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在 DB 的架構設計上，我覺得真的是特別需要深思熟慮的事情，後續要再盤點欄位的意義、被如何使用，甚至要想試著進行搬移整併的話都會相當困難QQ&lt;/p&gt;</content><author><name>文月</name></author><category term="sql" /><category term="sql" /><summary type="html">最近在工作上遇到很困擾的事情之一，就是在資料的架構上，前人建了很多重複、多餘的關聯跟欄位。</summary></entry><entry><title type="html">ruby 的 permutation</title><link href="/blog/ruby-permutations" rel="alternate" type="text/html" title="ruby 的 permutation" /><published>2021-09-02T17:00:00+08:00</published><updated>2021-09-02T17:00:00+08:00</updated><id>/blog/ruby-permutations</id><content type="html" xml:base="/blog/ruby-permutations">&lt;p&gt;不知道大家刷題的時候是不是有寫過 permutation，例如我有一個 array &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;['a', 'b', 'c']&lt;/code&gt;，我需要回傳的結果是這幾個元素的所有排列，例如&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;一般來說會試著窮舉所有可能性。
底下自己試著實作了遞迴版和迴圈版（解題方面弱弱的，有什麼建議都可以跟我說QQ&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/requiemformemories/305600eaf585d3467536aa266497e462.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;結果發現 ruby 的 array 竟然有 &lt;a href=&quot;https://www.rubydoc.info/stdlib/core/Array:permutation&quot;&gt;permutation&lt;/a&gt; 有這個神奇的 method。&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'b'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'c'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;permutation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [[&quot;a&quot;, &quot;b&quot;, &quot;c&quot;], [&quot;a&quot;, &quot;c&quot;, &quot;b&quot;], [&quot;b&quot;, &quot;a&quot;, &quot;c&quot;], [&quot;b&quot;, &quot;c&quot;, &quot;a&quot;], [&quot;c&quot;, &quot;a&quot;, &quot;b&quot;], [&quot;c&quot;, &quot;b&quot;, &quot;a&quot;]]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'a'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'b'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;permutation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [[&quot;a&quot;, &quot;a&quot;, &quot;b&quot;], [&quot;a&quot;, &quot;b&quot;, &quot;a&quot;], [&quot;a&quot;, &quot;a&quot;, &quot;b&quot;], [&quot;a&quot;, &quot;b&quot;, &quot;a&quot;], [&quot;b&quot;, &quot;a&quot;, &quot;a&quot;], [&quot;b&quot;, &quot;a&quot;, &quot;a&quot;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;搭配 uniq 或 to_set 就可以去除重複的結果，不需要自己很辛苦的寫扣窮舉，ruby 拿來刷題果然太奇怪了XD&lt;/p&gt;</content><author><name>文月</name></author><category term="ruby" /><category term="ruby" /><summary type="html">不知道大家刷題的時候是不是有寫過 permutation，例如我有一個 array ['a', 'b', 'c']，我需要回傳的結果是這幾個元素的所有排列，例如</summary></entry><entry><title type="html">BigSur 上開發 Rails， Rails 把 CPU 吃好吃滿？！</title><link href="/blog/gem-listen-high-cpu-usage" rel="alternate" type="text/html" title="BigSur 上開發 Rails， Rails 把 CPU 吃好吃滿？！" /><published>2021-09-01T17:00:00+08:00</published><updated>2021-09-01T17:00:00+08:00</updated><id>/blog/gem-listen-high-cpu-usage</id><content type="html" xml:base="/blog/gem-listen-high-cpu-usage">&lt;p&gt;不知道大家換到 BigSur 有沒有遇到比較舊的 Rails 專案會讓 mac 發燙起飛的狀況。
看一下 top 發生了什麼事，發現沒有在幹嘛的 Rails app 竟然把 CPU 吃好吃滿（咦&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;assets/images/listen_high_cpu_usage_1.png&quot; alt=&quot;top 截圖&quot; /&gt;&lt;/p&gt;

&lt;p&gt;原本我以為是 M1 有什麼特別的 issue，查了一下發現原來不少換到 BigSur 的人都有這個困擾&lt;/p&gt;

&lt;p&gt;會發生這個狀況是因為開發時會監控 file change 的 gem &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen&lt;/code&gt; 沒有套用到 Darwin 的 adapter，fall back to polling 形成高 CPU usage 的現象。
 
&lt;a href=&quot;https://github.com/guard/listen/issues/478&quot;&gt;https://github.com/guard/listen/issues/478&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;至於為什麼沒有套用到 Darwin-adapter 呢？因為之前的 regex 不包含 darwin20 XD&lt;/p&gt;

&lt;p&gt;會需要把 listen 升級至 3.3.0 以上，才不會有筆電起飛的困擾&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Gemfile&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'listen'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'~&amp;gt; 3.3'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>文月</name></author><category term="rails" /><category term="rails" /><summary type="html">不知道大家換到 BigSur 有沒有遇到比較舊的 Rails 專案會讓 mac 發燙起飛的狀況。 看一下 top 發生了什麼事，發現沒有在幹嘛的 Rails app 竟然把 CPU 吃好吃滿（咦</summary></entry><entry><title type="html">CS50 筆記：第四講 Memory</title><link href="/blog/cs50-notes-memory" rel="alternate" type="text/html" title="CS50 筆記：第四講 Memory" /><published>2021-02-25T15:34:00+08:00</published><updated>2021-02-25T15:34:00+08:00</updated><id>/blog/cs50-notes-memory</id><content type="html" xml:base="/blog/cs50-notes-memory">&lt;h2 id=&quot;筆記前言&quot;&gt;筆記前言&lt;/h2&gt;

&lt;p&gt;覺得這章是課程中我覺得蠻有趣的一章，除了學到了很多我以前不會的東西以外，這章的 &lt;a href=&quot;https://cs50.harvard.edu/college/2020/fall/psets/4/filter/more/&quot;&gt;problem set&lt;/a&gt; 很有趣，會帶著大家做一些基本的圖片處理（灰階、模糊、反轉、探測邊緣）。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;記憶體就像下圖的格子一樣有一格又一格的空間，我們可以幫每個 byte 編號。通常在電腦科學裡面會用十六進制來編號。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;assets/images/cs50_memory_1.png&quot; alt=&quot;memory grid&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;十六進制&quot;&gt;十六進制&lt;/h3&gt;

&lt;p&gt;遇到 15 進位，十進制中的 10, 11, 12, 13, 14, 15 分別用 A, B, C, D, E, F 來表示。&lt;/p&gt;

&lt;p&gt;十六進制的數數就會像底下這樣
00
01
02
03
04
05
06
07
08
09
0A (還沒進位！)
0B
0C
0D
0E
0F
10
…&lt;/p&gt;

&lt;p&gt;所以兩位數的時候最多可以算到 FF (十進制的 255)&lt;/p&gt;

&lt;p&gt;正好十六進制 FF 相當於二進制的 11111111（8bits!），每個十六進制的位數都可以表示 4 個 bits，正好可以用 2 個為表示一個 bytes&lt;/p&gt;

&lt;p&gt;1111 1111 =&amp;gt; FF&lt;/p&gt;

&lt;h4 id=&quot;hex-color-codes&quot;&gt;Hex Color Codes&lt;/h4&gt;

&lt;p&gt;常看到的網頁色碼 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#f0f8ff&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#db90b5&lt;/code&gt;，就是用分別用 1 個 byte來表示紅綠藍三種顏色的光的量，來表示一個顏色。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;assets/images/cs50_memory_2.png&quot; alt=&quot;hex color&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;pointer&quot;&gt;pointer&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&lt;/code&gt; address of: 這個變數在哪個記憶體位置&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;: 這個記憶體位置存的是誰&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;string&quot;&gt;string&lt;/h3&gt;

&lt;p&gt;一個 string 是一個 char 組成的陣列，之前學過透過 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]&lt;/code&gt; 來取得各個元素，例如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s[1]&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s[2]&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s[3]&lt;/code&gt;。因為陣列是連續的記憶體空間，每個元素會正好相鄰（char 佔一個 byte，因此每個元素的位置都隔一個 byte）&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;HI!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 例如 0x125&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0x126&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 0x127&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;於是，除了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s[1]&lt;/code&gt; ，我們可以透過指標的方式 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*(s+1)&lt;/code&gt; 來獲得下一個元素的內容&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;HI!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;segmentation-fault&quot;&gt;segmentation fault&lt;/h4&gt;

&lt;p&gt;當我們嘗試去操作不該碰的 memory ，程式會發生 segmentation fault。&lt;/p&gt;

&lt;h3 id=&quot;compare--copy&quot;&gt;compare &amp;amp; copy&lt;/h3&gt;

&lt;p&gt;比較兩個 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*char&lt;/code&gt; 其實是在比較記憶體位置，即便 value 一樣也會被判斷成是不同的（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str1 == str2&lt;/code&gt; 為 false）&lt;/p&gt;

&lt;h3 id=&quot;valgrind&quot;&gt;valgrind&lt;/h3&gt;

&lt;p&gt;如果自行 malloc 要記得 free，忘記的話就會造成 memory leak，這些被忘記 free 的記憶體無法再被其他程式使用。&lt;/p&gt;

&lt;p&gt;這種時候就可以使用 valgrind ，可以用來檢查程式是否有造成 memory leak 的工具，在 CS50 IDE 裡面預設有裝。&lt;/p&gt;

&lt;p&gt;比方說當前目錄有個叫 memory 的執行檔，可以跑 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valgrind ./memory&lt;/code&gt; 看他的分析&lt;/p&gt;

&lt;h3 id=&quot;作用域&quot;&gt;作用域&lt;/h3&gt;

&lt;p&gt;教授寫了一個 function swap 試圖交換兩個值的內容：&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x is %i, y is %i&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x is %i, y is %i&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;但最後印出來的結果會是&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x is 1, y is 2
x is 1, y is 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;實際上執行會是，在主程式裡面的時候在 stack 裡放上 x 跟 y 的值。到 swap 裡時再放上 a 跟 b 的值，如下圖。 a 和 b 交換完以後，記憶體被釋放（a 跟 b 放的 1 跟 2 變成 garbage value），回到主程式。於是 x 跟 y 都保持原樣。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;assets/images/cs50_memory_3.png&quot; alt=&quot;memory stack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;所以要在另一個 function 中交換 x, y，就必須透過指標。&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x is %i, y is %i&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;x is %i, y is %i&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;swap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;scanf&quot;&gt;scanf&lt;/h3&gt;

&lt;p&gt;之前都是用 cs50.h 的 get_string 等等，助教講師群包好的工具。實際上要自己獲得使用者的 output 的話，可以用 scanf。&lt;/p&gt;

&lt;p&gt;get_string 方便的點是他把 linked list 之類的部分處理好了，可以接任意長度的用戶 input，但 scanf 就要看你自己拿來接的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char *&lt;/code&gt;的長度。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char *&lt;/code&gt; 再自己 malloc 和陣列可以做到差不多的效果，差別在於陣列用 memory 中的 stack，系統會幫你處理好不會 memory leak，malloc 則是用 heap，要記得 free 否則會造成 memory leak&lt;/p&gt;

&lt;h3 id=&quot;fopen-fprintf-fclose&quot;&gt;fopen, fprintf, fclose&lt;/h3&gt;

&lt;p&gt;記憶體裡的內容會隨著電源關閉而消失，如果想要長久保存資料，就必須存在印碟裡，把資料寫入檔案中。&lt;/p&gt;

&lt;p&gt;教授透過電話簿的範例，來示範檔案相關的操作&lt;/p&gt;

&lt;h4 id=&quot;讀檔&quot;&gt;讀檔&lt;/h4&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;FILE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;phonebook.csv&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;寫入&quot;&gt;寫入&lt;/h4&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%s,%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;關閉檔案&quot;&gt;關閉檔案&lt;/h4&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;jpeg&quot;&gt;jpeg&lt;/h3&gt;

&lt;p&gt;可以用前幾個 bytes 就判斷一個檔案是否為 jpeg（被稱為 magic number）。因為這些檔案有特定的 standard，可以快速分辨它是什麼檔案&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;先用 fread 讀檔&lt;/li&gt;
  &lt;li&gt;jpeg 前三個 bytes 會是: 0xff 0xd8 0xff&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;quiz&quot;&gt;quiz&lt;/h3&gt;

&lt;p&gt;1) In your own words, what is a pointer?&lt;/p&gt;

&lt;p&gt;我自己的答案：在 C 裡面的一種 data type，用來存放記憶體位置。在 C 裡面，我們可以透過指標去取出他指向的值（dereferencing）。&lt;/p&gt;

&lt;p&gt;2) If s is of type string, in what sense is s a pointer?&lt;/p&gt;

&lt;p&gt;我自己的答案：在 c 當中不存在 string 這個型別，實際上他是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char *&lt;/code&gt; （只是在 cs50.h 裡把它定義成叫做 string 的 type。 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char *&lt;/code&gt; 代表他是個指標，指向的 value 應該被當成 char 來解讀。&lt;/p&gt;

&lt;p&gt;3) If s and t are of type string, why can we not use s == t to check whether s and t contain the same characters?&lt;/p&gt;

&lt;p&gt;我自己的答案：當 s 跟 t 都是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;char *&lt;/code&gt;，在做 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s == t&lt;/code&gt; 這件事情實際上的意思是在比較兩個記憶體位置，即便 t 指向的位置存的內容跟 s 指向的位置存的內容一樣，兩個記憶體位置有可能是不一樣的，所以無法用這種方式去比較 s 和 t 是否有相同的字串。&lt;/p&gt;</content><author><name>文月</name></author><category term="cs50" /><category term="cs50" /><summary type="html">筆記前言</summary></entry><entry><title type="html">CS50 筆記：第三講 Algorithms</title><link href="/blog/cs50-notes-algorithm" rel="alternate" type="text/html" title="CS50 筆記：第三講 Algorithms" /><published>2020-12-21T20:50:00+08:00</published><updated>2020-12-21T20:50:00+08:00</updated><id>/blog/cs50-notes-algorithm</id><content type="html" xml:base="/blog/cs50-notes-algorithm">&lt;h2 id=&quot;筆記前言&quot;&gt;筆記前言&lt;/h2&gt;

&lt;p&gt;本章先簡介了時間複雜度的概念，帶了一點 struct，最後一大半在講不同的 sorting 方式。&lt;/p&gt;

&lt;h2 id=&quot;lecture-3-algorithms&quot;&gt;Lecture 3 Algorithms&lt;/h2&gt;
&lt;p&gt;英文講義：https://cs50.harvard.edu/college/2020/fall/notes/3&lt;/p&gt;

&lt;h3 id=&quot;執行時間&quot;&gt;執行時間&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://cs50.harvard.edu/college/2020/fall/notes/3/running_time.png&quot; alt=&quot;執行時間&quot; /&gt;&lt;/p&gt;

&lt;p&gt;第 0 講的時候介紹了兩種搜尋方式：一頁一頁查找電話簿的 linear search &amp;amp; 把電話簿拆半再拆半的 binary search（其實還有每兩頁找一次的進化版 linear search XD）&lt;/p&gt;

&lt;p&gt;這三種方式的執行時間分別是&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;方式&lt;/th&gt;
      &lt;th&gt;時間&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;一頁一頁找（linear）&lt;/td&gt;
      &lt;td&gt;n&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;兩頁兩頁找&lt;/td&gt;
      &lt;td&gt;n/2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;拆半拆半找（二分搜尋）&lt;/td&gt;
      &lt;td&gt;log2 n&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;在估時間複雜度的時候會把常數省略，常數的影響沒有像次方、對數這麼大，例如 n 跟 n/2 跟 3n 都是 n。log2 n 跟 log3 n 都是 log n。&lt;/p&gt;

&lt;h3 id=&quot;時間複雜度&quot;&gt;時間複雜度&lt;/h3&gt;
&lt;p&gt;這裡介紹了兩種 notation， big O 跟 big omega。表示方式像是 O(n)、Ω(n)，唸作 big O of n。&lt;/p&gt;

&lt;p&gt;big O 在描述這個資料量與執行時間之間的函數的 upper bound，代表執行時間的最壞情況。&lt;/p&gt;

&lt;p&gt;big omega 則是 lower bound，代表最佳情況。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;方式&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;O&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Ω&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;linear search&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;O(n)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;Ω(1)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;binary search&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;O(log n)&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;Ω(1)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;structs&quot;&gt;Structs&lt;/h3&gt;

&lt;p&gt;比方說有聯絡人的資料，比起把聯絡人姓名跟電話分成兩個 array 存，把它用 struct 組織起來操作也比較不容易出錯。&lt;/p&gt;

&lt;h4 id=&quot;bad&quot;&gt;bad&lt;/h4&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Brian&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;David&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;+1-617-495-1000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;+1-949-468-2750&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;good&quot;&gt;good&lt;/h4&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// inside main function&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Brian&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;+1-617-495-1000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;David&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;+1-949-468-2750&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;排序&quot;&gt;排序&lt;/h3&gt;

&lt;p&gt;之所以能夠用 binary search 有一大前題是，要找資料的那個 array 資料是有 sort 過的。&lt;/p&gt;

&lt;p&gt;電腦無法像人類一樣一眼望過去就知道怎麼排序移動，只能一次查看一個 item、一次調動一個 item。&lt;/p&gt;

&lt;h4 id=&quot;selection-sort&quot;&gt;selection sort&lt;/h4&gt;
&lt;p&gt;助教影片：https://video.cs50.io/3hH8kTHFw2A （看數字動一次勝過千言萬語啊）&lt;/p&gt;

&lt;p&gt;從最左邊開始選定一個數字，把他跟目前右手邊最小的數字交換。&lt;/p&gt;

&lt;h4 id=&quot;bubble-sort&quot;&gt;bubble sort&lt;/h4&gt;
&lt;p&gt;助教影片：https://video.cs50.io/RT-hUXUWQ2I
兩個兩個做比對，當左邊的元素比右邊大，就左右邊的互換。&lt;/p&gt;

&lt;h4 id=&quot;merge-sort-top-down&quot;&gt;merge sort (top-down)&lt;/h4&gt;
&lt;p&gt;助教影片：https://video.cs50.io/Ns7tGNbtvV4
把整個 array 切成一個個小 array。切到只有一個元素的時候，每個只有 1 個元素的 array 都是排好的。接著再把排好的 array 接在一起。因為元素已經排序過，所以可以只比較最左（最小）的元素。&lt;/p&gt;

&lt;h2 id=&quot;lab-3&quot;&gt;Lab 3&lt;/h2&gt;
&lt;p&gt;題目給了三支程式 sort1, sort2, sort3，還有一些排序方式不同的資料。要判斷這三個 sort 的程式分別是用哪一種方式（selection? bubble? merge?）來實作。&lt;/p&gt;

&lt;p&gt;簡單地寫一下我的解答：&lt;/p&gt;

&lt;p&gt;底下是我拿去執行 50000 筆資料的秒數。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;資料/哪一支程式&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;sort1&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;sort2&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;sort3&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;sorted&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;4&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;8&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;random&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;16&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;reversed&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;8&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;sort2 穩定地時間很短，應該是 nlogn 的 merge sort&lt;/p&gt;

&lt;p&gt;sort1 「已排序」跟「沒有排」的資料執行時間差很多，應該是交換排序（最佳情況 n, 平常 n^2）&lt;/p&gt;

&lt;p&gt;所以 sort3 應該是 selection sort。&lt;/p&gt;

&lt;h2 id=&quot;練習寫-merge-sort&quot;&gt;練習寫 merge sort&lt;/h2&gt;

&lt;p&gt;先寫了 ruby 版的，但覺得 ruby 拿來寫這個很沒 fu XD（執行時間就素慢（誤&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;left_half&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right_half&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;split_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merge_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left_half&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right_half&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;split_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'There should be more than 2 elements in the array'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;left_half&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;right_half&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left_half&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right_half&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 其中一個 array shift 空了就把還剩下的往 result 後面接&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;接著挑戰寫一下 C。對 C 的操作還不太熟（苦笑），先直接更動了原 array。&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NELEMS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Result: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NELEMS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;merge_sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;merge_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;merge_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_mid_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid_idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lselect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rselect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_mid_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 把 num array 複製進 ori_num&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ori_num 是原本 left 跟 right 的內容&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 判斷完誰大誰小以後直接更動原 array&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rselect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lselect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lselect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_mid_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rselect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lselect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rselect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]){&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lselect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ori_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rselect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>文月</name></author><category term="cs50" /><category term="cs50" /><summary type="html">筆記前言</summary></entry></feed>