cs50 week 4 問題:Recover

更新於 2024/09/28閱讀時間約 7 分鐘

cs50 第四週的課程核心為 memory 以及 pointer 的介紹,由於 pointer 的概念比較複雜,所以我看了兩次才稍微進入狀況 💦

老師在課堂最後面也快速介紹了如何用 C 語言開啟、讀取、寫入文件,而實際上的運用就是 problem set 4 的 recover 問題了。這個問題折騰了我快一天,好不容易通過了所有檢核,因此希望記錄下來,順便整理一下解題的思路。

背景說明

我們要用 C 語言寫程式,透過遞迴的方式從記憶卡找尋 JPEG 圖檔。記憶卡由許多 512 bytes 的區塊組成。JPEG 圖檔的首四個 bytes 則有固定的格式。每當我們發現新的 JPEG 圖檔,可以開啟一份新檔案,將 bytes 從記憶卡寫入到新檔案裡面。

JPEG 規則

JPEG 圖檔的頭三個 bytes 一定是 0xff0xd80xff,而第四個 byte 則可能是 0xe00xef 其中一個。看到 0x 我們其實就知道這些 byte 是用十六進位制

每個 JPEG 彼此緊貼延續,所以當我們辨識出 JPEG header 出現,也代表上一個 JPEG 的結束。還有一點值得注意,JPEG 不會只剛好佔據一個 512 byte 的區塊,而是會根據圖檔的大小而定。參考 problem set 的 walkthrough 影片更加清楚:

raw-image

檔案名稱規定

當我們開啟一份新檔案想要寫入記憶卡的 bytes 時,要注意題目有規定檔案名稱的寫法。檔案名稱必須為 ###.jpg。其中 ### 代表三個十進位的數碼,以 000 作為第一個檔案的名稱。換句話說,若是第三個檔案,其名稱將為 003.jpg

Command-line argument

command-line 需要帶入兩個參數,./recover 以及 IMAGE,其中 IMAGE 就是我們要讀取的檔案 (記憶卡)。所以真實運作起來會長這樣:

$ ./recover card.raw // card.raw 就是要讀取的記憶卡



解題思路

  1. 確認使用者有沒有乖乖在 command-line 提供兩個參數
  2. 打開要讀取的檔案 (記憶卡)
  3. 確認檔案 (記憶卡) 能否開啟
  4. 宣告待會將用到的變數
  5. 讀取檔案 (記憶卡) 眾多 512 bytes
  6. 尋找 JPEG header 的蹤跡 (前四個 bytes)
  7. 有找到 JPEG header 的話,建立新檔案的名稱
  8. 打開新檔案 (output_file)
  9. 找到的 JPEG 圖檔數量加一 (紀錄數量是為了檔案名稱)
  10. 確認新檔案可以寫入,然後寫入
  11. 關閉檔案,並釋放記憶體空間
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef uint8_t BYTE;

int main(int argc, char *argv[])
{
    // Check if user provides two arguments in command-line
    if (argc != 2)
    {
        printf("Usage: ./recover IMAGE\n");
        return 1;
    }

    // Open the file for reading
    FILE *input_file = fopen(argv[1], "r");

    // Check the file can be opened
    if (input_file == NULL)
    {
        printf("This file can not be opened!\n");
        return 1;
    }

    // Declare the vars
    BYTE buffer[512];
    int image_counter = 0;

    //Initialize the output file
    FILE *output_file = NULL;

    // ***.JPG (with a space for /n at the end)
    char *filename = malloc(8 * sizeof(char));

    // Read the blocks
    while (fread(buffer, 512, 1, input_file) == 1)
    {
        // Identify JPEG signature
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            // Create filename
            sprintf(filename, "%03i.jpg", image_counter);

            // Open outputfile for writing
            output_file = fopen(filename, "w");

            // Image Counter increased by 1
            image_counter++;
        }

        // If JPEG has been found then write into output file
        if (!(image_counter == 0))
        {
            fwrite(buffer, 512, 1, output_file);
        }
    }

    // Close the files
    fclose(input_file);
    fclose(output_file);

    // Release memory spaces allocated by malloc
    free(filename);

    return 0;
}


要點筆記

fopen() 開啟檔案

FILE *fopen(const char *pathname, const char *mode);

在這個問題中,我們會用到兩種 mode:

  • "r":代表檔案讀取模式。
  • "w":代表檔案寫入模式。

fread() 讀取檔案

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  • ptr:要讀取資料的記憶體位址
  • size:要讀取的資料類型大小 (以 byte 當作單位)
  • nmemb:一次要讀取的資料大小
  • stream:被讀取的檔案的 pointer

在本次的問題中,我們使用了 while 迴圈來重複檢查記憶卡眾多的 512 bytes 區塊群當中,是否出現 JPEG header 的蹤跡。while 迴圈的條件就是透過 fread() 來實現的。

while (fread(buffer, 512, 1, input_file) == 1)
💡 fread() 會回傳讀取的項目數量,如果到達被讀取的檔案底端,則會回傳 0 或是小於 nmemb 的數字。
隨處可見的台灣普男,育有一貓,最近喜歡上富邦悍將的韓國啦啦隊南珉貞,也是個健身後容易跑去吃麥當勞,意志力有夠不堅定的魯蛇。這邊會記錄平常的閱讀心得。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
了解CSR與ESG的關鍵差異,並探索行為經濟學如何幫助企業推動永續發展。從中小企業到大型企業,這些策略有助於達成長期經營目標。
Thumbnail
本週道瓊回到四萬點,收在40659點,本週看到思科CSCO要全球裁員7%的新聞,查了一下,手上沒這支,現在加倉買在49元。 也是一支要靠AI翻身的股票
Thumbnail
現在CSI正夯,各式各樣的科學營隊好多,但價格真的................不便宜。 科學營隊中,其中有一項是【指紋採集】,怎麼採?如何採?需要具備什麼工具?今天介紹簡易採集工具!   一般指紋採集建議要戴口罩, 粉末它較容易揚起在空中,吸入過多對於身體並不OK 採取指紋的第一個重要的
Thumbnail
在本章節中,我們介紹了 CSS 偽元素的基本概念和常見用法,通過一些示例,我們展示了如何使用這些偽元素來樣式化文檔中的特定部分。此外,我們還探討了一些高級用法,如創建自定義引號和實現複雜的圖形效果。這些內容應該能夠幫助你更好地理解和應用 CSS 偽元素。
Thumbnail
在這一章中,我們介紹了 CSS 的過渡效果和動畫效果。過渡效果使 CSS 屬性的變化更加平滑,而動畫效果則允許我們更精細地控制元素的多個屬性隨時間變化的過程。我們通過基本語法和示例展示了如何使用這些效果,並提供了一個綜合應用的實踐案例來幫助理解。這些技術可以讓你的網頁更具互動性和動態效果。
韓商CS Wind 在越南擴張其風機塔架生產廠,預計供應直徑10公尺的大型離岸風機塔架。
Thumbnail
試想一下,如果政府每個月都發給所有國民一筆錢,讓他們能夠滿足基本生活所需,是不是一件很棒,但聽起來匪夷所思的事情?這正是「無條件基本收入」(又稱universal basic income,UBI)想要促成的目標。 無條件基本收入這件事歐美早有在討論,而台灣在這一兩年慢慢從媒體上看到相關話題...
Thumbnail
2020肇始,新冠疫情肆虐,全球經濟遭受程度不一的衝擊,根據聯合國開發署(UNDP)的報告,國際社會不分彼此,皆遭受程度不一的影響,在經濟與社會發展,人道主義危機,公共衛生與國家安全,乃至教育與人權等部分,受到相當的影響,特別是在開發中國家和最低度開發國家(LDC),疫情造成的衝擊更是嚴重影響...
Thumbnail
CSRF全名為 Cross Site Request Forgery( 跨站請求偽造)。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
了解CSR與ESG的關鍵差異,並探索行為經濟學如何幫助企業推動永續發展。從中小企業到大型企業,這些策略有助於達成長期經營目標。
Thumbnail
本週道瓊回到四萬點,收在40659點,本週看到思科CSCO要全球裁員7%的新聞,查了一下,手上沒這支,現在加倉買在49元。 也是一支要靠AI翻身的股票
Thumbnail
現在CSI正夯,各式各樣的科學營隊好多,但價格真的................不便宜。 科學營隊中,其中有一項是【指紋採集】,怎麼採?如何採?需要具備什麼工具?今天介紹簡易採集工具!   一般指紋採集建議要戴口罩, 粉末它較容易揚起在空中,吸入過多對於身體並不OK 採取指紋的第一個重要的
Thumbnail
在本章節中,我們介紹了 CSS 偽元素的基本概念和常見用法,通過一些示例,我們展示了如何使用這些偽元素來樣式化文檔中的特定部分。此外,我們還探討了一些高級用法,如創建自定義引號和實現複雜的圖形效果。這些內容應該能夠幫助你更好地理解和應用 CSS 偽元素。
Thumbnail
在這一章中,我們介紹了 CSS 的過渡效果和動畫效果。過渡效果使 CSS 屬性的變化更加平滑,而動畫效果則允許我們更精細地控制元素的多個屬性隨時間變化的過程。我們通過基本語法和示例展示了如何使用這些效果,並提供了一個綜合應用的實踐案例來幫助理解。這些技術可以讓你的網頁更具互動性和動態效果。
韓商CS Wind 在越南擴張其風機塔架生產廠,預計供應直徑10公尺的大型離岸風機塔架。
Thumbnail
試想一下,如果政府每個月都發給所有國民一筆錢,讓他們能夠滿足基本生活所需,是不是一件很棒,但聽起來匪夷所思的事情?這正是「無條件基本收入」(又稱universal basic income,UBI)想要促成的目標。 無條件基本收入這件事歐美早有在討論,而台灣在這一兩年慢慢從媒體上看到相關話題...
Thumbnail
2020肇始,新冠疫情肆虐,全球經濟遭受程度不一的衝擊,根據聯合國開發署(UNDP)的報告,國際社會不分彼此,皆遭受程度不一的影響,在經濟與社會發展,人道主義危機,公共衛生與國家安全,乃至教育與人權等部分,受到相當的影響,特別是在開發中國家和最低度開發國家(LDC),疫情造成的衝擊更是嚴重影響...
Thumbnail
CSRF全名為 Cross Site Request Forgery( 跨站請求偽造)。