CS50 problem set 4 作業回顧

陳雁智 (Marat Y. C. Chen)
Manjeaneer
Published in
4 min readOct 23, 2017

--

resize
當時寫 pset4 的 resize 時,看完作業需求其實沒有很清楚要寫出什麼樣的 resize,找了一個很厲害的 reference bmpresize, 就開始抱頭下去燒一整週結果沒什麼成果,再去 reddit 上的課程討論區發現以下這一段

Think of it as you go pixel by pixel. If your ratio is .5, you’ll skip the first pixel, write the second. If the ratio is .25, you skip the first, second, third, and write the fourth.

Try to think of an algorithm to represent this. But at the same time, if your ratio is .4, you’ll skip the first pixel, the second pixel, but write the third. Then you’ll skip the fourth pixel, but write the fifth (4/10 = 2/5 for every 5 pixels in the out file you’ll write 2 pixels) So you’ll need to think of a way to do this.

英文很多,用圖來表示比較快

(左) 原圖 (中) 我以為的 resize (75%) (右) 作業預期的 resize (75%)

…原來只要按比例撿 pixel 就可以了,不用考慮 resize 後的細節變化,卡關途中撿了一個陣列在 C 裡需要注意的點: 陣列在 C 裡是以指標方式做開頭 (其實 Lecture 有強調),在呼叫時最好把大小一起帶入,比如以下兩種方式

void function(int m, n int array[m][n])

或建一個結構帶陣列大小,然後用指標取值

struct two_dimensional_array{
int m;
int n;
array[m][n]
}
two_dimensional_array *ptr = NULL
ptr = malloc(sizeof(two_dimensional_array))
void function(struct* ptr, array[(ptr)->m][(ptr)->n]

另外,特別要注意的是,建立變數時一定要初始化 (給零值或 NULL)在 debug 的時候可以少花很多時間,程式可能是對的,但沒有初始化變數而導致結果錯誤的時候,通常會先以為寫錯然後繞很遠的路

recover

寫 cs50 作業真的不能取巧,在這一題就遇到作業給的 card.raw 跟 check50 檢查用的檔不一樣,在寫的時候把 50 張檔案當成迴圈結尾,即使成功還原,在 check50 時會失敗在最後一個檔 (15.jpg)

一個方式是以當讀檔結束當跳出迴圈的條件,pseudo code:

While(1)
{
if (fread(讀card.raw進一個512 byte (FAT基本block) array))
{
//失敗就跳出loop
}
jf (array[0,1,2] = 0xffd8ff ) //找到jpg header
{
//開新檔,建pointer準備寫入
}
if (output_file_ptr) // 開檔跟pointer建起來
{
if(fwrite(..output_file) != 1)
{
//寫入失敗,關掉 output_file
}
}
}

寫 pset4 過程中卡蠻久,但解開不懂的問題時還蠻有收穫,像是實際去算一張 resize 後的圖大小應該變多少,為何要加padding (memory alignment),拿 bmp 的 header 檔跟 xxd 倒出來的實際資料相互驗證,重覆練習使用 fopen, fseek, fclose 這些檔案與指標操作,從中體會實際程式在讀取資料的大致過程,畢竟,寫作業如果只為了拿一個虛虛的 100% 而浪費了中間的過程就太可惜了。

--

--

陳雁智 (Marat Y. C. Chen)
Manjeaneer

project manager/savvy programmer/marathon runner/critical reader