--- tags: CS50 --- # (2022年) CS50 week4 其實之前就已經修完 CS50 了,不過因應 2022 年將課堂作業的系統 從 c9.io 換到 github codespace + vscode 整合 打算來重溫一下裡面的作業,並暖身一下 C 語言的手感 由於已經有許多前輩分享課程與作業的心得 加上官網教材的投影片、重點筆記、教學影片都非常完整 故不再做詳細的紀錄,專注在作業 (Lab, Problem sets) 上面 https://cs50.harvard.edu/x/2022/weeks/4/ --- ### Lab4: [Volume](https://cs50.harvard.edu/x/2022/labs/4) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c // Modifies the volume of an audio file #include <stdint.h> #include <stdio.h> #include <stdlib.h> // Number of bytes in .wav header const int HEADER_SIZE = 44; int main(int argc, char *argv[]) { // Check command-line arguments if (argc != 4) { printf("Usage: ./volume input.wav output.wav factor\n"); return 1; } // Open files and determine scaling factor FILE *input = fopen(argv[1], "r"); if (input == NULL) { printf("Could not open file.\n"); return 1; } FILE *output = fopen(argv[2], "w"); if (output == NULL) { printf("Could not open file.\n"); return 1; } float factor = atof(argv[3]); uint8_t header[HEADER_SIZE]; fread(&header, sizeof(header), 1, input); fwrite(&header, sizeof(header), 1, output); int16_t buffer; while (fread(&buffer, sizeof(buffer), 1, input)) { buffer *= factor; fwrite(&buffer, sizeof(buffer), 1, output); } // Close files fclose(input); fclose(output); } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c ``` ::: -- 執行 ![](https://hackmd.io/_uploads/SJ_3mZhQj.png) 驗證 ![](https://hackmd.io/_uploads/Hy2UQW3Qs.png) --- ### 作業: [Filter_less](https://cs50.harvard.edu/x/2022/psets/4/filter/less/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include "helpers.h" #include <math.h> #include <stdbool.h> // Convert image to grayscale void grayscale(int height, int width, RGBTRIPLE image[height][width]) { int avgRGB; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int Red = image[i][j].rgbtRed; int Green = image[i][j].rgbtGreen; int Blue = image[i][j].rgbtBlue; avgRGB = round((Red + Green + Blue) / (float) 3); image[i][j].rgbtRed = avgRGB; image[i][j].rgbtGreen = avgRGB; image[i][j].rgbtBlue = avgRGB; } } return; } // Convert image to sepia void sepia(int height, int width, RGBTRIPLE image[height][width]) { int originRed, originGreen, originBlue; int sepiaRed, sepiaBlue, sepiaGreen; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { originRed = image[i][j].rgbtRed; originGreen = image[i][j].rgbtGreen; originBlue = image[i][j].rgbtBlue; sepiaRed = round(0.393 * originRed + 0.769 * originGreen + 0.189 * originBlue); sepiaGreen = round(0.349 * originRed + 0.686 * originGreen + 0.168 * originBlue); sepiaBlue = round(0.272 * originRed + 0.534 * originGreen + 0.131 * originBlue); image[i][j].rgbtRed = (sepiaRed > 255) ? 255 : sepiaRed; image[i][j].rgbtGreen = (sepiaGreen > 255) ? 255 : sepiaGreen; image[i][j].rgbtBlue = (sepiaBlue > 255) ? 255 : sepiaBlue; } } return; } // Reflect image horizontally void reflect(int height, int width, RGBTRIPLE image[height][width]) { // iterate the height for (int i = 0; i < height; i++) { // iterate the `half of width` for (int j = 0; j < (width / 2); j++) { // get temp color in pixel int tempRed = image[i][j].rgbtRed; int tempGreen = image[i][j].rgbtGreen; int tempBlue = image[i][j].rgbtBlue; // then swap color from reflect pixel image[i][j].rgbtRed = image[i][width - j - 1].rgbtRed; image[i][j].rgbtGreen = image[i][width - j - 1].rgbtGreen; image[i][j].rgbtBlue = image[i][width - j - 1].rgbtBlue; // record temp color to reflect pixel image[i][width - j - 1].rgbtRed = tempRed; image[i][width - j - 1].rgbtGreen = tempGreen; image[i][width - j - 1].rgbtBlue = tempBlue; } } return; } // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { // create a temp image to record blurred pixel RGBTRIPLE tempImage[height][width]; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int totalRed = 0; int totalGreen = 0; int totalBlue = 0; int counter = 0; // get the near 9 pixels for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { int nearX = i + x; int nearY = j + y; // check is valid the near pixels bool invalidX = nearX < 0 || nearX > (height - 1); bool invalidY = nearY < 0 || nearY > (width - 1); if (invalidX || invalidY) { continue; // skip this round, next iterator } // records the pixels value totalRed += image[nearX][nearY].rgbtRed; totalGreen += image[nearX][nearY].rgbtGreen; totalBlue += image[nearX][nearY].rgbtBlue; counter++; } } // count the avg of near pixels, and record to temp tempImage[i][j].rgbtRed = round(totalRed / (float) counter); tempImage[i][j].rgbtGreen = round(totalGreen / (float) counter); tempImage[i][j].rgbtBlue = round(totalBlue / (float) counter); } } // replace the blurred image to the original image for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtRed = tempImage[i][j].rgbtRed; image[i][j].rgbtGreen = tempImage[i][j].rgbtGreen; image[i][j].rgbtBlue = tempImage[i][j].rgbtBlue; } } return; } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include "helpers.h" #include <math.h> #include <stdbool.h> // Convert image to grayscale void grayscale(int height, int width, RGBTRIPLE image[height][width]) { int avgRGB; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int Red = image[i][j].rgbtRed; int Green = image[i][j].rgbtGreen; int Blue = image[i][j].rgbtBlue; avgRGB = round((Red + Green + Blue) / (float) 3); image[i][j].rgbtRed = avgRGB; image[i][j].rgbtGreen = avgRGB; image[i][j].rgbtBlue = avgRGB; } } return; } // Convert image to sepia void sepia(int height, int width, RGBTRIPLE image[height][width]) { int originRed, originGreen, originBlue; int sepiaRed, sepiaBlue, sepiaGreen; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { originRed = image[i][j].rgbtRed; originGreen = image[i][j].rgbtGreen; originBlue = image[i][j].rgbtBlue; sepiaRed = round(0.393 * originRed + 0.769 * originGreen + 0.189 * originBlue); sepiaGreen = round(0.349 * originRed + 0.686 * originGreen + 0.168 * originBlue); sepiaBlue = round(0.272 * originRed + 0.534 * originGreen + 0.131 * originBlue); image[i][j].rgbtRed = (sepiaRed > 255) ? 255 : sepiaRed; image[i][j].rgbtGreen = (sepiaGreen > 255) ? 255 : sepiaGreen; image[i][j].rgbtBlue = (sepiaBlue > 255) ? 255 : sepiaBlue; } } return; } // Reflect image horizontally void reflect(int height, int width, RGBTRIPLE image[height][width]) { // iterate the height for (int i = 0; i < height; i++) { // iterate the `half of width` for (int j = 0; j < (width / 2); j++) { // get temp color in pixel int tempRed = image[i][j].rgbtRed; int tempGreen = image[i][j].rgbtGreen; int tempBlue = image[i][j].rgbtBlue; // then swap color from reflect pixel image[i][j].rgbtRed = image[i][width - j - 1].rgbtRed; image[i][j].rgbtGreen = image[i][width - j - 1].rgbtGreen; image[i][j].rgbtBlue = image[i][width - j - 1].rgbtBlue; // record temp color to reflect pixel image[i][width - j - 1].rgbtRed = tempRed; image[i][width - j - 1].rgbtGreen = tempGreen; image[i][width - j - 1].rgbtBlue = tempBlue; } } return; } // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { // create a temp image to record blurred pixel RGBTRIPLE tempImage[height][width]; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int totalRed = 0; int totalGreen = 0; int totalBlue = 0; int counter = 0; // get the near 9 pixels for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { int nearX = i + x; int nearY = j + y; // check is valid the near pixels bool invalidX = nearX < 0 || nearX > (height - 1); bool invalidY = nearY < 0 || nearY > (width - 1); if (invalidX || invalidY) continue; // skip this round, next iterator // records the pixels value totalRed += image[nearX][nearY].rgbtRed; totalGreen += image[nearX][nearY].rgbtGreen; totalBlue += image[nearX][nearY].rgbtBlue; counter++; } } // count the avg of near pixels, and record to temp tempImage[i][j].rgbtRed = round(totalRed / (float) counter); tempImage[i][j].rgbtGreen = round(totalGreen / (float) counter); tempImage[i][j].rgbtBlue = round(totalBlue / (float) counter); } } // replace the blurred image to the original image for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtRed = tempImage[i][j].rgbtRed; image[i][j].rgbtGreen = tempImage[i][j].rgbtGreen; image[i][j].rgbtBlue = tempImage[i][j].rgbtBlue; } } return; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/ry4oFZhQi.png) 驗證 ![](https://hackmd.io/_uploads/Hy_gYb2Xi.png) --- ### 作業: [Filter_more](https://cs50.harvard.edu/x/2022/psets/4/filter/more/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include "helpers.h" #include <math.h> #include <stdbool.h> // Convert image to grayscale void grayscale(int height, int width, RGBTRIPLE image[height][width]) { int avgRGB; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int Red = image[i][j].rgbtRed; int Green = image[i][j].rgbtGreen; int Blue = image[i][j].rgbtBlue; avgRGB = round((Red + Green + Blue) / (float) 3); image[i][j].rgbtRed = avgRGB; image[i][j].rgbtGreen = avgRGB; image[i][j].rgbtBlue = avgRGB; } } return; } // Reflect image horizontally void reflect(int height, int width, RGBTRIPLE image[height][width]) { // iterate the height for (int i = 0; i < height; i++) { // iterate the `half of width` for (int j = 0; j < (width / 2); j++) { // get temp color in pixel int tempRed = image[i][j].rgbtRed; int tempGreen = image[i][j].rgbtGreen; int tempBlue = image[i][j].rgbtBlue; // then swap color from reflect pixel image[i][j].rgbtRed = image[i][width - j - 1].rgbtRed; image[i][j].rgbtGreen = image[i][width - j - 1].rgbtGreen; image[i][j].rgbtBlue = image[i][width - j - 1].rgbtBlue; // record temp color to reflect pixel image[i][width - j - 1].rgbtRed = tempRed; image[i][width - j - 1].rgbtGreen = tempGreen; image[i][width - j - 1].rgbtBlue = tempBlue; } } return; } // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { // create a temp image to record blurred pixel RGBTRIPLE tempImage[height][width]; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int totalRed = 0; int totalGreen = 0; int totalBlue = 0; int counter = 0; // get the near 9 pixels for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { int nearX = i + x; int nearY = j + y; // check is valid the near pixels bool invalidX = nearX < 0 || nearX > (height - 1); bool invalidY = nearY < 0 || nearY > (width - 1); if (invalidX || invalidY) { continue; // skip this round, next iterator } // records the pixels value totalRed += image[nearX][nearY].rgbtRed; totalGreen += image[nearX][nearY].rgbtGreen; totalBlue += image[nearX][nearY].rgbtBlue; counter++; } } // count the avg of near pixels, and record to temp tempImage[i][j].rgbtRed = round(totalRed / (float) counter); tempImage[i][j].rgbtGreen = round(totalGreen / (float) counter); tempImage[i][j].rgbtBlue = round(totalBlue / (float) counter); } } // replace the blurred image to the original image for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtRed = tempImage[i][j].rgbtRed; image[i][j].rgbtGreen = tempImage[i][j].rgbtGreen; image[i][j].rgbtBlue = tempImage[i][j].rgbtBlue; } } return; } // Detect edges void edges(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE temp[height][width]; int gx[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int gy[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int gxBlue = 0; int gyBlue = 0; int gxGreen = 0; int gyGreen = 0; int gxRed = 0; int gyRed = 0; for (int r = -1; r < 2; r++) { for (int c = -1; c < 2; c++) { if (i + r < 0 || i + r > height - 1) { continue; } if (j + c < 0 || j + c > width - 1) { continue; } gxBlue += image[i + r][j + c].rgbtBlue * gx[r + 1][c + 1]; gyBlue += image[i + r][j + c].rgbtBlue * gy[r + 1][c + 1]; gxGreen += image[i + r][j + c].rgbtGreen * gx[r + 1][c + 1]; gyGreen += image[i + r][j + c].rgbtGreen * gy[r + 1][c + 1]; gxRed += image[i + r][j + c].rgbtRed * gx[r + 1][c + 1]; gyRed += image[i + r][j + c].rgbtRed * gy[r + 1][c + 1]; } } int blue = round(sqrt(gxBlue * gxBlue + gyBlue * gyBlue)); int green = round(sqrt(gxGreen * gxGreen + gyGreen * gyGreen)); int red = round(sqrt(gxRed * gxRed + gyRed * gyRed)); temp[i][j].rgbtBlue = (blue > 255) ? 255 : blue; temp[i][j].rgbtGreen = (green > 255) ? 255 : green; temp[i][j].rgbtRed = (red > 255) ? 255 : red; } } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtBlue = temp[i][j].rgbtBlue; image[i][j].rgbtGreen = temp[i][j].rgbtGreen; image[i][j].rgbtRed = temp[i][j].rgbtRed; } } return; } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include "helpers.h" #include <math.h> #include <stdbool.h> // Convert image to grayscale void grayscale(int height, int width, RGBTRIPLE image[height][width]) { int avgRGB; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int Red = image[i][j].rgbtRed; int Green = image[i][j].rgbtGreen; int Blue = image[i][j].rgbtBlue; avgRGB = round((Red + Green + Blue) / (float) 3); image[i][j].rgbtRed = avgRGB; image[i][j].rgbtGreen = avgRGB; image[i][j].rgbtBlue = avgRGB; } } return; } // Reflect image horizontally void reflect(int height, int width, RGBTRIPLE image[height][width]) { // iterate the height for (int i = 0; i < height; i++) { // iterate the `half of width` for (int j = 0; j < (width / 2); j++) { // get temp color in pixel int tempRed = image[i][j].rgbtRed; int tempGreen = image[i][j].rgbtGreen; int tempBlue = image[i][j].rgbtBlue; // then swap color from reflect pixel image[i][j].rgbtRed = image[i][width - j - 1].rgbtRed; image[i][j].rgbtGreen = image[i][width - j - 1].rgbtGreen; image[i][j].rgbtBlue = image[i][width - j - 1].rgbtBlue; // record temp color to reflect pixel image[i][width - j - 1].rgbtRed = tempRed; image[i][width - j - 1].rgbtGreen = tempGreen; image[i][width - j - 1].rgbtBlue = tempBlue; } } return; } // Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { // create a temp image to record blurred pixel RGBTRIPLE tempImage[height][width]; // iterate the height for (int i = 0; i < height; i++) { // iterate the width for (int j = 0; j < width; j++) { int totalRed = 0; int totalGreen = 0; int totalBlue = 0; int counter = 0; // get the near 9 pixels for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { int nearX = i + x; int nearY = j + y; // check is valid the near pixels bool invalidX = nearX < 0 || nearX > (height - 1); bool invalidY = nearY < 0 || nearY > (width - 1); if (invalidX || invalidY) continue; // skip this round, next iterator // records the pixels value totalRed += image[nearX][nearY].rgbtRed; totalGreen += image[nearX][nearY].rgbtGreen; totalBlue += image[nearX][nearY].rgbtBlue; counter++; } } // count the avg of near pixels, and record to temp tempImage[i][j].rgbtRed = round(totalRed / (float) counter); tempImage[i][j].rgbtGreen = round(totalGreen / (float) counter); tempImage[i][j].rgbtBlue = round(totalBlue / (float) counter); } } // replace the blurred image to the original image for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtRed = tempImage[i][j].rgbtRed; image[i][j].rgbtGreen = tempImage[i][j].rgbtGreen; image[i][j].rgbtBlue = tempImage[i][j].rgbtBlue; } } return; } // Detect edges void edges(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE temp[height][width]; int gx[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int gy[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int gxBlue = 0; int gyBlue = 0; int gxGreen = 0; int gyGreen = 0; int gxRed = 0; int gyRed = 0; for (int r = -1; r < 2; r++) { for (int c = -1; c < 2; c++) { if (i + r < 0 || i + r > height - 1) continue; if (j + c < 0 || j + c > width - 1) continue; gxBlue += image[i + r][j + c].rgbtBlue * gx[r + 1][c + 1]; gyBlue += image[i + r][j + c].rgbtBlue * gy[r + 1][c + 1]; gxGreen += image[i + r][j + c].rgbtGreen * gx[r + 1][c + 1]; gyGreen += image[i + r][j + c].rgbtGreen * gy[r + 1][c + 1]; gxRed += image[i + r][j + c].rgbtRed * gx[r + 1][c + 1]; gyRed += image[i + r][j + c].rgbtRed * gy[r + 1][c + 1]; } } int blue = round(sqrt(gxBlue * gxBlue + gyBlue * gyBlue)); int green = round(sqrt(gxGreen * gxGreen + gyGreen * gyGreen)); int red = round(sqrt(gxRed * gxRed + gyRed * gyRed)); temp[i][j].rgbtBlue = (blue > 255) ? 255 : blue; temp[i][j].rgbtGreen = (green > 255) ? 255 : green; temp[i][j].rgbtRed = (red > 255) ? 255 : red; } } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j].rgbtBlue = temp[i][j].rgbtBlue; image[i][j].rgbtGreen = temp[i][j].rgbtGreen; image[i][j].rgbtRed = temp[i][j].rgbtRed; } } return; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/rk5BnZ3Qi.png) 驗證 ![](https://hackmd.io/_uploads/ryu1hW2Xj.png) --- ### 作業: [Recover](https://cs50.harvard.edu/x/2022/psets/4/recover/) 記憶卡檔案用 hex editor 打開時,會看到的彩蛋 XD ![](https://hackmd.io/_uploads/SkxKTbhXj.png) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> typedef uint8_t BYTE; int main(int argc, char *argv[]) { // must have argument (input file) if (argc != 2) { printf("Usage: ./recover card.raw\n"); return 1; } // read file data FILE *file = fopen(argv[1], "r"); // ensure file is valid if (file == NULL) { printf("Could not open file"); return 2; } // initial variables BYTE buffer[512]; FILE *img = NULL; char filename[8]; int img_count = 0; // read file, and store to buffer while (fread(buffer, sizeof(char), 512, file)) { // use bitwise operator check 4th bit is valid // 0xe0 = 1110 0000 // 0xe1 = 1110 0001 // 0xe2 = 1110 0010 // 0xe3 = 1110 0011 // 0xe4 = 1110 0100 // 0xe5 = 1110 0101 // 0xe6 = 1110 0110 // 0xe7 = 1110 0111 // 0xe8 = 1110 1000 // 0xe9 = 1110 1001 // 0xea = 1110 1010 // 0xeb = 1110 1011 // 0xec = 1110 1100 // 0xed = 1110 1101 // 0xee = 1110 1110 // 0xef = 1110 1111 // & 0xf0 = 1111 0000 // when use & 0xf0, it means Upper part value will be change to 0xe0 bool valid_4th_bit = (buffer[3] & 0xf0) == 0xe0; // if is a JPEG (start with 0xff 0xd8 0xff ...) if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && valid_4th_bit) { // fix memory leak issue if (img_count > 0) { fclose(img); } // set value to filename (e.g. 000.jpg, 001.jpg, 002.jpg ...) sprintf(filename, "%03i.jpg", img_count); // create file for output img = fopen(filename, "w"); img_count++; } // check img must be valid, then fwrite if (img != NULL) { fwrite(buffer, sizeof(char), 512, img); } } fclose(img); fclose(file); return 0; } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> typedef uint8_t BYTE; int main(int argc, char *argv[]) { // must have argument (input file) if (argc != 2) { printf("Usage: ./recover card.raw\n"); return 1; } // read file data FILE *file = fopen(argv[1], "r"); // ensure file is valid if (file == NULL) { printf("Could not open file"); return 2; } // initial variables BYTE buffer[512]; FILE *img = NULL; char filename[8]; int img_count = 0; // read file, and store to buffer while (fread(buffer, sizeof(char), 512, file)) { // use bitwise operator check 4th bit is valid // 0xe0 = 1110 0000 // 0xe1 = 1110 0001 // 0xe2 = 1110 0010 // 0xe3 = 1110 0011 // 0xe4 = 1110 0100 // 0xe5 = 1110 0101 // 0xe6 = 1110 0110 // 0xe7 = 1110 0111 // 0xe8 = 1110 1000 // 0xe9 = 1110 1001 // 0xea = 1110 1010 // 0xeb = 1110 1011 // 0xec = 1110 1100 // 0xed = 1110 1101 // 0xee = 1110 1110 // 0xef = 1110 1111 // & 0xf0 = 1111 0000 // when use & 0xf0, it means Upper part value will be change to 0xe0 bool valid_4th_bit = (buffer[3] & 0xf0) == 0xe0; // if is a JPEG (start with 0xff 0xd8 0xff ...) if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && valid_4th_bit) { // fix memory leak issue if (img_count > 0) fclose(img); // set value to filename (e.g. 000.jpg, 001.jpg, 002.jpg ...) sprintf(filename, "%03i.jpg", img_count); // create file for output img = fopen(filename, "w"); img_count++; } // check img must be valid, then fwrite if (img != NULL) fwrite(buffer, sizeof(char), 512, img); } fclose(img); fclose(file); return 0; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/S16Ptz3Qj.png) 驗證 ![](https://hackmd.io/_uploads/SyMNtz2mo.png)