cs50 week 4 問題:Recover

閱讀時間約 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 的數字。
16會員
34內容數
Bonjour à tous,我本身是法文系畢業,這邊會刊登純文組學習網頁開發的筆記。如果能鼓勵更多文組夥伴一起學習,那就太開心了~
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
CS Wind 擴張越南塔架廠 生產大型離岸風塔架韓商CS Wind 在越南擴張其風機塔架生產廠,預計供應直徑10公尺的大型離岸風機塔架。
avatar
凱君
2023-08-31
CSR/ESG|UBI無條件基本收入:一個打破社福迷思的尊嚴未來試想一下,如果政府每個月都發給所有國民一筆錢,讓他們能夠滿足基本生活所需,是不是一件很棒,但聽起來匪夷所思的事情?這正是「無條件基本收入」(又稱universal basic income,UBI)想要促成的目標。 無條件基本收入這件事歐美早有在討論,而台灣在這一兩年慢慢從媒體上看到相關話題...
Thumbnail
avatar
本住人
2020-12-31
CSR/ESG|後疫情時代,經濟如何朝向更永續的目標發展2020肇始,新冠疫情肆虐,全球經濟遭受程度不一的衝擊,根據聯合國開發署(UNDP)的報告,國際社會不分彼此,皆遭受程度不一的影響,在經濟與社會發展,人道主義危機,公共衛生與國家安全,乃至教育與人權等部分,受到相當的影響,特別是在開發中國家和最低度開發國家(LDC),疫情造成的衝擊更是嚴重影響...
Thumbnail
avatar
本住人
2020-12-29
CSRF攻擊與防禦CSRF全名為 Cross Site Request Forgery( 跨站請求偽造)。
Thumbnail
avatar
Vic Lin
2020-10-23
CSS的大於(>)、加號(+)、取代符號(~)有時我們會在CSS裡看到「>」、「+」、「~」這些符號的使用,它們到底有甚麼功用呢?  A.大於符號(>) 大於(>)就是選取底下直接的子元素。 以大於符號(.box > p)和空格(.box p)來做比較,先看以下例子: 使用空格的情況 .box p{ font-size:20px; color
Thumbnail
avatar
哩老師
2020-05-06
CSS選擇器的優先權順序CSS提供許多選擇器類型,當使用不同的選擇器時,套用樣式的優先權也會不同。 A.元素內的(行內)樣式>頁面內的(崁入)樣式>外部載入(串連) 元素內的(行內)樣式 例子: 頁面內的樣式(崁入樣式) 例子: 外部載入(串連) 例子: B.後設定>前設定 最後設定的樣式將蓋過之前設定的樣式 例子:
Thumbnail
avatar
哩老師
2020-05-06
CS:GO IEM Katowice Major 2019 挑戰者第三及第四天戰報經過這兩天滿滿的bo3,通往傳奇組的門票只剩下三張了,而剩下的隊伍不是黑馬就是傳統豪門。
Thumbnail
avatar
高禕騏
2019-02-17
CS:GO IEM Katowice Major 2019 挑戰者第二天戰報MAJOR挑戰者組進行到第二天,由於本次賽制,只要攸關晉級或是淘汰的比賽都需要打BO3,在昨日經過四場BO3以及四場BO1,整個態勢已逐漸明朗。還是一如往常的CS:GO,黑馬、滑鐵盧等劇情不斷上演。
Thumbnail
avatar
高禕騏
2019-02-15
CS:GO IEM Katowice Major 2019 挑戰者第一天戰報       看完第一天的Katowice Major挑戰者賽程,戰況十分出乎人意料,其中原因或許在於歐美戰區之外的隊伍樣本資料過少,造成實力成謎,第一天賽程結束後普遍觀眾認為歐美地區似乎宰制力不如以
Thumbnail
avatar
高禕騏
2019-02-14