目录

Harvard CS50 学习笔记(四)

摘要
Harvard CS50 学习笔记(四)。

4 Memory

4.1 Lecture

4.1.1 Storing finite information

4.1.2 Pixel art

4.1.3 RGB

4.1.4 Hexadecimal

  • 16 进制一般前面有 0x,用于与 10 进制区分。0x11=17

4.1.5 Memory addresses

4.1.6 address.c

4.1.7 Pointers

  • 指针,是用于记录值的内存地址变量。

4.1.8 Declaring pointers

  1. 单个 &,是address operator(地址运算符)。

  2. &i 表示取变量 i 的地址

  3. * 表示要记录指针(声明指针变量)

    1
    2
    3
    4
    
    int n = 50;
    // 定义一个指向int型的指针变量p,并用n的地址来初始化p
    int *p = &n;
    printf("%p\n", p);
    

4.1.9 “Address of”

4.1.10 Dereference operator

  1. deference operator(引用解析运算符)—— *
  2. reference——(变量的引用)。
  3. dereference——其实就是de(反)- reference(引用),即**(指针的)变量**。
  4. 一个 *,表示我们要获取reference(引用),即地址值。
  5. 再加一个 *,表示我们要反引用,也译为解引用,就是获取那个引用(地址)所储存的值(获取到之后其实可以改变地址所存储的值)。

4.1.11 Visualizing pointers

  • 现在指针一般都是8字节(64比特)。

4.1.12 Assignment operators

  1. C 中,不会自动做什么事情。
  2. 如果有一个变量 n =50,其指针为 p =0x123
  3. 此时创建一个新变量 c = np 不会有任何变化。

4.1.13 Strings in memory

/images/Harvard_CS50/Lecture_4/string.png
string
  • 字符串变量,实质为指向第一个字符地址的指针。

4.1.14 char *

  • string s = "HI!"; 等同于 char *s = "HI!";

4.1.15 Different Variables with Different Pointers

/images/Harvard_CS50/Lecture_4/address_1.png /images/Harvard_CS50/Lecture_4/address_2.png
  • 为什么打印的结果不同?

4.1.16 address.c

  • 结果不同的原因解析:
    1. 右边比较好理解,字符串变量的地址,与字符串第一个字符的地址相同。
    2. 左边的关键在于,第 7 行,把字符串的第一个字符 H,赋值给了一个新的变量 c,此操作在内存里进行了复制,也就是内存中多了一个新的变量 c,在不同的位置,储存着与字符串第一个字符相同的字符 H
    3. 再打印变量 c 的地址,自然与字符串变量 s 的地址不同。

4.1.17 Pointers to array values

/images/Harvard_CS50/Lecture_4/array_pointer_1.png /images/Harvard_CS50/Lecture_4/array_pointer_2.png
  1. 左图比较好理解。
  2. 为什么右图的第 22 行打印出了不一样的地址?因为那是指针的地址
  3. 基本类型如果要获取地址值,需要在变量名前加 &
  4. 数组与字符串(底层就是数组)不需要。

4.1.18 Defining strings

  • <cs50.h> 中的 string 类型实质为 typedef char *string;

4.1.19 Pointer arithmetic

/images/Harvard_CS50/Lecture_4/array_pointer_3.png
array_pointer_3
  • 注意,这里的 +1 操作,加了 4 个字节,因为一个 int4 字节,而不是加 1 个字节或 1 个比特,编译器帮我们处理了。

4.1.20 Arrays as pointers

  1. 还是上图,此处并没有用 & 符号来表示数组的地址,但打印的时候,却使用了 * 符号来解析地址。
  2. 因为可以把数组的变量名,直接作为指针使用
  3. 可以把数组,当作指向其第一个元素的指针

4.1.21 Comparing integers

4.1.22 Comparing strings

4.1.23 Copying values

/images/Harvard_CS50/Lecture_4/copying_values_1.png
copying_values
  • 复制的是指针,并没有复制值,也就是引用传递。

    /images/Harvard_CS50/Lecture_4/copying_values_2.png

4.1.24 malloc and free

  1. malloc() 申请内存。
  2. free() 释放内存。
  3. 需要 #include <stdlib.h>
  4. 实际上,这个 malloc() 就相当于 Java 里面的 new 一样,只是 Java 把各种细节给你封装抽象成一个 newGC 会自动给你回收,不需要自己去 free()

4.1.25 Copying with malloc and free

4.1.26 Valgrind

  • 检查与内存相关的潜在BUG。

4.1.27 Garbage values

  • 不初始化,就会有无法预测的垃圾值。

4.1.28 Binky Pointer Fun

  • 试图deference(引用解析)垃圾值,会造成错误。

4.1.29 Swap

4.1.30 swap.c

/images/Harvard_CS50/Lecture_4/swap_1.png
swap_1
  • 没有传递引用,复制了值,原本的值不变。

4.1.31 Stack and heap

4.1.32 Visualizing swap.c

4.1.33 Pointers in swap.c

/images/Harvard_CS50/Lecture_4/swap_2.png
swap_2

4.1.34 scanf

4.1.35 Segmentation fault

4.1.36 Header bytes

4.1.37 Filter


4.2 Shorts

4.2.1 Hexadecimal

/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_1.png
hexadecimal_1
/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_2.png
hexadecimal_2
/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_3.png
hexadecimal_3
/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_4.png
hexadecimal_4
/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_5.png
hexadecimal_5
/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_6.png
hexadecimal_6
/images/Harvard_CS50/Lecture_4/hexadecimal/hexadecimal_7.png
hexadecimal_7

4.2.2 Pointers

/images/Harvard_CS50/Lecture_4/pointers/pointers_1.png
pointers_1
/images/Harvard_CS50/Lecture_4/pointers/pointers_2.png
pointers_2
/images/Harvard_CS50/Lecture_4/pointers/pointers_3.png
pointers_3
/images/Harvard_CS50/Lecture_4/pointers/pointers_4.png
pointers_4
/images/Harvard_CS50/Lecture_4/pointers/pointers_5.png
pointers_5
/images/Harvard_CS50/Lecture_4/pointers/pointers_6.png
pointers_6
  • 指针就是地址值。

/images/Harvard_CS50/Lecture_4/pointers/pointers_7.png
pointers_7
/images/Harvard_CS50/Lecture_4/pointers/pointers_8.png
pointers_8
/images/Harvard_CS50/Lecture_4/pointers/pointers_9.png
pointers_9
  • 指针的类型就是其指向地址值数据的类型。
/images/Harvard_CS50/Lecture_4/pointers/pointers_10.png
pointers_10
  • 指针必须初始化,如果初始化的事情没有明确的值,就指向空(NULL)。

/images/Harvard_CS50/Lecture_4/pointers/pointers_11.png
pointers_11
/images/Harvard_CS50/Lecture_4/pointers/pointers_12.png
pointers_12
/images/Harvard_CS50/Lecture_4/pointers/pointers_13.png
pointers_13
/images/Harvard_CS50/Lecture_4/pointers/pointers_14.png
pointers_14
/images/Harvard_CS50/Lecture_4/pointers/pointers_15.png
pointers_15
/images/Harvard_CS50/Lecture_4/pointers/pointers_16.png
pointers_16
/images/Harvard_CS50/Lecture_4/pointers/pointers_17.png
pointers_17
/images/Harvard_CS50/Lecture_4/pointers/pointers_18.png
pointers_18
/images/Harvard_CS50/Lecture_4/pointers/pointers_19.png
pointers_19

4.2.3 Defining Custom Types

/images/Harvard_CS50/Lecture_4/defining_custom_types/defining_custom_types_1.png
defining_custom_types_1
/images/Harvard_CS50/Lecture_4/defining_custom_types/defining_custom_types_2.png
defining_custom_types_2
/images/Harvard_CS50/Lecture_4/defining_custom_types/defining_custom_types_3.png
defining_custom_types_3
/images/Harvard_CS50/Lecture_4/defining_custom_types/defining_custom_types_4.png
defining_custom_types_4
/images/Harvard_CS50/Lecture_4/defining_custom_types/defining_custom_types_5.png
defining_custom_types_5
/images/Harvard_CS50/Lecture_4/defining_custom_types/defining_custom_types_6.png
defining_custom_types_6

4.2.4 Dynamic Memory Allocation

/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_1.png
dynamic_memory_allocation_1
  • 一般有名字的变量在栈,没名字的在堆。

/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_2.png
dynamic_memory_allocation_2
  • 堆与栈实质为一块内存空间的不同部分。

/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_3.png
dynamic_memory_allocation_3
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_4.png
dynamic_memory_allocation_4
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_5.png
dynamic_memory_allocation_5
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_6.png
dynamic_memory_allocation_6
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_7.png
dynamic_memory_allocation_7
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_8.png
dynamic_memory_allocation_8
  1. 使用 malloc() 必须释放内存。
  2. 只有 malloc() 使用的内存需要被释放(静态声明在堆的变量不需要释放)。
  3. 不要重复释放。

/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_9.png
dynamic_memory_allocation_9
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_10.png
dynamic_memory_allocation_10
/images/Harvard_CS50/Lecture_4/dynamic_memory_allocation/dynamic_memory_allocation_11.png
dynamic_memory_allocation_11

4.2.5 Call Stacks

/images/Harvard_CS50/Lecture_4/call_tacks/call_tacks_1.png
call_tacks_1
/images/Harvard_CS50/Lecture_4/call_tacks/call_tacks_2.png
call_tacks_2

4.2.6 File Pointers

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_1.png
file_pointers_1
  1. C 操作文件有抽象的数据类型,叫 FILE
  2. 一般情况下,只要操作文件,都用文件的指针,即 FILE*

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_2.png
file_pointers_2
  • 文件相关的函数,都在 stdio.h 里。

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_3.png
file_pointers_3
  1. 打开一个文件,即获取这个文件的指针。
  2. 确保 NULL 的检查。
  3. 操作可以为 r-readw-writea-append

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_4.png
file_pointers_4
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_5.png
file_pointers_5
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_6.png
file_pointers_6
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_7.png
file_pointers_7
  • 关闭文件指针。

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_8.png
file_pointers_8
  1. 读字符函数。
  2. 获取文件的下一个字符。
  3. 打开文件的方式必须为 r-read

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_9.png
file_pointers_9
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_10.png
file_pointers_10
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_11.png
file_pointers_11
  1. 可通过循环读取整个文件。
  2. EOF 表示 End Of File。

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_12.png
file_pointers_12
  1. 写字符函数。
  2. 将字符写入文件。
  3. 打开文件的方式必须为 w-wirtea-append

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_13.png
file_pointers_13
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_14.png
file_pointers_14
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_15.png
file_pointers_15
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_16.png
file_pointers_16
  • 可通过循环读与写,实现文件复制。

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_17.png
file_pointers_17
  1. 读文件函数,参数从右往左看。
  2. <file pointer> 为文件指针,必须是读指针。
  3. <qty> 读文件的数据块的数量。
  4. <size> 读文件的数据块的大小(单位为字节)。
  5. <buffer> 内存中的缓存区域,用于存放读到的数据,需要用指针表示(数组名本身为指针)。

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_18.png
file_pointers_18
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_19.png
file_pointers_19
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_20.png
file_pointers_20
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_21.png
file_pointers_21
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_22.png
file_pointers_22
  1. 写文件函数,参数从右往左看。
  2. <file pointer> 为文件指针,必须是写指针。
  3. <qty> 读文件的数据块的数量。
  4. <size> 读文件的数据块的大小(单位为字节)。
  5. <buffer> 内存中的缓存区域,用于存放要写的数据,需要用指针表示(数组名本身为指针)。

/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_23.png
file_pointers_23
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_24.png
file_pointers_24
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_25.png
file_pointers_25
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_26.png
file_pointers_26
/images/Harvard_CS50/Lecture_4/file_pointers/file_pointers_27.png
file_pointers_27

4.3 Lab 4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 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]);

    // TODO: Copy header from input file to output file
    uint8_t header[HEADER_SIZE];
    int length1 = sizeof(header)/sizeof(uint8_t);

    fread(header, length1, 1, input);
    fwrite(header, length1, 1, output);

    // TODO: Read samples from input file and write updated data to output file

      // 注释掉的方法,确实可以完成需求,但是不能通过检测
    // int16_t buffer[4096];
    // int length2 = sizeof(buffer)/sizeof(int16_t);
    // while (!feof(input)) {
    //     fread(buffer, length2, 1, input);

    //     for (int i = 0; i< length2; i++) {

    //         buffer[i] *= factor;
    //     }
    //     fwrite(buffer, length2, 1, output);
    // }

    int16_t buffer;
    while(fread(&buffer, sizeof(int16_t), 1, input)) {
        buffer *= factor;
        fwrite(&buffer, sizeof(int16_t), 1, output);
    }


    // Close files
    fclose(input);
    fclose(output);
}

4.4 Problem Set 4

4.4.1 FIlter

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "helpers.h"
#include <math.h>


// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
          	// 求平均即可
            BYTE average = round((image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed) / 3.0);
            image[i][j].rgbtBlue = average;
            image[i][j].rgbtGreen = average;
            image[i][j].rgbtRed = average;
        }
    }
    return;
}

// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{

    for (int i = 0; i < height; i++) {
        for (int j = 0; j < (width / 2); j++) {
          	// 调换顺序即可
            RGBTRIPLE temp;
            temp = image[i][j];
            image[i][j] = image[i][width - 1 - j];
            image[i][width - j - 1] = temp;
        }
    }

    return;
}

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
  	// 用一个新图片储存改变后的数据,修改原图片会导致计算异常
    RGBTRIPLE temp[height][width];
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
          	// 数组记录每个像素的相对坐标
            int arr[] = {-1, 0, 1};
            int red = 0;
            int blue = 0;
            int green = 0;
          	// 记录参与计算的像素数
            int count = 0;
            for (int k = 0; k < sizeof(arr)/sizeof(int); k++) {
                for (int l = 0; l < sizeof(arr)/sizeof(int); l++) {
                    int x = j + arr[l];
                    int y = i + arr[k];
                  	// 越界情况排除
                    if (x < 0 || x >= width || y < 0 || y >= height) {
                        continue;
                    } else {
                        red += image[y][x].rgbtRed;
                        blue += image[y][x].rgbtBlue;
                        green += image[y][x].rgbtGreen;
                        count++;
                    }
                }
            }
        // 计算
        temp[i][j].rgbtRed = round(red * 1.0 / count);
        temp[i][j].rgbtBlue = round(blue * 1.0 / count);
        temp[i][j].rgbtGreen = round(green * 1.0 / count);
        }
    }
  	// 新图片替代旧图片
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            image[i][j] = temp[i][j];
        }
    }
    return;
}

// Detect edges
void edges(int height, int width, RGBTRIPLE image[height][width])
{
  	// 用一个新图片储存改变后的数据,修改原图片会导致计算异常
    RGBTRIPLE temp[height][width];
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
          	// 数组记录每个像素的相对坐标
            int arr[] = {-1, 0, 1};
            int redX = 0;
            int blueX = 0;
            int greenX = 0;
            int redY = 0;
            int blueY = 0;
            int greenY = 0;
          	// 记录计算次数(总共2次)
            int count = 0;
            while (count < 2) {
              	// X 方向计算
                for (int k = 0; k < sizeof(arr)/sizeof(int); k++) {
                    for (int l = 0; l < sizeof(arr)/sizeof(int); l++) {
                        int x = j + arr[l];
                        int y = i + arr[k];
                        if (count == 0) {
                            if (y != i) {
                                if (x < 0 || x >= width || y < 0 || y >= height) {
                                    continue;
                                }
                                redX += image[y][x].rgbtRed * arr[l];
                                blueX += image[y][x].rgbtBlue * arr[l];
                                greenX += image[y][x].rgbtGreen * arr[l];
                            } else {
                                if (x < 0 || x >= width || y < 0 || y >= height) {
                                    continue;
                                }
                                redX += image[y][x].rgbtRed * arr[l] * 2;
                                blueX += image[y][x].rgbtBlue * arr[l] * 2;
                                greenX += image[y][x].rgbtGreen * arr[l] * 2;
                            }

                        }
                      	// Y 方向计算
                        if (count == 1) {
                            if (x != j) {
                                if (x < 0 || x >= width || y < 0 || y >= height) {
                                    continue;
                                }
                                redY += image[y][x].rgbtRed * arr[k];
                                blueY += image[y][x].rgbtBlue * arr[k];
                                greenY += image[y][x].rgbtGreen * arr[k];
                            } else {
                                if (x < 0 || x >= width || y < 0 || y >= height) {
                                    continue;
                                }
                                redY += image[y][x].rgbtRed * arr[k] * 2;
                                blueY += image[y][x].rgbtBlue * arr[k] * 2;
                                greenY += image[y][x].rgbtGreen * arr[k] * 2;
                            }

                        }
                    }
                }
                count++;
            }
          	// 计算
            temp[i][j].rgbtRed = ((round(fabs(sqrt(redX * redX + redY * redY)))) > 255) ? 255 : round(fabs(sqrt(redX * redX + redY * redY)));
            temp[i][j].rgbtBlue = ((round(fabs(sqrt(blueX * blueX + blueY * blueY)))) > 255) ? 255 : round(fabs(sqrt(blueX * blueX + blueY * blueY)));
            temp[i][j].rgbtGreen = ((round(fabs(sqrt(greenX * greenX + greenY * greenY)))) > 255) ? 255 : round(fabs(sqrt(greenX * greenX + greenY * greenY)));
        }
    }
  	// 新图片替代旧图片
    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            image[i][j] = temp[i][j];
        }
    }
    return;
}

4.4.2 Recover

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cs50.h>

int main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("Usage: ./recover image\n");
        return 1;
    }

    FILE *file = fopen(argv[1], "r");
    if (file == NULL)
    {
        printf("Could not open file.\n");
        return 1;
    }

  	// jpg 的头
    char first = 0xff;
    char second = 0xd8;
    char third = 0xff;
    int fourth = 0xe0;

  	// 文件名
    int name = -1;

    FILE *img = NULL;
    bool flag = false;
    char buffer[512];

  	// 循环读
    while(fread(buffer, sizeof(char), 512, file)) {

        if (buffer[0] == first && buffer[1] == second && buffer[2] == third && (buffer[3] & 0xf0) == fourth) {

            flag = true;

          	// 第一次不关闭,之后先关闭旧文件,再打开新文件
            if (name != -1) {
                fclose(img);
            }

            name++;
            char fileName[8];
            sprintf(fileName, "%03i.jpg", name);
            img = fopen(fileName, "a");

        }

        if (flag) {
            fwrite(buffer, sizeof(char), 512, img);
        }

    }

    fclose(file);
    return 0;
}