Try   HackMD

(2022年) CS50 week4

其實之前就已經修完 CS50 了,不過因應 2022 年將課堂作業的系統
c9.io 換到 github codespace + vscode 整合
打算來重溫一下裡面的作業,並暖身一下 C 語言的手感

由於已經有許多前輩分享課程與作業的心得
加上官網教材的投影片、重點筆記、教學影片都非常完整
故不再做詳細的紀錄,專注在作業 (Lab, Problem sets) 上面

https://cs50.harvard.edu/x/2022/weeks/4/


Lab4: Volume

(點擊展開) 符合 style50 風格的程式碼
// 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);
}

(點擊展開) 個人覺得比較好讀的程式碼風格

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Filter_less

(點擊展開) 符合 style50 風格的程式碼
#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;
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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;
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Filter_more

(點擊展開) 符合 style50 風格的程式碼
#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;
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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;
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Recover

記憶卡檔案用 hex editor 打開時,會看到的彩蛋 XD

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

(點擊展開) 符合 style50 風格的程式碼
#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;
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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;
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →