C - Book Note


出于某些原因,全面复习一下C还是有必要的。

那就让我们快速复习、记录一下吧。

后面接着转战C++

Win 开发环境设置

C 环境设置

  • MinGW 下载对应的GCC
    • 下载MinGW Installation Manager
    • 选择安装GCC bin相关的就好
    • 其他的功能暂不需要
  • IDE 我使用的是Visual Studio Code,安装上C/C++插件就可以撸代码了

Hello world!

#include <stdio.h>
#include <stdlib.h>

int main() {

    printf("hello world! \n");
    system("pause");

    return 0;
}

运行输出:

PS D:\jave\Work Files\C\Studies\1 hello world> gcc .\hello_world.c -o out
PS D:\jave\Work Files\C\Studies\1 hello world> .\out.exe
hello world!

printf format test

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main() {

    int size = 5555;
    unsigned int usize = ((unsigned int)-1) - UINT_MAX;
    float fsize = 555.123456;
    long double ldsize = 555.123456;
    char c = 'm';
    char str[20] = "this is your name";
    int* p = &size;
    int negNum = -1;
    printf("d       : %d       \n",            size);    // d       : 5555
    printf("000d    : %000d    \n",            size);    // 000d    : 5555
    printf("###d    : %###d    \n",            size);    // ###d    : 5555
    printf("--d     : %--d     \n",            size);    // --d     : 5555
    printf("++d     : %++d     \n",            size);    // ++d     : +5555
    printf("   d    : %   d    \n",            size);    //    d    :  5555
    printf("3d      : %3d      \n",            size);    // 3d      : 5555
    printf("6d      : %6d      \n",            size);    // 6d      :   5555
    printf("06d     : %06d     \n",            size);    // 06d     : 005555
    printf("ld      : %ld      \n",            size);    // ld      : 5555
    printf("o       : %o       \n",            size);    // o       : 12663
    printf("x       : %x       \n",            size);    // x       : 15b3
    printf("X       : %X       \n",            size);    // X       : 15B3
    printf("0X      : %0X      \n",            size);    // 0X      : 15B3
    printf("u       : %u       \n",            usize);   // u       : 0
    printf("#X      : %#X      \n",            size);    // #X      : 0X15B3
    printf("#x      : %#x      \n",            size);    // #x      : 0x15b3
    printf("f       : %f       \n",            fsize);   // f       : 555.123474
    printf("e       : %e       \n",            fsize);   // e       : 5.551235e+002
    printf("E       : %E       \n",            fsize);   // E       : 5.551235E+002
    printf("g       : %g       \n",            fsize);   // g       : 555.123
    printf("G       : %G       \n",            fsize);   // G       : 555.123
    printf(".2f     : %.2f     \n",            fsize);   // .2f     : 555.12
    printf(".3e     : %.3e     \n",            fsize);   // .3e     : 5.551e+002
    printf(".4E     : %.4E     \n",            fsize);   // .4E     : 5.5512E+002
    printf(".5g     : %.5g     \n",            fsize);   // .5g     : 555.12
    printf(".6G     : %.6G     \n",            fsize);   // .6G     : 555.123
    printf(".*f     : %.*f     \n",            fsize);   // .*f     : 0.000000
    printf(".*e     : %.*e     \n",            fsize);   // .*e     : 5.346871e-315
    printf(".*E     : %.*E     \n",            fsize);   // .*E     : 5.346871E-315
    printf(".*g     : %.*g     \n",            fsize);   // .*g     : 5.34687e-315
    printf(".*G     : %.*G     \n",            fsize);   // .*G     : 5.34687E-315
    printf("p       : %p       \n",            p);       // p       : 0061FEFC
    printf("d       : %d       \n",            *p);      // d       : 5555
    printf("c       : %c       \n",            c);       // c       : m
    printf("s       : %s       \n",            str);     // s       : this is your name
    printf("u       : %u       \n",            negNum);  // u       : 4294967295
    printf("lu      : %lu      \n",            negNum);  // lu      : 4294967295
    printf("llu     : %llu     \n",            negNum);  // llu     : 4648094134073032703
    system("pause");

    return 0;
}


PS D:\jave\Work Files\C\Studies\2 printf_format> gcc .\printf_format.c -o out                                           PS D:\jave\Work Files\C\Studies\2 printf_format> .\out.exe                                                              d       : 5555
000d    : 5555
###d    : 5555
--d     : 5555
++d     : +5555
   d    :  5555
3d      : 5555
6d      :   5555
06d     : 005555
ld      : 5555
o       : 12663
x       : 15b3
X       : 15B3
0X      : 15B3
u       : 0
#X      : 0X15B3
#x      : 0x15b3
f       : 555.123474
e       : 5.551235e+002
E       : 5.551235E+002
g       : 555.123
G       : 555.123
.2f     : 555.12
.3e     : 5.551e+002
.4E     : 5.5512E+002
.5g     : 555.12
.6G     : 555.123
.*f     : 0.000000
.*e     : 5.346871e-315
.*E     : 5.346871E-315
.*g     : 5.34687e-315
.*G     : 5.34687E-315
p       : 0061FEFC
d       : 5555
c       : m
s       : this is your name
u       : 4294967295
lu      : 4294967295
llu     : 4648094134073032703

define variable test

#include <stdio.h>
#include <stdlib.h>

int main() {
    
    float f_var = 210.0f;
    double ff_var = 2.123456789E+10;
    printf("f_var=%.2f\n", f_var);
    printf("ff_var=%.2e\n", ff_var);
    system("pause");

    return 0;
}

extern var test

a.c

#include <stdio.h>

extern int a;
extern int b;
int c;
extern int d;

int sum() {
    return a+b+c+d;
}

int main() {
    printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);

    printf("a+b=%d\n",a+b);
    printf("c+a=%d\n",c+a);
    printf("c+d=%d\n",c+d);
    printf("sum()=%d\n",sum());
    return 0;
}

b.c

int a = 1;
int b = 2;

extern int c;

int d = 3;
PS D:\jave\Work Files\C\Studies\extern var> gcc .\a.c .\b.c -o out
PS D:\jave\Work Files\C\Studies\extern var> .\out.exe
a=1,b=2,c=0,d=3
a+b=3
c+a=1
c+d=3
sum()=6

time interval test

#include <stdio.h>
#include <time.h>

#define TIME 1000000000
int m, n = TIME; /* 全局变量 */

int main(void)
{   
    time_t start, stop;
    register int a, b = TIME; /* 寄存器变量 */
    int x, y = TIME;          /* 一般变量   */

    time(&start);
    for (a = 0; a < b; a++);
    time(&stop);
    printf("register var use time: %ld s\n", stop - start);
    
    time(&start);
    for (x = 0; x < y; x++);
    time(&stop);
    printf("auto var use time: %ld s\n", stop - start);
    
    time(&start);
    for (m = 0; m < n; m++);
    time(&stop);
    printf("global var use time: %ld s\n", stop - start);

    return 0;
}
PS D:\jave\Work Files\C\Studies\5 test time> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\5 test time> .\out.exe
register var use time: 0 s
auto var use time: 2 s
global var use time: 2 s

time detail test

common.h

/*common.h*/
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <stdarg.h>

#define SPLIT_LINE(title)\
printf("============ " #title " ==========\n");
#define LINE printf("\n");
#define LINE_F(format,args...) printf(#format "\n", args);
#define STR(msg) printf(#msg "\n");

#endif

asctime test

#include <time.h>
#include "common.h"

typedef struct tm TM;

int main() {
    SPLIT_LINE(asctime test start)

    TM tm;

    tm.tm_year  = 2020;
    tm.tm_mon   = 4;
    tm.tm_mday  = 21;
    tm.tm_hour  = 16;
    tm.tm_min   = 28;
    tm.tm_sec   = 18;

    LINE_F(asctime(%p):%s, &tm, asctime(&tm));

    SPLIT_LINE(asctime test end)
    LINE
    return 0;
}

============ asctime test start ==========
asctime(0061FEFC):Sun May 21 16:28:18 3920

============ asctime test end ==========

clock per second test

#include <time.h>
#include "common.h"

int main() {

    SPLIT_LINE(CLOCKS_PER_SEC test start)
    LINE_F("CLOCKS_PER_SEC:%d", CLOCKS_PER_SEC);
    SPLIT_LINE(CLOCKS_PER_SEC test end)
    LINE

    /*
    ============ CLOCKS_PER_SEC test start ==========
    "CLOCKS_PER_SEC:1000"
    ============ CLOCKS_PER_SEC test end ==========
    */

    return 0;
}

clock test

/*clock.c*/
#include <time.h>
#include <Windows.h>
#include "common.h"

int main() {

    SPLIT_LINE(clock test start)

    clock_t start, end;
    double elapsed;

    // 耗时:秒
    #define ET_S (double)(end - start) / CLOCKS_PER_SEC
    // 耗时:毫秒
    #define ET_MS (end - start)

    STR( --- 10000000 loop test --- )
    start = clock();
    for (size_t i = 0; i < 10000000; i++) {
        // noops
    }
    end = clock();
    LINE_F("elapsed time : %lfs", ET_S);
    
    STR( --- Sleep(1000) test ---)
    start = clock();
    Sleep(1000);
    end = clock();
    printf("elapsed time : %lfs, start : %ld, end : %ld\n", ET_S, start, end);

    SPLIT_LINE(clock test end)
    LINE

    return 0;
}
============ clock test start ==========
--- 10000000 loop test ---
"elapsed time : 0.014000s"
--- Sleep(1000) test ---
elapsed time : 1.002000s, start : 14, end : 1016
============ clock test end ==========

ctime test

#include <time.h>
#include "common.h"

// char *ctime(const time_t *timer)

int main() {
    time_t curtime;
    time(&curtime);
    LINE_F(current time : %s, ctime(&curtime))
    return 0;
}
// current time : Tue Apr 21 17:47:17 2020

difftime test

#include <time.h>
#include <Windows.h>
#include "common.h"

// double difftime(time_t time1, time_t time2)

int main() {

    time_t start;
    time_t end;

    time(&start); // all elapsed seconds from 1980'

    LINE_F(start time : %ld, start)

    STR(sleep time : 2 second)

    Sleep(2000); // ms

    time(&end);
    LINE_F(end time : %ld. end - start time : %ld, end, end - start)

    return 0;

    /*
    start time : 1587463061
    sleep time : 2 second
    end time : 1587463063. end - start time : 2
    */
}

gmtime test

#include <time.h>
#include "common.h"

// 时差
#define BST_DIFF_HOURS (1)
#define CCT_DIFF_HOURS (8)

int main() {
    time_t curtime;
    struct tm *curtm;
    
    time(&curtime);
    // 使用 time_t 来填充 tm
    curtm = gmtime(&curtime);

    STR(current world time : )
    LINE_F(West time : %2d:%02d, (curtm->tm_hour + BST_DIFF_HOURS) % 24, curtm->tm_min)
    LINE_F(East time : %2d:%02d, (curtm->tm_hour + CCT_DIFF_HOURS) % 24, curtm->tm_min)

    /*
    current world time :
    West time : 11:10
    East time : 18:10
    */

    return 0;
}

applied domain test

#include <stdio.h>

void func(int a) {
    {
        int a = 4;
        printf("-->a=%d\n",a);
    }
    printf("->a=%d\n",a);
}

int main() {

    int a = 1;
    {
        int a = 2;
        printf("-->a=%d\n",a);
    }
    printf("->a=%d\n",a);

    func(3);

    return 0;
}
PS D:\jave\Work Files\C\Studies\applied domain> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\applied domain> .\out.exe
-->a=2
->a=1
-->a=4
->a=3

1D array test

#include <stdio.h>

int main() {

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    const int len = sizeof(arr) / sizeof(int);
    printf("len=%d\n", len);
    for (int i = 0; i < len; i++)
    {
        printf("a[%d]=%d\n", i, arr[i]);
    }
    arr[0] *= 2;
    arr[2] *= 2;
    arr[4] *= 2;
    arr[6] *= 2;
    arr[8] *= 2;

    printf("\n========= after modify array ==========\n");

    int* arr_p = &arr[0];
    for (int i = 0; i < len; i++)
    {
        printf("*arr_p+[%d]=%d\n", i, *(arr_p+i));
    }

    *(arr_p+1) *= 2;
    *(arr_p+3) *= 2;
    *(arr_p+5) *= 2;
    *(arr_p+7) *= 2;
    *(arr_p+9) *= 2;

    printf("\n========= after modify pointer ==========\n");

    for (int i = 0; i < len; i++)
    {
        printf("*arr_p+[%d]=%d\n", i, *(arr_p+i));
    }

    return 0;
}
PS D:\jave\Work Files\C\Studies\1D array test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\1D array test> .\out.exe
len=10
a[0]=1
a[1]=2
a[2]=3
a[3]=4
a[4]=5
a[5]=6
a[6]=7
a[7]=8
a[8]=9
a[9]=10

========= after modify array ==========
*arr_p+[0]=2
*arr_p+[1]=2
*arr_p+[2]=6
*arr_p+[3]=4
*arr_p+[4]=10
*arr_p+[5]=6
*arr_p+[6]=14
*arr_p+[7]=8
*arr_p+[8]=18
*arr_p+[9]=10

========= after modify pointer ==========
*arr_p+[0]=2
*arr_p+[1]=4
*arr_p+[2]=6
*arr_p+[3]=8
*arr_p+[4]=10
*arr_p+[5]=12
*arr_p+[6]=14
*arr_p+[7]=16
*arr_p+[8]=18
*arr_p+[9]=20

multi D array test

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int size;
    int * arr;
} ARR_STRUCT;

void printf_element(char* title, int * arr, int size) {
    printf("\n%s start\n", title);
    for (int i = 0; i < size; i++)
    {
        printf("%d,", *(arr+i));
    }
    printf("\n%s end\n", title);
}

void printf_element1(int arr[], int size) {
    printf_element("printf_element1", &arr[0], size);
}

ARR_STRUCT GetArr(int size) {
    ARR_STRUCT result;
    result.size = size;
    result.arr = malloc(sizeof(int) * size);
    return result;
}

void ResizeArr(ARR_STRUCT* p, int size) {
    p->size = size;
    realloc(p->arr, size);
}

void FreeArr(ARR_STRUCT v) {
    free(v.arr);
}

int main() {

    int arr[10][10];

    int len2 = sizeof(arr[0]) / sizeof(int);
    int len1 = sizeof(arr) / (sizeof(int) * len2);

    printf("sizeof(arr) = bytes =%d\n", sizeof(arr));

    printf("len1=%d\n", len1);
    printf("len2=%d\n", len2);

    int idx = 0;
    for (int row = 0; row < len1; row++)
    {
        for (int col = 0; col < len2; col++)
        {
            arr[row][col] = idx++;
        }
    }

    for (int row = 0; row < len1; row++)
    {
        printf("row%d:\t", row);
        for (int col = 0; col < len2; col++)
        {
            printf("%d\t", arr[row][col]);
        }
        printf("\n");
    }

    printf("======================\n");

    int arr2[2][2] = {
        {1, 2},
        {3, 4}
    };

    for (int i = 0; i < 2; i++)
    {
        printf("row%d:\t", i);
        for (int j = 0; j < 2; j++)
        {
            printf("%d\t", arr2[i][j]);
        }
        printf("\n");
    }

    printf("======================\n");
    int array[9] = {
        1, 2, 3,
        4, 5, 6,
        7, 8, 9
    };
    int arr3[3][3] = {
        1, 2, 3,
        4, 5, 6,
        7, 8, 9
    };
    for (int i = 0; i < 3; i++)
    {
        printf("row%d:\t", i);
        for (int j = 0; j < 3; j++)
        {
            printf("%d\t", arr3[i][j]);
        }
        printf("\n");
    }

    printf("======================\n");
    int _1D_Arr[3] = {9, 8, 7};
    int count = sizeof(_1D_Arr) / sizeof(int);
    printf("_1D_Arr count:%d\n",count);

    printf("======================\n");
    printf("sizeof(array)=%d\n", sizeof(array));
    printf_element("printf_element", array, sizeof(array)/sizeof(int));

    printf_element1(array, sizeof(array)/sizeof(int));

    // printf_element2(array);

    printf("======================\n");
    ARR_STRUCT arr_struct = GetArr(10);
    printf("GetArr start, arr.size=%d\n", arr_struct.size);

    for (int i = 0; i < arr_struct.size; i++)
    {
        *(arr_struct.arr+i) = i*2;
    }

    for (int i = 0; i < arr_struct.size; i++)
    {
        printf("%d=%d,",i,*(arr_struct.arr+i));
    }
    printf("\nGetArr end");

    printf("\n======================\n");

    printf("Free the array struct\n");
    // free(&arr_struct);
    FreeArr(arr_struct);
    
    printf("\n======================\n");

    printf("\n======================\n");
    printf("\nResize start\n");

    int resize = 20;
    printf("ResizeArr(arr, %d)\n", resize);
    // free(&arr_struct);
    ResizeArr(&arr_struct, resize);

    for (int i = 0; i < arr_struct.size; i++)
    {
        printf("%d=%d,",i,*(arr_struct.arr+i));
    }

    for (int i = 0; i < arr_struct.size; i++)
    {
        *(arr_struct.arr+i) = i;
    }
    printf("\n");
    for (int i = 0; i < arr_struct.size; i++)
    {
        printf("%d=%d,",i,*(arr_struct.arr+i));
    }

    resize = 5;
    printf("\nResizeArr(arr, %d)\n", resize);
    // free(&arr_struct);
    ResizeArr(&arr_struct, resize);
    for (int i = 0; i < arr_struct.size; i++)
    {
        printf("%d=%d,",i,*(arr_struct.arr+i));
    }
    FreeArr(arr_struct);
    printf("\nResize end\n");
    
    printf("\n======================\n");

    return 0;
}
ve\Work Files\C\Studies\multi D array test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\multi D array test> .\out.exe
sizeof(arr) = bytes =400
len1=10
len2=10
row0:   0       1       2       3       4       5       6       7       8       9
row1:   10      11      12      13      14      15      16      17      18      19
row2:   20      21      22      23      24      25      26      27      28      29
row3:   30      31      32      33      34      35      36      37      38      39
row4:   40      41      42      43      44      45      46      47      48      49
row5:   50      51      52      53      54      55      56      57      58      59
row6:   60      61      62      63      64      65      66      67      68      69
row7:   70      71      72      73      74      75      76      77      78      79
row8:   80      81      82      83      84      85      86      87      88      89
row9:   90      91      92      93      94      95      96      97      98      99
======================
row0:   1       2
row1:   3       4
======================
row0:   1       2       3
row1:   4       5       6
row2:   7       8       9
======================
_1D_Arr count:3
======================
sizeof(array)=36

printf_element start
1,2,3,4,5,6,7,8,9,
printf_element end

printf_element1 start
1,2,3,4,5,6,7,8,9,
printf_element1 end
======================
GetArr start, arr.size=10
0=0,1=2,2=4,3=6,4=8,5=10,6=12,7=14,8=16,9=18,
GetArr end
======================
Free the array struct

======================

======================

Resize start
ResizeArr(arr, 20)
0=11547824,1=11539864,2=4,3=6,4=8,5=10,6=12,7=14,8=16,9=18,10=738197548,11=12476,12=11547824,13=11539864,14=11543720,15=11539880,16=0,17=779384175,18=6649957,19=0,
0=0,1=1,2=2,3=3,4=4,5=5,6=6,7=7,8=8,9=9,10=10,11=11,12=12,13=13,14=14,15=15,16=16,17=17,18=18,19=19,
ResizeArr(arr, 5)
0=0,1=1,2=2,3=3,4=4,
Resize end

======================

enum test

#include <stdio.h>

typedef enum EnumType {
    One = 1,
    Two = 2,
    ReturnToOne = 1,
    Three = 3,
} ET;

int main() {

    for (int i = One; i < Three; i++)
    {
        printf("et:%d,%d\n", i, (ET)i);
    }

    printf("One==ReturnToOne:%d\n", One==ReturnToOne);

    int a = Two;
    printf("a=Two,a=%d\n", a);

    ET et = 3;
    printf("Et et=3,et=%d\n", et);
    
    return 0;
}
PS D:\jave\Work Files\C\Studies\enum test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\enum test> .\out.exe
et:1,1
et:2,2
One==ReturnToOne:1
a=Two,a=2
Et et=3,et=3

pointer test

#include <stdio.h>

#define MODIFY_MEM(offset,type,value) *(type*)(NULL+offset)=value;

#define GET_MEM(offset,type) *(type*)(NULL+offset)

int main() {

    int a = 0, b = 0;
    printf("int a = 0, b = 0;\n");
    printf("a's address : %d bytes\n",  &a);
    printf("b's address : %d bytes\n",  &b);
    printf("a'-b'=%d bytes\n", (long)&a-(long)&b);
    printf("=================\n");
    int arr[2] = {8,2};
    printf("int arr[2] = {1,2};\n");
    printf("arr[0]'s address : %d bytes\n",  &arr[0]);
    printf("arr[1]'s address : %d bytes\n",  &arr[1]);
    printf("arr[0]'-arr[1]'=%d bytes\n", (long)&arr[0]-(long)&arr[1]);

    // 可以根据一个int地址,就可以定位内存
    long offset = (long)&arr[1];
    printf("offset=%d bytes\n", offset);
    *(int*)(NULL + offset) = 100; // 直接从NULL(0地址)+偏移定位到指定内存,可以修改对应内存的数据
    printf("arr[1]'s address : %d bytes\n",  &arr[1]);
    printf("arr[1]'s value : %d\n",  arr[1]);

    MODIFY_MEM(offset, int, 200);

    printf("MODIFY_MEM==arr[1]'s address : %d bytes\n",  &arr[1]);
    printf("MODIFY_MEM==arr[1]'s value : %d\n",  arr[1]);

    printf("GetMemData==arr[0]==%d\n", GET_MEM((long)&arr[0], int));

    printf("=================\n");

    int *nullPointer = NULL;
    // int *nullPointer = &arr[1];
    if(nullPointer) {
        printf("nullPointer not NULL\n");
    } else {
        printf("nullPointer is NULL\n");
    }

    return 0;
}
PS D:\jave\Work Files\C\Studies\pointer test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\pointer test> .\out.exe
int a = 0, b = 0;
a's address : 6422292 bytes
b's address : 6422288 bytes
a'-b'=4 bytes
=================
int arr[2] = {1,2};
arr[0]'s address : 6422280 bytes
arr[1]'s address : 6422284 bytes
arr[0]'-arr[1]'=-4 bytes
offset=6422284 bytes
arr[1]'s address : 6422284 bytes
arr[1]'s value : 100
MODIFY_MEM==arr[1]'s address : 6422284 bytes
MODIFY_MEM==arr[1]'s value : 200
GetMemData==arr[0]==8
=================
nullPointer is NULL

rand test

#include <stdio.h>
#include <stdlib.h>

int main() {

    // 设置随机种子
    // srand(rand());
    for (int i = 0; i < 3; i++)
    {
        printf("get the %d random number is : %d\n", i, rand());
    }

    return 0;
}
PS D:\jave\Work Files\C\Studies\rand test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\rand test> .\out.exe
get the 0 random number is : 41
get the 1 random number is : 18467
get the 2 random number is : 6334

callback or func pointer test

#include <stdio.h>

// 总和
int sum(int *array, int size) {
    int sum = 0;
    for (int i = 0; i < size; i++){
        sum += *(array+i);
    }
    return sum;
}

// 平均值
int avg(int *array, int size) {
    return (sum(array, size) / size);
}

// 最大值
int max(int *array, int size) {
    int max = *array;
    for (int i = 1; i < size; i++){
        int v = *(array+i);
        max = max < v ? v : max;
    }
    return max;
}

// 最小值
int min(int *array, int size) {
    int min = *array;
    for (int i = 1; i < size; i++){
        int v = *(array+i);
        min = min > v ? v : min;
    }
    return min;
}

// 打印数据
void printArr(char *title, int *array, int size) {
    printf("%s", title);
    for (int i = 0; i < size; i++){
        printf("%d, ", *(array+i));
    }
    printf("\n");
}

// 对数组数据执行callback来过滤数据的函数
int filterEntry(int (*callback)(int*,int), int *array, int size) {
    return callback(array, size);
}

int main() {
    int scores[8] = {100, 60, 45, 70, 98, 100, 95, 99};
    const int size = sizeof(scores) / sizeof(int);
    printArr("score list : ", scores, size);
    printf("sum of score list : %d\n", filterEntry(sum, scores, size));
    printf("avg of score list : %d\n", filterEntry(avg, scores, size));
    printf("max of score list : %d\n", filterEntry(max, scores, size));
    printf("min of score list : %d\n", filterEntry(min, scores, size));
    return 0;
}
PS D:\jave\Work Files\C\Studies\callback or func pointer test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\callback or func pointer test> .\out.exe
score list : 100, 60, 45, 70, 98, 100, 95, 99,
sum of score list : 667
avg of score list : 83
max of score list : 100
min of score list : 45

string test

#include <stdio.h>
#include <string.h>

// 我们可以自己来编写、测试一个类似strlen的函数
int my_strlen(char* str) {
    register int len = 0;
    while(*(str+len)!='\0') ++len;
    return len;
}

// 注意destination必须为可写缓存
// 如果传入的destination的原始数据是char*是不可修改的常量
// 所以我们的destination只能传入char arr[]数组
char* my_strcpy(char* destination, char* source) {
    register int i = 0;
    while(*(source+i)!='\0') {
        *(destination + i) = *(source + i);
        ++i;
    }
    *(destination + i) = '\0'; // 添加会结束符
    return destination;
}

// 返回destination + connectingStr
// 注意destination传入的只能是可修改内存
char* my_strcat(char* destination, char* connectingStr) {
    register int validatedLen = my_strlen(destination);
    register int i = 0;
    while(*(connectingStr+i)!='\0') {
        *(destination + (validatedLen + i)) = *(connectingStr + i);
        ++i;
    }
    *(destination + (validatedLen + i)) = '\0'; // 添加会结束符
    return destination;
}

// a > b, reutrn 1;
// a == b, return 0;
// a < b, return -1;
int my_strcmp(char *a, char* b) {
    register int aLen = my_strlen(a);
    register int bLen = my_strlen(b);

    register int minLen = aLen < bLen ? aLen : bLen;
    register int aV = 0, bV = 0;
    for (register int i = 0; i < minLen; i++) {
        aV = *(a + i);
        bV = *(b + i);
        if (aV > bV) return 1;
        else if(aV < bV) return -1;
    }
    if (aLen > bLen) return 1;
    else if (aLen < bLen) return -1;
    return 0;
}

// 在str字符串中查找chr字符对应位置的指针
// 查找不到返回NULL
char* my_strchr(char *str, int chr) {
    register int validatedLen = my_strlen(str) + 1; // +1因为最后一个'\0'也算入搜索范围
    register int i = 0;
    do
    {
        if ((int)*(str + i) == chr) {
            return (str + i);
        }
        ++i;
    } while (i < validatedLen);
    return NULL;
}

// 在str字符串中查找 searchStr 字符对应位置的指针
// 查找不到返回NULL
char* my_strstr(char *str, char *searchStr) {
    // if (*(searchStr) == "" || *(searchStr) == "\0") return str;
    if (my_strcmp(searchStr, "") == 0 || my_strcmp(searchStr, "\0") == 0) return str;

    register int aLen = my_strlen(str);
    register int bLen = my_strlen(searchStr);
    char same = 0;
    char *p = NULL;

    for (register int i = 0; i < aLen; i++)
    {
        same = 1;
        p = str + i;
        for (register int j = 0; j < bLen; j++)
        {
            if (*(p + j) != *(searchStr + j)) {
                same = 0;
                break;
            }
        }
        if (same) return p;
    }
    return NULL;
}

int main() {
    // normally test
    char* name = "jave.lin";
    printf("A:Jave.Lin, Any you?\n", name);
    printf("B:Bill.Gates\n");

    char names[20] = "TonyStack";
    printf("A:Any other guys..., name?\n");
    printf("C:My name is %s...\n", names);

    printf("A:OK, Here we go. Changed the world!\n");

    printf("====================================\n");

    // testing end char '\0'
    // and testing  sizeof(str_pointer) & sizeof(type) & strlen(str_poinster)
    printf("========== testing end char \'\\0\' & strlen & sizeof =============\n");
    char content[10] = "123456789";
    printf("content=%s, sizeof(content)=%d, strlen(content)=%d\n", content, sizeof(content), strlen(content));
    content[3]='\0'; // 将3索引的值设置为'\0',3索引就是第4个
    printf("content=%s, sizeof(content)=%d, strlen(content)=%d\n", content, sizeof(content), strlen(content)); // 所以我们只看到输出 "123"

    char* str = "aaa"; // 3个a字符
    // sizeof(str)==4 说明 一串 "aaa" 中,最后一个字符是'\0',所以是4个字符的大小
    // strlen(str)==3 说明它是没有算上'\0'的
    printf("str=%s, sizeof(str)==%d, strlen(str)=%d\n", str, sizeof(str), strlen(str));

    register int x = 0;
    // 注意register沒有RAM地址,他是在CPU上的缓存,所以sizeof计算的是该int值类型的byte占用数量
    printf("register int x, sizeof(x) == %d\n", sizeof(x)); // sizeof(x) == 4 (bytes)

    long *test;
    printf("sizeof(test)==%d\n", sizeof(test));

    // 结合上面的sizeof(str), 与strlen(str),可以看到两者区别:
    // - sizeof(str) : 计算的是一个 指针地址数据 或是 动态分配的内存对象 或是 数据类型 的大小
    // char* str; sizeof(str) == 4 // 计算的是一个 指针地址数据 ,即用于 表示地址数据用的数据类型 通常是int占用4个bytes
    // char str[50]; sizeof(str) == 50 // 计算的是 动态分配的内存对象 占用的字节数
    // sizeof(long double) == 12 // 计算的是 数据类型 的大小
    // - strlen(str) : 计算的是一个 字符串中有效表示出来字符连续大小,就是从字符的0索引到第一个遇到的'\0'字符的数量统计(但不包括'\0')
    // strlen(str) 的伪代码如下:
    /*
    int my_strlen(char* str) {
        register int len = 0;
        while(*(str+len)!='\0') ++len;
        return len;
    }
    */

    printf("str=%s, sizeof(str)==%d, strlen(str)=%d, my_strlen(str)=%d\n", str, sizeof(str), strlen(str), my_strlen(str));

    // testing strcpy
    char *str1 = "you are my sun shin";
    printf("str1=%s, sizeof(str1)==%d\n", str1, sizeof(str1));
    // error testing
    // char *str2 = NULL;
    // printf("str2=%s\n", str2);
    // // 这里注意char *,是常量字符串,在字符表里有记录的,字符指针无法修改内容的,否则会出错
    // strcpy(str2, str1);
    // printf("str2=%s\n", str2);

    // 那么我们只能用char var[]的方式了,这种方式的内存是可以更改的,不是常量字符表的方式
    // correct testing
    printf("========== testing strcpy =============\n");
    char str2[50];
    printf("str2=%s, sizeof(str2)==%d\n", str2, sizeof(str2));
    // testing strcpy
    strcpy(str2, str1);
    printf("str2=%s, sizeof(str2)==%d, strlen(str2)==%d, my_strlen(str2)==%d\n",
        str2, sizeof(str2), strlen(str2), my_strlen(str2));

    // testing strlen & my_strlen, on no end char
    char str3[2] = "1";
    str3[1] = 'a'; // 我们把尾部的修改了,strlen或是my_strlen就不对了,strlen有可能遍历到别的地址的数据了,直到遇到'\0'

    printf("before my_strcpy str2=%s\n", str2);
    my_strcpy(str2, "that's my name");
    printf("after my_strcpy str2=%s\n", str2);

    printf("strlen(str3)=%d, my_strlen(str3)=%d\n", strlen(str3), my_strlen(str3));

    // testing strcat
    printf("========== testing strcat =============\n");
    char a_src[4] = "123";
    a_src[1] = '\0'; // 可以把这一句注释掉可以看到
    char a[10];
    strcpy(a, a_src);
    printf("a=%s\n",a);
    char *b = "456";
    printf("a_src=%s,a=%s,b=%s,strcat(a,b)=%s\n", a_src, a, b, strcat(a,b));

    char b_src[7] = "654321";
    char b_dest[20] = "123456";
    printf("before my_strcat, src=%s, dest=%s\n", b_src, b_dest);
    my_strcat(b_dest, b_src);
    printf("after my_strcat, src=%s, dest=%s\n", b_src, b_dest);

    printf("before my_strcat, src=%s, dest=%s\n", b_src, b_dest);
    b_src[3]='\0';
    b_dest[3]='\0';
    my_strcat(b_dest, b_src);
    printf("after my_strcat, src=%s, dest=%s\n", b_src, b_dest);

    /*
    a_src[1] = '\0'; // 可以把这一句注释掉输出以下结果
    a=123
    a_src=123,a=123456,b=456,strcat(a,b)=123456

    a_src[1] = '\0'; // 运行这一句的话,输出以下结果
    a=1
    a_src=1,a=1456,b=456,strcat(a,b)=1456

    从结果可以看到strcat复制的是0~'\0'之间的字符
    */

    // testing strcmp
    printf("========== testing strcmp =============\n");

    char *cmp_str_1 = "a";
    char *cmp_str_2 = "b";
    char *cmp_str_3 = "c";

    char *cmp_str_4 = "aabb";
    char *cmp_str_5 = "aabb";

    char *cmp_str_6 = "aabc";
    char *cmp_str_7 = "aac";

    char *cmp_str_8 = "aa";
    char cmp_str_9[3] = "aa";
    cmp_str_9[1]='\0';

    printf("cmp_str_1=%s,cmp_str_2=%s\n", cmp_str_1, cmp_str_2);
    printf("cmp_str_1'ASCII=%d,cmp_str_2'ASCII=%d\n", (int)(*cmp_str_1), (int)(*cmp_str_2));

    printf("strcmp(%s, %s)=%d\n",cmp_str_1,cmp_str_2,strcmp(cmp_str_1, cmp_str_2));
    printf("strcmp(%s, %s)=%d\n",cmp_str_3,cmp_str_2,strcmp(cmp_str_3, cmp_str_2));

    printf("strcmp(%s, %s)=%d\n",cmp_str_4, cmp_str_5,strcmp(cmp_str_4, cmp_str_5));
    printf("strcmp(%s, %s)=%d\n",cmp_str_6, cmp_str_5,strcmp(cmp_str_6, cmp_str_5));
    printf("strcmp(%s, %s)=%d\n",cmp_str_5, cmp_str_6,strcmp(cmp_str_5, cmp_str_6));
    printf("strcmp(%s, %s)=%d\n",cmp_str_6, cmp_str_7,strcmp(cmp_str_6, cmp_str_7));
    printf("strcmp(%s, %s)=%d\n",cmp_str_3, cmp_str_7,strcmp(cmp_str_3, cmp_str_7));
    printf("strcmp(%s, %s)=%d\n",cmp_str_1, cmp_str_8,strcmp(cmp_str_1, cmp_str_8));
    printf("strcmp(%s, %s)=%d\n",cmp_str_1, cmp_str_9,strcmp(cmp_str_1, cmp_str_9));

    printf("my_strcmpy start testing\n");

    printf("strcmp(%s, %s)=%d\n",cmp_str_1,cmp_str_2,my_strcmp(cmp_str_1, cmp_str_2));
    printf("strcmp(%s, %s)=%d\n",cmp_str_3,cmp_str_2,my_strcmp(cmp_str_3, cmp_str_2));

    printf("strcmp(%s, %s)=%d\n",cmp_str_4, cmp_str_5,my_strcmp(cmp_str_4, cmp_str_5));
    printf("strcmp(%s, %s)=%d\n",cmp_str_6, cmp_str_5,my_strcmp(cmp_str_6, cmp_str_5));
    printf("strcmp(%s, %s)=%d\n",cmp_str_5, cmp_str_6,my_strcmp(cmp_str_5, cmp_str_6));
    printf("strcmp(%s, %s)=%d\n",cmp_str_6, cmp_str_7,my_strcmp(cmp_str_6, cmp_str_7));
    printf("strcmp(%s, %s)=%d\n",cmp_str_3, cmp_str_7,my_strcmp(cmp_str_3, cmp_str_7));
    printf("strcmp(%s, %s)=%d\n",cmp_str_1, cmp_str_8,my_strcmp(cmp_str_1, cmp_str_8));
    printf("strcmp(%s, %s)=%d\n",cmp_str_1, cmp_str_9,my_strcmp(cmp_str_1, cmp_str_9));
    
    printf("my_strcmpy end testing\n");

    /*
    输出

    cmp_str_1=a,cmp_str_2=b
    cmp_str_1'ASCII=97,cmp_str_2'ASCII=98
    strcmp(a, b)=-1
    strcmp(c, b)=1
    strcmp(aabb, aabb)=0
    strcmp(aabc, aabb)=1
    strcmp(aabb, aabc)=-1
    strcmp(aabc, aac)=-1
    strcmp(c, aac)=1

    从上面的结果可以看出来是遍历字符的ASCII的大小来区别的
    如果ASCII都一样,就比较谁的字符比较长
    同样也是截取有效字符来比较的
    */

    // testing strchr
    printf("========== testing strchr =============\n");

    char strchr_str1[100] = "this is my testing message";
    char strchr_str2[10] = "1234567";
    printf("strchr_str1=%s\n", strchr_str1);
    char chr = 'y';
    printf("strchr_str1'=%d,strchr(%c)'==%d,interval=%d\n",
        (int)strchr_str1, 
        chr, 
        (int)strchr(strchr_str1, chr),
        (int)strchr(strchr_str1, chr)-(int)strchr_str1);

    strchr_str1[4]='\0';
    printf("after changed strchr_str1'=%d,strchr(%c)'==%d,interval=%d\n",
        (int)strchr_str1, 
        chr, 
        (int)strchr(strchr_str1, chr),
        (int)strchr(strchr_str1, chr)-(int)strchr_str1);
    printf("strchr_str2'=%d,strchr(%c)'==%d,interval=%d\n",
        (int)strchr_str2, 
        chr, 
        (int)strchr(strchr_str2, chr),
        (int)strchr(strchr_str2, chr)-(int)strchr_str2);
    printf("seach end char strchr_str1'=%d,strchr(%c)'==%d,interval=%d\n",
        (int)strchr_str1, 
        '\0', 
        (int)strchr(strchr_str1, '\0'),
        (int)strchr(strchr_str1, '\0')-(int)strchr_str1);
    printf("seach end char strchr_str2'=%d,strchr(%c)'==%d,interval=%d\n",
        (int)strchr_str2, 
        '\0', 
        (int)strchr(strchr_str2, '\0'),
        (int)strchr(strchr_str2, '\0')-(int)strchr_str2);
    printf("seach end char in empty str strchr_str2'=%d,strchr(%c)'==%d,interval=%d\n",
        (int)"", 
        '\0', 
        (int)strchr("", '\0'),
        (int)strchr("", '\0')-(int)"");

    printf("my_strchr start testing\n");
    printf("after changed strchr_str1'=%d,my_strlen(%c)'==%d,interval=%d\n",
        (int)strchr_str1, 
        chr, 
        (int)my_strchr(strchr_str1, chr),
        (int)my_strchr(strchr_str1, chr)-(int)strchr_str1);
    printf("strchr_str2'=%d,my_strlen(%c)'==%d,interval=%d\n",
        (int)strchr_str2, 
        chr, 
        (int)my_strchr(strchr_str2, chr),
        (int)my_strchr(strchr_str2, chr)-(int)strchr_str2);
    printf("seach end char strchr_str1'=%d,my_strlen(%c)'==%d,interval=%d\n",
        (int)strchr_str1, 
        '\0', 
        (int)my_strchr(strchr_str1, '\0'),
        (int)my_strchr(strchr_str1, '\0')-(int)strchr_str1);
    printf("seach end char strchr_str2'=%d,my_strlen(%c)'==%d,interval=%d\n",
        (int)strchr_str2, 
        '\0', 
        (int)my_strchr(strchr_str2, '\0'),
        (int)my_strchr(strchr_str2, '\0')-(int)strchr_str2);
    printf("seach end char in empty str strchr_str2'=%d,my_strlen(%c)'==%d,interval=%d\n",
        (int)"", 
        '\0', 
        (int)my_strchr("", '\0'),
        (int)my_strchr("", '\0')-(int)"");
    printf("my_strchr end testing\n");


    /*
    输出结果为
    strchr_str1=this is my testing message
    strchr_str1'=6422029,strchr(y)'==6422038,interval=9
    after changed strchr_str1'=6422029,strchr(y)'==0,interval=-6422029
    strchr_str2'=6422019,strchr(y)'==0,interval=-6422019
    seach end char strchr_str1'=6422029,strchr( )'==6422033,interval=4
    seach end char strchr_str2'=6422019,strchr( )'==6422026,interval=7
    seach end char in empty str strchr_str2'=4220380,strchr( )'==4220380,interval=0
    my_strchr start testing
    after changed strchr_str1'=6422029,my_strlen(y)'==0,interval=-6422029
    strchr_str2'=6422019,my_strlen(y)'==0,interval=-6422019
    seach end char strchr_str1'=6422029,my_strlen( )'==6422033,interval=4
    seach end char strchr_str2'=6422019,my_strlen( )'==6422026,interval=7
    seach end char in empty str strchr_str2'=4220380,my_strlen( )'==4220380,interval=0
    my_strchr end testing

    从输出结果中可以看出:不管搜索的字符串是什么相等就返回对应的索引位置的指针
    */

    
    // testing strstr
    printf("========== testing strstr =============\n");

    char strstr_str1[100] = "this is my testing message";
    char strstr_str2[100] = "this is my testing message";
    char searchStr[50] = "testing";
    char searchStr1[50] = "testing1";

    printf("strstr_str1=%s\n", strstr_str1);
    printf("strstr_str1'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr, 
        (int)strstr(strstr_str1, searchStr),
        (int)strstr(strstr_str1, searchStr)-(int)strstr_str1);
    printf("strstr_str1'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr1, 
        (int)strstr(strstr_str1, searchStr1),
        (int)strstr(strstr_str1, searchStr1)-(int)strstr_str1);
    searchStr1[1] = 's';
    searchStr1[2] = '\0';
    printf("strstr_str1'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr1, 
        (int)strstr(strstr_str1, searchStr1),
        (int)strstr(strstr_str1, searchStr1)-(int)strstr_str1);

    strstr_str1[0]='\0';
    searchStr[0] = '\0';
    printf("after change strstr_str1'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr, 
        (int)strstr(strstr_str1, searchStr),
        (int)strstr(strstr_str1, searchStr)-(int)strstr_str1);

    // 下面三个输出一样
    printf("after change strstr_str2'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str2, 
        "\0", 
        (int)strstr(strstr_str2, "\0"),
        (int)strstr(strstr_str2, "\0")-(int)strstr_str2);
    printf("after change strstr_str2'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str2, 
        "", 
        (int)strstr(strstr_str2, ""),
        (int)strstr(strstr_str2, "")-(int)strstr_str2);
    printf("after change strstr_str2'=%d,strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str2, 
        "t", 
        (int)strstr(strstr_str2, "t"),
        (int)strstr(strstr_str2, "t")-(int)strstr_str2);

    printf("my_strstr start testing\n");

    // char strstr_str1[100] = "this is my testing message";
    // char strstr_str2[100] = "this is my testing message";
    // char searchStr[50] = "testing";
    // char searchStr1[50] = "testing1";

    my_strcpy(strstr_str1, "this is my testing message");
    my_strcpy(strstr_str2, "this is my testing message");
    my_strcpy(searchStr, "testing");
    my_strcpy(searchStr1, "testing1");

    printf("strstr_str1=%s\n", strstr_str1);
    printf("strstr_str1'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr, 
        (int)my_strstr(strstr_str1, searchStr),
        (int)my_strstr(strstr_str1, searchStr)-(int)strstr_str1);
    printf("strstr_str1'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr1, 
        (int)my_strstr(strstr_str1, searchStr1),
        (int)my_strstr(strstr_str1, searchStr1)-(int)strstr_str1);
    searchStr1[1] = 's';
    searchStr1[2] = '\0';
    printf("strstr_str1'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr1, 
        (int)my_strstr(strstr_str1, searchStr1),
        (int)my_strstr(strstr_str1, searchStr1)-(int)strstr_str1);

    strstr_str1[0]='\0';
    searchStr[0] = '\0';
    printf("after change strstr_str1'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str1, 
        searchStr, 
        (int)my_strstr(strstr_str1, searchStr),
        (int)my_strstr(strstr_str1, searchStr)-(int)strstr_str1);

    // 下面三个输出一样
    printf("after change strstr_str2'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str2, 
        "\0", 
        (int)my_strstr(strstr_str2, "\0"),
        (int)my_strstr(strstr_str2, "\0")-(int)strstr_str2);
    printf("after change strstr_str2'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str2, 
        "", 
        (int)my_strstr(strstr_str2, ""),
        (int)my_strstr(strstr_str2, "")-(int)strstr_str2);
    printf("after change strstr_str2'=%d,my_strstr(%s)'==%d,interval=%d\n",
        (int)strstr_str2, 
        "t", 
        (int)my_strstr(strstr_str2, "t"),
        (int)my_strstr(strstr_str2, "t")-(int)strstr_str2);

    printf("my_strstr start end\n");

    /*
    输出
    strstr_str1=this is my testing message
    strstr_str1'=6421919,strstr(testing)'==6421930,interval=11
    strstr_str1'=6421919,strstr(testing1)'==0,interval=-6421919
    strstr_str1'=6421919,strstr(ts)'==0,interval=-6421919
    after change strstr_str1'=6421919,strstr()'==6421919,interval=0
    after change strstr_str2'=6421819,strstr()'==6421819,interval=0
    after change strstr_str2'=6421819,strstr()'==6421819,interval=0
    after change strstr_str2'=6421819,strstr(t)'==6421819,interval=0
    my_strstr start testing
    strstr_str1=this is my testing message
    strstr_str1'=6421919,my_strstr(testing)'==6421930,interval=11
    strstr_str1'=6421919,my_strstr(testing1)'==0,interval=-6421919
    strstr_str1'=6421919,my_strstr(ts)'==0,interval=-6421919
    after change strstr_str1'=6421919,my_strstr()'==6421919,interval=0
    after change strstr_str2'=6421819,my_strstr()'==6421819,interval=0
    after change strstr_str2'=6421819,my_strstr()'==6421819,interval=0
    after change strstr_str2'=6421819,my_strstr(t)'==6421819,interval=0
    my_strstr start end
    */

    return 0;
}
PS D:\jave\Work Files\C\Studies\string test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\string test> .\out.exe
A:Jave.Lin, Any you?
B:Bill.Gates
A:Any other guys..., name?
C:My name is TonyStack...
A:OK, Here we go. Changed the world!
====================================
========== testing end char '\0' & strlen & sizeof =============
content=123456789, sizeof(content)=10, strlen(content)=9
content=123, sizeof(content)=10, strlen(content)=3
str=aaa, sizeof(str)==4, strlen(str)=3
register int x, sizeof(x) == 4
sizeof(test)==4
str=aaa, sizeof(str)==4, strlen(str)=3, my_strlen(str)=3
str1=you are my sun shin, sizeof(str1)==4
========== testing strcpy =============
str2=, sizeof(str2)==50
str2=you are my sun shin, sizeof(str2)==50, strlen(str2)==19, my_strlen(str2)==19
before my_strcpy str2=you are my sun shin
after my_strcpy str2=that's my name
strlen(str3)=16, my_strlen(str3)=16
========== testing strcat =============
a=1
a_src=1,a=1456,b=456,strcat(a,b)=1456
before my_strcat, src=654321, dest=123456
after my_strcat, src=654321, dest=123456654321
before my_strcat, src=654321, dest=123456654321
after my_strcat, src=654, dest=123654
========== testing strcmp =============
cmp_str_1=a,cmp_str_2=b
cmp_str_1'ASCII=97,cmp_str_2'ASCII=98
strcmp(a, b)=-1
strcmp(c, b)=1
strcmp(aabb, aabb)=0
strcmp(aabc, aabb)=1
strcmp(aabb, aabc)=-1
strcmp(aabc, aac)=-1
strcmp(c, aac)=1
strcmp(a, aa)=-1
strcmp(a, a)=0
my_strcmpy start testing
strcmp(a, b)=-1
strcmp(c, b)=1
strcmp(aabb, aabb)=0
strcmp(aabc, aabb)=1
strcmp(aabb, aabc)=-1
strcmp(aabc, aac)=-1
strcmp(c, aac)=1
strcmp(a, aa)=-1
strcmp(a, a)=0
my_strcmpy end testing
========== testing strchr =============
strchr_str1=this is my testing message
strchr_str1'=6422029,strchr(y)'==6422038,interval=9
after changed strchr_str1'=6422029,strchr(y)'==0,interval=-6422029
strchr_str2'=6422019,strchr(y)'==0,interval=-6422019
seach end char strchr_str1'=6422029,strchr( )'==6422033,interval=4
seach end char strchr_str2'=6422019,strchr( )'==6422026,interval=7
seach end char in empty str strchr_str2'=4223044,strchr( )'==4223044,interval=0
my_strchr start testing
after changed strchr_str1'=6422029,my_strlen(y)'==0,interval=-6422029
strchr_str2'=6422019,my_strlen(y)'==0,interval=-6422019
seach end char strchr_str1'=6422029,my_strlen( )'==6422033,interval=4
seach end char strchr_str2'=6422019,my_strlen( )'==6422026,interval=7
seach end char in empty str strchr_str2'=4223044,my_strlen( )'==4223044,interval=0
my_strchr end testing
========== testing strstr =============
strstr_str1=this is my testing message
strstr_str1'=6421919,strstr(testing)'==6421930,interval=11
strstr_str1'=6421919,strstr(testing1)'==0,interval=-6421919
strstr_str1'=6421919,strstr(ts)'==0,interval=-6421919
after change strstr_str1'=6421919,strstr()'==6421919,interval=0
after change strstr_str2'=6421819,strstr()'==6421819,interval=0
after change strstr_str2'=6421819,strstr()'==6421819,interval=0
after change strstr_str2'=6421819,strstr(t)'==6421819,interval=0
my_strstr start testing
strstr_str1=this is my testing message
strstr_str1'=6421919,my_strstr(testing)'==6421930,interval=11
strstr_str1'=6421919,my_strstr(testing1)'==0,interval=-6421919
strstr_str1'=6421919,my_strstr(ts)'==0,interval=-6421919
after change strstr_str1'=6421919,my_strstr()'==6421919,interval=0
after change strstr_str2'=6421819,my_strstr()'==6421819,interval=0
after change strstr_str2'=6421819,my_strstr()'==6421819,interval=0
after change strstr_str2'=6421819,my_strstr(t)'==6421819,interval=0
my_strstr start end

struct test

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct B BType;

typedef struct A {
    char name[50];
    BType *b_pointer;
} AType;

typedef struct B {
    char name[50];
    AType *a_pointer;
} BType;

typedef struct C {
    int a;
    char b;
} CType;

typedef struct BF { // bit-field

    // 单计算没有位域的struct的占用byte数量还是比较简单的
    // 结构体大小的计算 : https://www.runoob.com/w3cnote/struct-size.html
    // CType c;
    // 但是一旦加入了bit-field,计算方式就会复杂很多

    // char v : 8;        // char == 1 byte
    // unsigned char v : 8; // unsinged char == 1 byte
    // short v : 16; // short == 2 bytes
    // unsigned short v : 16; // unsigned short == 2 bytes
    // unsigned v : 32; // 无类型,的unsinged 默认为一个int,一个int==4byte
    // int v : 32; // 4 bytes
    // unsigned int v : 32; // 4 bytes
    // long v : 32; // 4 bytes
    // unsigned long v : 32; // 4 bytes
    // size_t v : 32; // 4 bytes

    // 如果一个bit field里包含了各种不一样的数据类型
    // 那么将会以 最大的位数 的数据类型来做 对齐

    // 下面3个v1,v2,v3定义这个 bit-field的话,需要使用8 bytes,原因下面有些
    // char v1 : 1;    // 1 byte
    // short v2 : 1;   // 2 bytes
    // int v3 : 1;     // 三者中最大为int 4 bytes
    // 前面的char和short对齐到一个int里
    // 所以这里就相当于用了8个 bytes 来定义一个bit field

    // 下面8个f1~f8定义这个 bit-field的话,需要使用1 bytes,原因下面有些
    // char f1 : 1;
    // char f2 : 1;
    // char f3 : 1;
    // char f4 : 1;
    // char f5 : 1;
    // char f6 : 1;
    // char f7 : 1;
    // char f8 : 1;
    // 前面的 8个char 都一样,所以还是对齐到一个char
    // 所以这里就相当于用了1个 bytes 来定义一个bit field

    // 那么下面这个呢,什么都用一起了
    // 我们还最大的是int,unsigned int, long, unsigned long都是4bytes
    // 所以最小按4 bytes来对齐
    // 有v1~v8个,所以就是,暂时没有发现规律,后面需要再细究
    char v1 : 1;
    unsigned char v2 : 1;
    short v3 : 1;
    unsigned short v4 : 1;
    int v5 : 1;
    unsigned int v6 : 1;
    long v7 : 1;
    unsigned long v8 : 1;

} BFType;

int main() {

    printf("sizeof(AType)==%d,sizeof(BType)==%d\n",sizeof(AType),sizeof(BType));

    printf("=====on stack variable testing=====\n");

    AType a_struct={"This is A's name", NULL};
    BType b_struct={"This is B's name", NULL};

    printf("a_struct.name=%s,b_struct.name=%s\n",a_struct.name,b_struct.name);

    a_struct.b_pointer = &b_struct;
    b_struct.a_pointer = &a_struct;

    printf("a_struct=%p,b_struct=%p\n",&a_struct,&b_struct);
    printf("a_struct.b_pointer=%p,b_struct.a_pointer=%p\n",
        a_struct.b_pointer, b_struct.a_pointer);

    strcpy(a_struct.name, "Tom");
    strcpy(b_struct.name, "Jerry");

    printf("a_struct.name=%s,b_struct.name=%s\n",a_struct.name,b_struct.name);

    printf("=====on heap pointer variable testing=====\n");
    // 添加指针的struct只能指向一个现有的结构体地址
    // 如果不指向现有的地址,那就只能自己创建堆数据来指向它
    /*
    序号    函数和描述
    1	    void *calloc(int num, int size);
            在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是0。
    2	    void free(void *address);
            该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
    3	    void *malloc(int num);
            在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。
    4	    void *realloc(void *address, int newsize);
            该函数重新分配内存,把内存扩展到 newsize。
    */
    AType *a_pointer = malloc(sizeof(AType));
    BType *b_pointer = malloc(sizeof(BType));

    strcpy(a_pointer->name,"Bill.Gates");
    strcpy(b_pointer->name,"Steven.Jobs");

    printf("a_pointer->name=%s,b_struct.name=%s\n",a_pointer->name,b_pointer->name);

    a_pointer->b_pointer = b_pointer;
    b_pointer->a_pointer = a_pointer;

    printf("a_pointer=%p,b_pointer=%p\n",a_pointer,b_pointer);
    printf("a_pointer->b_pointer=%p,b_pointer->a_pointer=%p\n",
        a_pointer->b_pointer, b_pointer->a_pointer);

    printf("free the pointers\n");
    free(a_pointer);
    free(b_pointer);
    // 这里free了之后还可以使用
    printf("after free a_pointer=%p,b_pointer=%p\n",a_pointer,b_pointer);

    strcpy(a_pointer->name,"1");
    strcpy(b_pointer->name,"2");
    printf("after free a_pointer->name=%s,b_struct.name=%s\n",a_pointer->name,b_pointer->name);

    // 所以我们最好养成习惯free了之后的heap数据都指向NULL
    a_pointer = NULL;
    b_pointer = NULL;
    // 这时输出地址就变成00000000了
    printf("after free a_pointer=%p,b_pointer=%p\n",a_pointer,b_pointer);
    // 如果恢复下面对NULL数据的->name就会报错
    // strcpy(a_pointer->name,"1");
    // strcpy(b_pointer->name,"2");

    printf("sizeof(unsigned)==%d\n", sizeof(unsigned)); // 4
    printf("sizeof(unsigned int)==%d\n", sizeof(unsigned int)); // 4
    printf("sizeof(unsigned long)==%d\n", sizeof(unsigned long)); // 4
    printf("sizeof(long int)==%d\n", sizeof(long int)); // 4
    printf("sizeof(unsigned long int)==%d\n", sizeof(unsigned long int)); // 4
    printf("sizeof(long double)==%d\n", sizeof(long double)); // 12
    printf("sizeof(double)==%d\n", sizeof(double)); // 8

    // bit field testing
    printf("=====bit field testing=====\n");

    BFType bf = {1,1,1,1,1,1,1,1};
    printf("sizeof(BFType)==%d\n",sizeof(BFType));
    printf("sizeof(bf)==%d\n",sizeof(bf));
    printf("bf.v1=%d\n",bf.v1);
    printf("bf.v2=%d\n",bf.v2);
    printf("bf.v3=%d\n",bf.v3);
    printf("bf.v4=%d\n",bf.v4);
    printf("bf.v5=%d\n",bf.v5);
    printf("bf.v6=%d\n",bf.v6);
    printf("bf.v7=%d\n",bf.v7);
    printf("bf.v8=%d\n",bf.v8);

    /*
    sizeof(BFType)==8
    sizeof(bf)==8
    bf.v1=-1
    bf.v2=1
    bf.v3=-1
    bf.v4=1
    bf.v5=-1
    bf.v6=1
    bf.v7=-1
    bf.v8=1

    因为有些只剩一个符号位了,所以就是-1,
    所以一般只有1 bit的,一般用无符号来表示,结果就是0或是1
    */

    printf("done!\n");
    return 0;
}
PS D:\jave\Work Files\C\Studies\struct test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\struct test> .\out.exe
sizeof(AType)==56,sizeof(BType)==56
=====on stack variable testing=====
a_struct.name=This is A's name,b_struct.name=This is B's name
a_struct=0061FEE0,b_struct=0061FEA8
a_struct.b_pointer=0061FEA8,b_struct.a_pointer=0061FEE0
a_struct.name=Tom,b_struct.name=Jerry
=====on heap pointer variable testing=====
a_pointer->name=Bill.Gates,b_struct.name=Steven.Jobs
a_pointer=00C022D8,b_pointer=00C02318
a_pointer->b_pointer=00C02318,b_pointer->a_pointer=00C022D8
free the pointers
after free a_pointer=00C022D8,b_pointer=00C02318
after free a_pointer->name=1,b_struct.name=2
after free a_pointer=00000000,b_pointer=00000000
sizeof(unsigned)==4
sizeof(unsigned int)==4
sizeof(unsigned long)==4
sizeof(long int)==4
sizeof(unsigned long int)==4
sizeof(long double)==12
sizeof(double)==8
=====bit field testing=====
sizeof(BFType)==8
sizeof(bf)==8
bf.v1=-1
bf.v2=1
bf.v3=-1
bf.v4=1
bf.v5=-1
bf.v6=1
bf.v7=-1
bf.v8=1
done!

union test

#include <stdio.h>

typedef struct S1 {
    char v1;
    char v2;
} S1Type;

typedef struct S2 {
    char v1;
    char v2;
    short v3;
    int v4;
} S2Type;

typedef struct S3 {
    char v1;
    short v3;
    char v2;
    int v4;
} S3Type;

typedef union U1 {
    char v1;
} U1Type;

typedef union U2 {
    char v1;
    short v2;
} U2Type;

typedef union U3 {
    char v1;
    short v2;
    unsigned v3;
} U3Type;

typedef union U4 {
    char v1;
    short v2;
    unsigned v3;
    double v4;
} U4Type;

typedef union U5 {
    char v1;
    short v2;
    unsigned v3;
    double v4;
    long double v5;
} U5Type;

typedef union U6 {
    char v1;
    U1Type v2;
    S1Type v3;
} U6Type;

typedef union U7 {
    char v1;
    S2Type v2;
} U7Type;

typedef union U8 {
    char v1;
    S3Type v2;
} U8Type;

typedef union U9 {
    char v1;
    char v2[20];
    double v3;
    // sizeof(char) == 1 && sizeof(double) == 8 : S
    // 以最大double 8 bytes对齐
    // max(sizeof(v1), sizeof(v2), sizeof(v3)) == 20 : M
    // sizeof(U9Type):
    // == ((int)(M / S)  + (S % M  != 0 ? 1 : 0)) * S
    // == ((int)(20 / 8) + (8 % 20 != 0 ? 1 : 0)) * 8
    // == (      2       + (  4    != 0 ? 1 : 0)) * 8
    // == (      2       + (       1           )) * 8
    // == (              3                      ) * 8
    // == 3 * 8 = 24
} U9Type;

int main() {

    printf("sizeof(U1)==%d\n",sizeof(U1Type));
    printf("sizeof(U2)==%d\n",sizeof(U2Type));
    printf("sizeof(U3)==%d\n",sizeof(U3Type));
    printf("sizeof(U4)==%d\n",sizeof(U4Type));
    printf("sizeof(U5)==%d\n",sizeof(U5Type));
    printf("sizeof(U6)==%d\n",sizeof(U6Type));
    printf("sizeof(U7)==%d\n",sizeof(U7Type));
    printf("sizeof(U8)==%d\n",sizeof(U8Type));
    printf("sizeof(U9)==%d\n",sizeof(U9Type));

    return 0;
}
PS D:\jave\Work Files\C\Studies\union test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\union test> .\out.exe
sizeof(U1)==1
sizeof(U2)==2
sizeof(U3)==4
sizeof(U4)==8
sizeof(U5)==16
sizeof(U6)==2
sizeof(U7)==8
sizeof(U8)==12
sizeof(U9)==24

stdio test

  • a.c
#include <stdio.h>
#include <stdlib.h>

int main() {

    pr intf("Enter a char, please : ");
    char c = getchar(); // 只会取第一次输入的字符
    // printf("\n");
    printf("I got it, you enter the char is : %c\n", c);
    printf("putchar(c):");
    putchar(c);
    printf("\n");

    return 0;
}
PS D:\jave\Work Files\C\Studies\stdio test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\stdio test> .\out.exe
Enter a char, please : j
I got it, you enter the char is : j
putchar(c):j
  • b.c
#include <stdio.h>
#include <stdlib.h>

int main() {

    char msg[100];
    printf("Enter a message again please : (limit 100 chars)");
    gets(msg);
    printf("I got your message : ");
    puts(msg);
    printf("\n");

    return 0;
}
PS D:\jave\Work Files\C\Studies\stdio test> gcc .\b.c -o out
PS D:\jave\Work Files\C\Studies\stdio test> .\out.exe
Enter a message again please : (limit 100 chars)this is message.
I got your message : this is message.

  • c.c
#include <stdio.h>
#include <stdlib.h>

int main() {

    char msg[100];
    printf("Enter a message please : (limit 100 chars, split by space)");
    scanf("%s", msg);
    printf("I got your message : %s\n", msg);

    return 0;
}
PS D:\jave\Work Files\C\Studies\stdio test> gcc .\c.c -o out
PS D:\jave\Work Files\C\Studies\stdio test> .\out.exe
Enter a message please : (limit 100 chars, split by space)first second thrid
I got your message : first

file io test

先在创建tmp目录

/*
 C 文件读写
https://www.runoob.com/cprogramming/c-file-io.html
*/

#include <stdio.h>
#include <string.h>
#include <Windows.h>

int main() {
    FILE *fp = NULL;

    char *filename = "D:\\jave\\Work Files\\C\\Studies\\file io test\\tmp\\test.txt";

    fp = fopen(filename, "a+");
    char *inputStr = malloc(255);

    printf("reading the file info:...\n");
    while(fgets(inputStr, 255, (FILE*)fp) > 0) {
        printf(inputStr);
        Sleep(50);
    }

    printf("reading complete!\n");

    // fprintf(fp, "This is testing for fprintf...\n");
    // fputs("This is testing for fputs...\n", fp);

    printf("input you want to written message : ");
    gets(inputStr); // 输入:#clear,可以执行清空文件命令
    if (*inputStr == '#') {
        printf("->enter the cmd : ...\n");
        if (strcmp((inputStr + 1),"clear")==0) {
            printf("cmd:clear action ...");
            fclose(fp);
            fp = fopen(filename, "w+");
            printf("cmd clear action complete!\n");
        } else {
            printf("unhandle cmd : %s\n", (inputStr + 1));
        }
        printf("<-exit the cmd.\n");
    } else {
        fputs(strcat(inputStr, "\n"), fp);
    }

    free(inputStr);
    fclose(fp);
    printf("done!\n");
    return 0;
}
PS D:\jave\Work Files\C\Studies\file io test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\file io test> .\out.exe
reading the file info:...
new message input
second message.
reading complete!
input you want to written message : last on message
done!
PS D:\jave\Work Files\C\Studies\file io test> .\out.exe
reading the file info:...
new message input
second message.
last on message
reading complete!
input you want to written message : #clear
->enter the cmd : ...
cmd:clear action ...cmd clear action complete!
<-exit the cmd.
done!
PS D:\jave\Work Files\C\Studies\file io test> .\out.exe
reading the file info:...
reading complete!
input you want to written message : new one message
done!
PS D:\jave\Work Files\C\Studies\file io test> .\out.exe
reading the file info:...
new one message
reading complete!

pre-process or macro test

  • a.h
int a_header_file_def_var = 999;
char* a_header_file_def_string = "Hello world!";
void* (*callback)(int,int);
  • a.c
#include <stdio.h> // <system header file>, search in system directory
#include "a.h" // "custom header file", search in custom directory

#define MY_NAME "Jave.Lin"  // mapping a string
#define ONE 1               // mapping a number
#define PI 3.14159265359    // mapping pi value

#define UN_DEF_TAG
#undef UN_DEF_TAG

#define STR(v) (#v)
#define SAY_HI_TO(v) ("Hi " #v)             // 字符串连接

#define GET_GLOBAL_STR(v) (global_var_##v)  // 变量名拼接

#define SUM(a,b) ((a)+(b))                  // 求和

#define P(msg) \                            // 打印
    printf(""#msg "\n")

// 搜索字符
#define SEARCH(str,c,out_idx)\
    size_t out_idx=0;\
    while (*(str+out_idx)!='\0') {\
        if(*(str+out_idx)==c) break;\
        ++out_idx;\
    }\

char * global_var_a = "A STRING CONTENT";
char * global_var_b = "B STRING CONTENT";
char * global_var_c = "B STRING CONTENT";

int sum(int a, int b) {
    return a+b;
}

int main() {

    // setups...
    callback = (void *)sum;

    // printf...
    printf("Hello %s\n",MY_NAME);
    printf("ONE:%d\n",ONE);
    printf("ONE:%d\n",ONE);
    printf("PI:%d\n",PI);
    printf("int_var:%d\n",a_header_file_def_string);
    printf("str_var:%s\n",a_header_file_def_string);
    printf("callback(%d,%d)==%d\n", 7, 3, callback(7, 3));
    
    #ifdef UN_DEF_TAG
        printf("def UN_DEF_TAG\n");
    #else
        printf("un def UN_DEF_TAG\n");
    #endif

    #ifndef UN_DEF_TAG
        #define UN_DEF_TAG
    #endif

    #ifdef UN_DEF_TAG
        printf("again def UN_DEF_TAG\n");
    #else
        printf("again un def UN_DEF_TAG\n");
    #endif

    printf("%s\n", SAY_HI_TO(Bill.Gates));
    printf("%s\n", SAY_HI_TO(Steven.Jobs));

    printf("input:%s, get the:%s\n", STR(a), GET_GLOBAL_STR(a));
    printf("input:%s, get the:%s\n", STR(b), GET_GLOBAL_STR(b));
    printf("input:%s, get the:%s\n", STR(c), GET_GLOBAL_STR(c));

    #ifndef UN_DEF_TAG
        #error have an error...
    #endif

    #pragma abcdefg

    printf("SUM(%d,%d)==%d\n", 70, 30, SUM(70, 30));

    printf("__DATE__:%s\n",__DATE__);
    printf("__TIME__:%s\n",__TIME__);
    printf("__FILE__:%s\n",__FILE__);
    printf("__LINE__:%d\n",__LINE__);
    printf("__STDC__:%d\n",__STDC__);

    P(God Like);

    char* content = "123456789A987654321";
    char search_c = 'A';
    SEARCH(content, search_c, idx)
    printf("SEARCH(%s, %c, idx),idx=%d\n",content,search_c,idx);

    return 0;
}
PS D:\jave\Work Files\C\Studies\pre-process test> gcc .\a.c -o out                                                      PS D:\jave\Work Files\C\Studies\pre-process test> .\out.exe                                                             Hello Jave.Lin
ONE:1
ONE:1
PI:1413754602
int_var:4214856
str_var:Hello world!
callback(7,3)==10
un def UN_DEF_TAG
again def UN_DEF_TAG
Hi Bill.Gates
Hi Steven.Jobs
input:a, get the:A STRING CONTENT
input:b, get the:B STRING CONTENT
input:c, get the:B STRING CONTENT
SUM(70,30)==100
__DATE__:Apr 20 2020
__TIME__:10:45:14
__FILE__:.\a.c
__LINE__:86
__STDC__:1
God Like
SEARCH(123456789A987654321, A, idx),idx=9

include test

include each other

有三个文件 a.c, a.h, b.h

/*a.c*/
#include "a.h"
int main() {
    ap();
    bp();
    return 0;
}
/*a.h*/
// #include "b.h" // a.h 和 b.h 相互引用会出问题
// 改成条件编译来include
#ifndef __A_H
#define __A_H
#include "b.h"
#endif
int a_var = 1;
void ap() { a_var = b_var; }
/*b.h*/
// #include "a.h" // a.h 和 b.h 相互引用会出问题
#ifndef __B_H
#define __B_H
#include "a.h" // a.h处理了,这里就不用处理了
#endif
int b_var = 2;
void bp() { a_var = 3; }

直接编译报错

PS D:\jave\Work Files\C\Studies\19 include test> gcc .\a.c -o out
In file included from .\b.h:5,
                 from .\a.h:6,
                 from .\a.c:2:
.\a.h: In function 'ap':
.\a.h:9:21: error: 'b_var' undeclared (first use in this function); did you mean 'a_var'?
    9 | void ap() { a_var = b_var; }
      |                     ^~~~~
      |                     a_var
.\a.h:9:21: note: each undeclared identifier is reported only once for each function it appears in
In file included from .\a.c:2:
.\a.h: At top level:
.\a.h:8:5: error: redefinition of 'a_var'
    8 | int a_var = 1;
      |     ^~~~~
In file included from .\b.h:5,
                 from .\a.h:6,
                 from .\a.c:2:
.\a.h:8:5: note: previous definition of 'a_var' was here
    8 | int a_var = 1;
      |     ^~~~~
In file included from .\a.c:2:
.\a.h:9:6: error: redefinition of 'ap'
    9 | void ap() { a_var = b_var; }
      |      ^~
In file included from .\b.h:5,
                 from .\a.h:6,
                 from .\a.c:2:
.\a.h:9:6: note: previous definition of 'ap' was here
    9 | void ap() { a_var = b_var; }
      |      ^~

使用gcc -E输出只有预处理后的内容

现在 a.c 文件同目录下创建 tmp.txt

PS D:\jave\Work Files\C\Studies\19 include test> gcc -E .\a.c > tmp.txt                      

查看 tmp.txt

# 1 ".\\a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 ".\\a.c"

# 1 ".\\a.h" 1





# 1 ".\\b.h" 1




# 1 ".\\a.h" 1







int a_var = 1;
void ap() { a_var = b_var; }
# 6 ".\\b.h" 2

int b_var = 2;
void bp() { a_var = 3; }
# 7 ".\\a.h" 2

int a_var = 1;
void ap() { a_var = b_var; }
# 3 ".\\a.c" 2
int main() {
    ap();
    bp();
    return 0;
}

可以看到ap() 函数在使用b_var时,b_var的定义还没有被include

解决方法

将共用变量提取到一个global.h
/*a.c*/
#include "a.h"
#include "b.h"
int main() {
    ap();
    bp();
    return 0;
}
/*a.h*/
#include "global.h"
void ap() {
    a_var = b_var;
}
/*b.h*/
#include "global.h"
void bp() {
    a_var = 3;
}
/*global.h*/
int a_var = 1;
int b_var = 2;

编译报错,有重复定义

PS D:\jave\Work Files\C\Studies\19 include test> gcc .\a.c -o out
In file included from .\b.h:2,
                 from .\a.c:3:
.\global.h:2:5: error: redefinition of 'a_var'
    2 | int a_var = 1;
      |     ^~~~~
In file included from .\a.h:4,
                 from .\a.c:2:
.\global.h:2:5: note: previous definition of 'a_var' was here
    2 | int a_var = 1;
      |     ^~~~~
In file included from .\b.h:2,
                 from .\a.c:3:
.\global.h:3:5: error: redefinition of 'b_var'
    3 | int b_var = 2;
      |     ^~~~~
In file included from .\a.h:4,
                 from .\a.c:2:
.\global.h:3:5: note: previous definition of 'b_var' was here
    3 | int b_var = 2;
      |     ^~~~~

我们用gcc -E再看看预处理内容

PS D:\jave\Work Files\C\Studies\19 include test> gcc -E .\a.c > tmp.txt

打开tmp.txt

# 1 ".\\a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 ".\\a.c"

# 1 ".\\a.h" 1

# 1 ".\\global.h" 1

int a_var = 1;
int b_var = 2;
# 3 ".\\a.h" 2
void ap() {
    a_var = b_var;
}
# 3 ".\\a.c" 2
# 1 ".\\b.h" 1

# 1 ".\\global.h" 1

int a_var = 1;
int b_var = 2;
# 3 ".\\b.h" 2
void bp() {
    a_var = 3;
}
# 4 ".\\a.c" 2
int main() {
    ap();
    bp();
    return 0;
}

可以看到,a_var与b_var有两份定义。
因为我们在a.c引用了"a.h"和"b.h"导致的

添加条件编译来include

我们只更改"a.h","b.h"两个文件就好

/*a.h*/
#ifndef __G_H
#define __G_H
#include "global.h"
#endif
void ap() {
    a_var = b_var;
}
/*b.h*/
#ifndef __G_H
#define __G_H
#include "global.h"
#endif
void bp() {
    a_var = 3;
}

再来编译,发现没有报错了
再用gcc -E看看预处理结果

# 1 ".\\a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 ".\\a.c"

# 1 ".\\a.h" 1



# 1 ".\\global.h" 1

int a_var = 1;
int b_var = 2;
# 5 ".\\a.h" 2

void ap() {
    a_var = b_var;
}
# 3 ".\\a.c" 2
# 1 ".\\b.h" 1





void bp() {
    a_var = 3;
}
# 4 ".\\a.c" 2
int main() {
    ap();
    bp();
    return 0;
}

可以看到没有重复的a_var,b_var的定义了

error print test

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

extern int errno;   // 引入errno.h内的errno变量声明

int main() {
    // errno, perror(), strerror() test
    // errno == get the error number
    // perror(char* title) == print the error with prefix title
    // strerror(int errorNumber) == get description of the error number

    // ==== open file error test =====
    printf("====== open file start test ======\n");
    FILE* fp;
    int errnum;
    fp = fopen("un exsit file.txt","rb");
    if (fp == NULL) {
        errnum = errno;
        fprintf(stderr, "error number : %d\n", errnum);
        perror("this is error lable");
        fprintf(stderr, "open file error : %s\n", strerror(errno));
    } else {
        fclose(fp);
    }

    printf("====== div zero start test ======\n");
    int dn = 0;
    int n = 1;
    // n = n / dn;
    // errnum = errno;
    if (dn == 0) {
        char* strFormat = (char*)malloc(100);
        sprintf(strFormat, "May div zero err, dn=%d, n=%d\n", dn, n);
        printf(strFormat);
        free(strFormat);
        exit(-1); // exit by error code : -1
    }

    printf("done!\n");

    return 0;
}
PS D:\jave\Work Files\C\Studies\error print test> gcc .\a.c -o out                                                      PS D:\jave\Work Files\C\Studies\error print test> .\out.exe                                                             ====== open file start test ======
error number : 2
this is error lable: No such file or directory
open file error : No such file or directory
====== div zero start test ======
May div zero err, dn=0, n=1

dynamic arg num test

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>

#define P_FIXED_SIZE(func_name,arg_num,sizePerArg)\
    size_t sizePerArg = sizeof(arg_num);\
    printf(#func_name ", have %d dynamic args, " #sizePerArg "=%d\n",arg_num,sizePerArg);

#define P_NO_FIXED_SIZE(func_name)\
    printf(#func_name ", have no fixed dynamic args\n");

void func1(char argNum, ...) {
    P_FIXED_SIZE(func1, argNum, sizePerArg);
}

void func2(int argNum, ...) {
    P_FIXED_SIZE(func2, argNum, sizePerArg);
    // 利用从右往左入栈的特性
    // 先入栈的地址高
    // 所以firstArg是最左边的,从地址底的往高的遍历
    int *firstArg = &argNum;
    for (int i = 1; i < argNum + 1; i++) {
        printf("dynamic arg %d == %d\n", i, *(firstArg + i));
    }
}

int func3(char* firstArg,...) {
    P_NO_FIXED_SIZE(func3);
    /*
    需要 #include <stdarg.h>
    va_list,参数列表管理指针,需要用:va_start(list, first)来指定
    va_start,用来指定参数列表的首地址:va_start(list, first)
    va_arg,在va_list中获取下一个参数:nextArg = va_arg(list, type)
    va_end,结果处理,与va_start配对使用:va_end(list)
    */

    // 统计参数数量
    register int argCounter = 0;
    printf("arg %d = %s\n", ++argCounter, firstArg);
    // typedef char* va_list;
    va_list arglist;
    char *getArg;
    va_start(arglist, firstArg);
    register int i = 255;
    while(--i > 0) {
        getArg = va_arg(arglist, char*);
        if (strcmp(getArg, "") == 0)
            break;
        printf("arg %d = %s\n", ++argCounter, getArg);
    }
    va_end(arglist);
    if (i < 0) {
        printf("func3 over loop, i:%d\n", i);
        return -1;
    }
    return 0;
}

typedef struct Info {
    char* name;
    int value;
} InfoType;

void SetInfo(InfoType* info, char *name, int value) {
    info->name = name;
    info->value = value;
}

InfoType* GetInfo(char *name, int value) {
    InfoType *result = malloc(sizeof(InfoType));
    SetInfo(result, name, value);
    return result;
}

void ToStr(InfoType* info, char* str) {
    sprintf(str, "name=%s,value=%d", info->name,info->value);
}

int func4(InfoType* firstArg,...) {
    P_NO_FIXED_SIZE(func4);
    // 统计参数数量
    register int argCounter = 0;
    char* printStr = malloc(100);
    ToStr(firstArg, printStr);
    printf("arg %d = %s\n", ++argCounter, printStr);
    va_list arglist;
    InfoType *getArg;
    va_start(arglist, firstArg);
    register int i = 255;
    while(--i > 0) {
        getArg = va_arg(arglist, InfoType*);
        if (getArg->value == 0)
            break;
        ToStr(getArg, printStr);
        printf("arg %d = %s\n", ++argCounter, printStr);
    }
    free(printStr);
    va_end(arglist);
    if (i < 0) {
        printf("func4 over loop, i:%d\n", i);
        return -1;
    }
    return 0;
}

int main() {

    func1(2,3,5);
    func2(3,1,3,5);
    func3("first", "second", "third", "fourth", "");
    InfoType* p1 = GetInfo("Bill.Gates", 18);
    InfoType* p2 = GetInfo("Steven.Jobs", 17);
    InfoType* p3 = GetInfo("Human", 1);
    InfoType* p4 = GetInfo("God", 0);
    func4(p1,p2,p3,p4);

    return 0;
}
PS D:\jave\Work Files\C\Studies\21 dynamic arg num test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\21 dynamic arg num test> .\out.exe
>>
func1, have 2 dynamic args, sizePerArg=1
func2, have 3 dynamic args, sizePerArg=4
dynamic arg 1 == 1
dynamic arg 2 == 3
dynamic arg 3 == 5
func3, have no fixed dynamic args
arg 1 = first
arg 2 = second
arg 3 = third
arg 4 = fourth
func4, have no fixed dynamic args
arg 1 = name=Bill.Gates,value=18
arg 2 = name=Steven.Jobs,value=17
arg 3 = name=Human,value=1

func variables heap enqueue test

#include <stdio.h>

void func(int a, int b, int c) {
    int d = 7; // 0061FEFC
    double e = 999.9999; // 0061FEF0
    int f = 888; // 0061FEEC
    int g = 777; // 0061FEE8
    int h = 666; // 0061FEE4
    int i = 666; // 0061FEE0
    int j[2] = {555}; // 1:0061FEDC,0:0061FED8

    // params variables
    // a~c 地址越来越大,越大的地址,是越早如栈的
    // 参数从右往左入栈
    printf("a=%p\n",&a);
    printf("b=%p\n",&b);
    printf("c=%p\n",&c);
    // local variables
    // h~d 地址越来越大,越大的地址,是越早如栈的
    // 参数从下往上入栈
    // j数据第1索引的地址比第0索引地址要大
    printf("j=%p\n",&j[0]);
    printf("i=%p\n",&i);
    printf("h=%p\n",&h);
    printf("g=%p\n",&g);
    printf("f=%p\n",&f);
    printf("e=%p\n",&e);
    printf("d=%p\n",&d);
}

int main() {

    func(1,3,5);

    return 0;
}
PS D:\jave\Work Files\C\Studies\22 func variables heap enqueue test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\22 func variables heap enqueue test> .\out.exe
a=0061FF10
b=0061FF14
c=0061FF18
j=0061FED8
i=0061FEE0
h=0061FEE4
g=0061FEE8
f=0061FEEC
e=0061FEF0
d=0061FEFC

mem mgr test

#include <stdio.h>
#include <stdlib.h>

void printBuff(char* buff, size_t size) {
    for (size_t i = 0; i < size; i++) {
        printf("%d,", *(buff + i));
    }
    printf("\n");
}

int main() {
    printf("====== malloc start test ======\n");
    char* buff = malloc(10);
    printf("after malloc buff : ");
    printBuff(buff, 10); // malloc 后的指针数据是不确定的
    
    printf("====== free start test ======\n");
    free(buff);
    printf("after free buff : ");
    printBuff(buff, 10);

    printf("====== calloc start test ======\n");
    buff = calloc(10, sizeof(char));
    printf("after calloc buff : "); // calloc 后的指针数据是确定为0的
    printBuff(buff, 10);
    free(buff);
    printf("after free buff : ");
    printBuff(buff, 10);

    printf("====== realloc start test ======\n");
    realloc(buff, 15);
    printf("after realloc buff : "); // realloc与malloc一样 指针数据是不确定的
    printBuff(buff, 10);
    free(buff);
    printf("after free buff : ");
    printBuff(buff, 10);

    return 0;
}
PS D:\jave\Work Files\C\Studies\22 mem mgr test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\22 mem mgr test> .\out.exe
>>                                                                                                                      ====== malloc start test ======
after malloc buff : -40,34,-78,0,-64,0,-78,0,2,0,
====== free start test ======
after free buff : -40,34,-78,0,-64,0,-78,0,2,0,
====== calloc start test ======
after calloc buff : 0,0,0,0,0,0,0,0,0,0,
after free buff : -40,34,-78,0,-64,0,-78,0,0,0,
====== realloc start test ======
after realloc buff : -40,34,-78,0,-64,0,-78,0,0,0,
after free buff : -40,34,-78,0,-64,0,-78,0,0,0,

call app pass args test

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

// 我们可以自己来编写、测试一个类似strlen的函数
int my_strlen(char* str) {
    register int len = 0;
    while(*(str+len)!='\0') ++len;
    return len;
}

// 注意destination必须为可写缓存
// 如果传入的destination的原始数据是char*是不可修改的常量
// 所以我们的destination只能传入char arr[]数组
char* my_strcpy(char* destination, char* source) {
    register int i = 0;
    while(*(source+i)!='\0') {
        *(destination + i) = *(source + i);
        ++i;
    }
    *(destination + i) = '\0'; // 添加会结束符
    return destination;
}

// 返回destination + connectingStr
// 注意destination传入的只能是可修改内存
char* my_strcat(char* destination, char* connectingStr) {
    register int validatedLen = my_strlen(destination);
    register int i = 0;
    while(*(connectingStr+i)!='\0') {
        *(destination + (validatedLen + i)) = *(connectingStr + i);
        ++i;
    }
    *(destination + (validatedLen + i)) = '\0'; // 添加会结束符
    return destination;
}

// a > b, reutrn 1;
// a == b, return 0;
// a < b, return -1;
int my_strcmp(char *a, char* b) {
    register int aLen = my_strlen(a);
    register int bLen = my_strlen(b);

    register int minLen = aLen < bLen ? aLen : bLen;
    register int aV = 0, bV = 0;
    for (register int i = 0; i < minLen; i++) {
        aV = *(a + i);
        bV = *(b + i);
        if (aV > bV) return 1;
        else if(aV < bV) return -1;
    }
    if (aLen > bLen) return 1;
    else if (aLen < bLen) return -1;
    return 0;
}

// 在str字符串中查找chr字符对应位置的指针
// 查找不到返回NULL
char* my_strchr(char *str, int chr) {
    register int validatedLen = my_strlen(str) + 1; // +1因为最后一个'\0'也算入搜索范围
    register int i = 0;
    do
    {
        if ((int)*(str + i) == chr) {
            return (str + i);
        }
        ++i;
    } while (i < validatedLen);
    return NULL;
}

// 在str字符串中查找 searchStr 字符对应位置的指针
// 查找不到返回NULL
char* my_strstr(char *str, char *searchStr) {
    // if (*(searchStr) == "" || *(searchStr) == "\0") return str;
    if (my_strcmp(searchStr, "") == 0 || my_strcmp(searchStr, "\0") == 0) return str;

    register int aLen = my_strlen(str);
    register int bLen = my_strlen(searchStr);
    char same = 0;
    char *p = NULL;

    for (register int i = 0; i < aLen; i++)
    {
        same = 1;
        p = str + i;
        for (register int j = 0; j < bLen; j++)
        {
            if (*(p + j) != *(searchStr + j)) {
                same = 0;
                break;
            }
        }
        if (same) return p;
    }
    return NULL;
}

#define NEW(type) (malloc(sizeof(type)))
#define NEW_MULTI(type,count) (malloc(sizeof(type)*(count)))

// 申请字符串空间,并将src复制到dest
char* my_alloc_cpy_str(char* dest, char* src) {
    printf("ac src:%s,",src);
    int len = my_strlen(src) + 1; // +1是为了尾部添加'\0'
    printf("src's len:%d,",len);
    dest = NEW_MULTI(char,len);
    my_strcpy(dest, src);
    printf("copy to dest, dest:%s\n",dest);
    return dest;
}

// 从 src 字符串中获取指定:开始位置,到,结束位置,的字符串,并复制到 dest
// 如果 endIdx == -1,则截取到尾部的字符,截取的字符中不包含 第endIdx个字符
char* my_alloc_get_str(char* dest, char* src, int startIdx, int endIdx, char forceNew) {
    if (endIdx == -1) {
        endIdx = my_strlen(src);
        printf("endIdx == -1, changed to : %d\n", endIdx);
    }
    if (endIdx < startIdx) {
        printf("endIdx < startIdx\n");
        return dest;
    }
    if (endIdx == startIdx) {
        printf("endIdx == startIdx\n");
        return dest;
    }
    printf("--->split src:%s,start:%d,end:%d\n",src,startIdx,endIdx);

    int len = endIdx - startIdx;

    if (!dest || forceNew) {
        dest = NEW_MULTI(char, len + 1); // +1因为要有结束符
    }

    printf("start:%d,end:%d->",startIdx,endIdx);
    for (size_t i = 0, srcOffset = startIdx; srcOffset < endIdx; srcOffset++, i++) {
        printf("%d:%c,",srcOffset,*(src + srcOffset));
        *(dest + i) = *(src + srcOffset);
    }
    printf("\n");
    // 补上结束符
    *(dest + len) = '\0';
    return dest;
}

typedef struct Arg {
    char* name;
    char* value;
} ArgType;

typedef struct ArgNode ArgNodeType;

typedef struct ArgNode {
    ArgType* arg;
    ArgNodeType* next;
} ArgNodeType;

ArgType* get_args(int argc, char* args[], const char spliter) {
    int spliterPos;
    char* spliterPosPointer;
    
    ArgNodeType* firstNode = NULL;

    ArgNodeType* curNodeArg = NULL;
    ArgType* newArg = NULL;

    // 忽略第一个参数
    for (size_t i = 1; i < argc; i++) {
        char* a = args[i];
        // 第一次检测
        ArgType* arg = NULL;
        spliterPosPointer = my_strchr(a, spliter);
        if (spliterPosPointer) { // 有分隔符
            char* errorPointer = my_strchr(spliterPosPointer + 1, spliter);
            if (errorPointer) { // 第二次还有重复的分隔符
                printf("error: multi spliter char, arg[%d]=%s\n", i, a);
                return NULL;
            }
            spliterPos = (int)spliterPosPointer - (int)a;
            // printf("spliterPos==%d\n", spliterPos);
            if (spliterPos == 0) {
                printf("error: split char position invalidated, arg[%d]=%s\n", i, a);
                return NULL;
            }
            arg = NEW(ArgType);
            // printf("before split name:%s,value:%s\n", arg->name,arg->value);
            arg->name = my_alloc_get_str(arg->name, a, 0, spliterPos, 1);
            arg->value = my_alloc_get_str(arg->value, a, spliterPos + 1, -1, 1);
            printf("after split arg %d name=%s,value=%s\n", i, arg->name, arg->value);
        } else { // 无分隔符
            arg = NEW(ArgType);
            arg->name = my_alloc_cpy_str(arg->name,a);
            arg->value = NULL;
        }
        // 分析好的 ArgType 数据放入链表
        if (arg) {
            ArgNodeType* newNode = NEW(ArgNodeType);
            newNode->arg = arg;
            newNode->next = NULL;

            if (!firstNode) {
                firstNode = newNode;
            }
            if (curNodeArg) {
                curNodeArg->next = newNode;
                curNodeArg = newNode;
            } else {
                curNodeArg = newNode;
            }
        }
    }

    if (firstNode) {
        ArgType* result = NEW_MULTI(ArgType, argc - 1);
        int idx = 0;
        ArgNodeType* freeNode;
        do
        {
            freeNode = firstNode;
            *(result + idx) = *(firstNode->arg);
            firstNode = firstNode->next;
            ++idx;
            free(freeNode);
        } while (firstNode);
        return result;
    }
    return NULL;
}

void free_args(const int argc, ArgType* args) {
    for (size_t i = 0; i < argc; i++) {
        free((*(args + i)).name);
        free((*(args + i)).value);
    }
    free(args);
}

int main(int argc, char* args[]) {
    printf("====== normally start test ======\n");
    printf("argc == %d\n", argc);
    for (size_t i = 0; i < argc; i++) {
        printf("arg[%d]=%s\n", i, args[i]);
    }
    printf("====== args analyzes start test ======\n");
    ArgType* result = get_args(argc, args, ':');
    if (result) {
        printf("args analyzes successfully\n");
        for (size_t i = 0; i < argc - 1; i++) {
            // printf("%d start\n",i);
            printf("==[name=%s,value=%s]==\n",(*(result+i)).name, (*(result+i)).value);
            // printf("%d end\n",i);
            // ... handle
        }
        printf("args analyzes & handle complete!\n");
        
        printf("free args start\n");
        free_args(argc - 1, result);
        printf("free args complete!\n");

    } else {
        printf("invalidated args, and exit with error code : -1!\n");
        return -1;
    }
    printf("done!\n");
    return 0;
}
PS D:\jave\Work Files\C\Studies\24 call app pass args test> gcc .\a.c -o out
PS D:\jave\Work Files\C\Studies\24 call app pass args test> .\out.exe shadow:csm shadowsoft:pcf quality:veryhigh light:on
====== normally start test ======
argc == 5
arg[0]=D:\jave\Work Files\C\Studies\24 call app pass args test\out.exe
arg[1]=shadow:csm
arg[2]=shadowsoft:pcf
arg[3]=quality:veryhigh
arg[4]=light:on
====== args analyzes start test ======
--->split src:shadow:csm,start:0,end:6
start:0,end:6->0:s,1:h,2:a,3:d,4:o,5:w,
endIdx == -1, changed to : 10
--->split src:shadow:csm,start:7,end:10
start:7,end:10->7:c,8:s,9:m,
after split arg 1 name=shadow,value=csm
--->split src:shadowsoft:pcf,start:0,end:10
start:0,end:10->0:s,1:h,2:a,3:d,4:o,5:w,6:s,7:o,8:f,9:t,
endIdx == -1, changed to : 14
--->split src:shadowsoft:pcf,start:11,end:14
start:11,end:14->11:p,12:c,13:f,
after split arg 2 name=shadowsoft,value=pcf
--->split src:quality:veryhigh,start:0,end:7
start:0,end:7->0:q,1:u,2:a,3:l,4:i,5:t,6:y,
endIdx == -1, changed to : 16
--->split src:quality:veryhigh,start:8,end:16
start:8,end:16->8:v,9:e,10:r,11:y,12:h,13:i,14:g,15:h,
after split arg 3 name=quality,value=veryhigh
--->split src:light:on,start:0,end:5
start:0,end:5->0:l,1:i,2:g,3:h,4:t,
endIdx == -1, changed to : 8
--->split src:light:on,start:6,end:8
start:6,end:8->6:o,7:n,
after split arg 4 name=light,value=on
args analyzes successfully
==[name=shadow,value=csm]==
==[name=shadowsoft,value=pcf]==
==[name=quality,value=veryhigh]==
==[name=light,value=on]==
args analyzes & handle complete!
free args start
free args complete!
done!

doublePointer test / 二级、多级指针测试

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MODE0 0 // 不安全操作模式
#define MODE1 1 // 安全的操作模式
#define MODE2 2 // 可以成功修改的方式正确的方式
#define MODE3 3 // 二级指针方式方式
#define MODE4 4 // 超越长度复制字符串

#define USE_MODE MODE3

void modify_pointer_value(char* pointer, char* value) {
    register int i = 0;
    while(*(value + i) != '\0') {
        *(pointer + i) = *(value + i);
        ++i;
    }
}

void repoint_the_pointer(char* pointer, char* value) {
    register int i = 0;
    while(*(value + i) != '\0') {
        ++i;
    }
    // jave.lin:
    // 注意这里再函数里改了pointer参数的指针,相当于换了另一个指针
    // 函数执行完后,外部的pointer是不会有任何变化的
    // 这个需要了解变量的作用于
    pointer = malloc(sizeof(char) * i + 1); // +1因为需要尾部加上'\0'结束符
    for (size_t j = 0; j < i; j++) {
        *(pointer + j) = *(value + j);
    }
    *(pointer + i) = '\0';
}

char* repoint_the_pointer2(char* pointer, char* value) {
    register int i = 0;
    while(*(value + i) != '\0') {
        ++i;
    }
    if (!pointer) {
        pointer = malloc(sizeof(char) * i + 1); // +1因为需要尾部加上'\0'结束符
    }
    for (size_t j = 0; j < i; j++) {
        *(pointer + j) = *(value + j);
    }
    *(pointer + i) = '\0';
    return pointer;
}

void changedDoublePointer(char** doublePointer, char* value) {
    register int i = 0;
    while(*(value + i) != '\0') {
        ++i;
    }
    
    char* tempPointer = *(doublePointer);
    if (!tempPointer) {
        tempPointer =  malloc(sizeof(char) * i + 1); // +1因为需要尾部加上'\0'结束符
    } else {
        tempPointer = realloc(tempPointer, sizeof(char) * i + 1);
    }
    *(doublePointer) = tempPointer;

    for (size_t j = 0; j < i; j++) {
        *(tempPointer + j) = *(value + j);
    }
    *(tempPointer + i) = '\0';
}

int main() {
    printf("USE_MODE == %d\n", USE_MODE);
    #if USE_MODE == MODE0
        char* value = "This is string.";
        char* pointer1; // 这时危险的方式,因为pointer1是不确定的地址
        printf("before modify pointer1:%s,pointer1'=%p\n",pointer1,pointer1);
        modify_pointer_value(pointer1, value);
        printf("after modify pointer1:%s,pointer1'=%p\n",pointer1,pointer1);

        char* pointer2; // 这时危险的方式,因为pointer1是不确定的地址
        printf("before repoint pointer2:%s,pointer2'=%p\n",pointer2,pointer2);
        repoint_the_pointer(pointer2, value);
        printf("after repoint pointer2:%s,pointer2'=%p\n",pointer2,pointer2);
        /*
        上面的内容输出:
        before modify pointer1:,pointer1'=003B3000
        after modify pointer1:This is string.w?h,pointer1'=003B3000
        before repoint pointer2:(null),pointer2'=00000000
        after repoint pointer2:(null),pointer2'=00000000
        done!

        可以看到pointer1有乱码,pointer2为NULL
        */
    #elif USE_MODE == MODE1
        char* value = "This is string.";
        // +1因为需要处理补上'\0',因为strlen不計算'\0'结束符
        // 这样指向地址之后,就不会有危险操作了
        // malloc 不会初始化 分配的内容,所以有可能before modify之前会看到乱码的输出
        // 如果需要 初始化 分配的内容,可以使用calloc,但是没必要,反正modify_pointer_value都要更改指针内容
        char* pointer1 = malloc(strlen(value) + 1);
        printf("before modify pointer1:%s,pointer1'=%p\n",pointer1,pointer1);
        modify_pointer_value(pointer1, value);
        printf("after modify pointer1:%s,pointer1'=%p\n",pointer1,pointer1);

        // 因为repointer会重新分配这里就没有必要去alloc
        // 但是从输出结果来看,pointer2在执行完repoint_the_pointer后
        // pointer2的内容还是NULL
        char* pointer2 = NULL;
        printf("before repoint pointer2:%s,pointer2'=%p\n",pointer2,pointer2);
        repoint_the_pointer(pointer2, value);
        printf("after repoint pointer2:%s,pointer2'=%p\n",pointer2,pointer2);

        /*
        上面的内容输出:
        before modify pointer1:?f,pointer1'=00661598
        after modify pointer1:This is string.,pointer1'=00661598
        before repoint pointer2:(null),pointer2'=00000000
        after repoint pointer2:(null),pointer2'=00000000
        done!

        从结果上来看,pointer2还是NULL的,我们还是需要另一中方法来处理
        */
    #elif USE_MODE == MODE2
        char* value = "This is string.";
        // +1因为需要处理补上'\0',因为strlen不計算'\0'结束符
        // 这样指向地址之后,就不会有危险操作了
        // malloc 不会初始化 分配的内容,所以有可能before modify之前会看到乱码的输出
        // 如果需要 初始化 分配的内容,可以使用calloc,但是没必要,反正modify_pointer_value都要更改指针内容
        char* pointer1 = malloc(strlen(value) + 1);
        printf("before modify pointer1:%s,pointer1'=%p\n",pointer1,pointer1);
        modify_pointer_value(pointer1, value);
        printf("after modify pointer1:%s,pointer1'=%p\n",pointer1,pointer1);

        // 注意MODE2模式中,我们使用的是 repoint_the_pointer2 函数(结尾有个2)
        char*pointer2 = NULL;
        printf("before repoint pointer2:%s,pointer2'=%p,sizeof(pointer2)=%d\n",pointer2,pointer2,sizeof(pointer2));
        // 解决方式很简单,我们对原来的
        pointer2 = repoint_the_pointer2(pointer2, value);
        printf("after repoint pointer2:%s,pointer2'=%p,sizeof(pointer2)=%d\n",pointer2,pointer2,sizeof(pointer2));

        /*
        上面的内容输出:
        before modify pointer1:?f,pointer1'=00661598
        after modify pointer1:This is string.,pointer1'=00661598
        before repoint pointer2:(null),pointer2'=00000000
        after repoint pointer2:(null),pointer2'=00000000
        done!

        从结果上来看,pointer2还是NULL的,我们还是需要另一中方法来处理
        */
    #elif USE_MODE == MODE3
        // 再来看看二级指针的方式
        char* pointer3 = malloc(sizeof(char) * 1);
        printf("before changedDoublePointer pointer3=%s,pointer3=%p\n", pointer3,pointer3);
        changedDoublePointer(&pointer3, "hello world!");
        printf("after changedDoublePointer pointer3=%s,pointer3=%p\n", pointer3,pointer3);

        /*
        USE_MODE == 3
        before changedDoublePointer pointer3=??pointer3=00C61598
        after changedDoublePointer pointer3=hello world!,pointer3=00C61598
        done!
        */

    #elif USE_MODE == MODE4

        // 危险操作!!
        // 注意我们分配给 pointer4 的只有1个字节长度的空间
        char* pointer4 = malloc(sizeof(char) * 1);
        printf("before copy pointer4=%s\n", pointer4);
        // 但是我们用了一个hello 5个字节空间的复制到 pointer4 ,那么对 pointer4 的越界操作也是危险的
        strcpy(pointer4, "hello");
        printf("after copy pointer4=%s\n", pointer4); // pointer4 == "hello",除了第一个h字符是安全的操作,后面的都是不安全的

        /*
        USE_MODE == 4
        before copy pointer4=??
        after copy pointer4=hello
        done!
        */
    #endif

    printf("done!\n");

    return 0;
}

二级指针测试

#define DATE_TYPE1 1
#define DATE_TYPE2 2
#define DATE_TYPE3 3
#define DATE_TYPE4 4
#define DATE_TYPE5 5
#define DATE_TYPE6 6
#define DATE_TYPE7 7

#define DATA_TYPE 7

#if DATA_TYPE == DATE_TYPE1
    #define ElementType char
    #define FORMAT "%d,"
#elif DATA_TYPE == DATE_TYPE2
    #define ElementType short
    #define FORMAT "%d,"
#elif DATA_TYPE == DATE_TYPE3
    #define ElementType unsigned
    #define FORMAT "%d,"
#elif DATA_TYPE == DATE_TYPE4
    #define ElementType int
    #define FORMAT "%d,"
#elif DATA_TYPE == DATE_TYPE5
    #define ElementType float
    #define FORMAT "%f,"
#elif DATA_TYPE == DATE_TYPE6
    #define ElementType double
    #define FORMAT "%lf,"
#elif DATA_TYPE == DATE_TYPE7
    #define ElementType long double
    #define FORMAT "%LG,"
    // 为了输出long double
    // long double 怎样输出?
    // https://www.zhihu.com/question/64387466
    #define __USE_MINGW_ANSI_STDIO 1
#else
    #define ElementType long long
    #define FORMAT "%ld,"
#endif

#include <stdio.h>
#include <stdlib.h>

int main() {

    printf("======================\n");
    printf("double pointer test start\n");

    // 二级指针
    const int w = 4;
    const int h = 3;
    const int e_size = sizeof(ElementType);
    const int mem_size = e_size * (w * h);
    printf("w:%d, h:%d, element size:%d(0x%X), format:%s\n", w, h, e_size, e_size, FORMAT);

    ElementType _2d_arr[3][4] = {
        1,      2,      3,      4,
        5,      6,      7,      8,
        9,      10,     11,     12
    };

    // 测试指向一级指针
    ElementType* p = (void*)&_2d_arr;
    // 指向二级指针
    ElementType** q = &p;
    // 从下面的q2,q3测试可得
    // 每多一级指针,都是间隔了一级地址(地址数据需要一个int,所以都会间隔4 bytes)
    ElementType*** q2 = &q;
    // 计算出每一行需要的字节数
    int rowSize = sizeof(_2d_arr[0]);
    int rowStep = rowSize / e_size;

    printf("row size:%d(0x%X)\n",rowSize,rowSize);

    printf("p:%p\n", p);
    printf("q:%p\n", q);
    printf("q+1:%p\n", q+1);
    printf("q2:%p\n", q2);
    printf("q2+1:%p\n", q2+1);
    printf("q2+2:%p\n", q2+2);
    
    printf("&_2d_arr:%p\n", &_2d_arr);
    printf("&_2d_arr[0]:%p\n", &_2d_arr[0]);
    printf("&_2d_arr[1]:%p\n", &_2d_arr[1]);
    printf("&_2d_arr[2]:%p\n", &_2d_arr[2]);

    // 通过二级指针来遍历
    for (size_t i = 0; i < h; i++) {
        ElementType* row = (*q) + (i * rowStep);
        printf("row[%d]:%p\n", i, row);
        printf("row:%d:", i);
        for (size_t j = 0; j < w; j++) {
            printf(FORMAT, (ElementType)*(row + j));
        }
        printf("\n");
    }

    printf("double pointer test end\n");
    printf("======================\n");

    return 0;
}

运行会有警告使用了 过期宏定义:__USE_MINGW_ANSI_STDIO

PS D:\jave\Work Files\C\Studies\8 multi D array test> gcc .\b.c -o out                                                  In file included from c:\mingw\include\stdio.h:55,
                 from .\b.c:41:
c:\mingw\include\_mingw.h:413:3: warning: #warning "Direct definition of __USE_MINGW_ANSI_STDIO is deprecated." [-Wcpp]
  413 | # warning "Direct definition of __USE_MINGW_ANSI_STDIO is deprecated."
      |   ^~~~~~~
c:\mingw\include\_mingw.h:414:10: note: #pragma message: See <_mingw.h> for preferred feature activation methods.
  414 | # pragma message "See <_mingw.h> for preferred feature activation methods."
      |          ^~~~~~~
PS D:\jave\Work Files\C\Studies\8 multi D array test> .\out.exe                                                         ======================
double pointer test start
w:4, h:3, element size:12(0xC), format:%LG,
row size:48(0x30)
p:0062fe58
q:0062fe54
q+1:0062fe58
q2:0062fe50
q2+1:0062fe54
q2+2:0062fe58
&_2d_arr:0062fe58
&_2d_arr[0]:0062fe58
&_2d_arr[1]:0062fe88
&_2d_arr[2]:0062feb8
row[0]:0062fe58
row:0:1,2,3,4,
row[1]:0062fe88
row:1:5,6,7,8,
row[2]:0062feb8
row:2:9,10,11,12,
double pointer test end
======================

assert test

#include <stdio.h>
#include <math.h>
#include <assert.h>

int main() {

    float d = 0;
    float n = 1;

    assert(d != 0);

    float v = d / n;

    printf("d/n=v\n");
    printf("%f/%f=%f\n", d, n, v);

    printf("done!\n");

    return 0;
}

/*
assert(true) 则通过
assert(false) 则抛出异常
运行输出
Assertion failed: d != 0, file .\a.c, line 10
*/

float frexp test

浮点数是如何构成的: float value = mantissa * (2 ^ exponent);

// https://www.runoob.com/cprogramming/c-standard-library-assert-h.html
// https://www.runoob.com/cprogramming/c-macro-assert.html

// 下一个测试math
// double frexp(double x, int *exponent)
// 把浮点数 x 分解成尾数和指数。返回值是尾数,并将指数存入 exponent 中。所得的值是 x = mantissa * 2 ^ exponent。

#include <stdio.h>
#include <math.h>

int main() {
    double v = 99.123;
    double mantissa = 0;
    int exponent = 0;
    mantissa = frexp(v, &exponent);
    printf("frexp(%lf), mantissa=%lf, exponent=%d\n", v, mantissa, exponent);
    double v1 = mantissa * (pow((double)2, (double)exponent));
    printf("v1 = mantissa * 2 ^ exponent\n");
    printf("v1 = %lf * (2 ^ %d)\n", mantissa, exponent);
    printf("v1 = %lf\n",v1);
    double v2 = ldexp(mantissa, exponent);
    printf("v2 = %lf\n", v2);
    return 0;
}
frexp(99.123000), mantissa=0.774398, exponent=7
v1 = mantissa * 2 ^ exponent
v1 = 0.774398 * (2 ^ 7)
v1 = 99.123000
v2 = 99.123000

以下参考了:frexp ( )【C语言库函数源代码】
【C语言库函数源代码】

【本程序在Dev C++ 4.9.9.2 下编译通过】

/*
   把浮点数x分解成尾数和指数。x=m*2^exptr,m为规格化小数。
   返回尾数m,并将指数存入exptr中。
*/
double my_frexp01(double x, int *exptr)
{
   union
   {
      double d;
      unsigned char c[8];
   } u;
   u.d = x;
   //得到移码,并减去1022得到指数值。
   *exptr = (int)(((u.c[7] & 0x7f) << 4) | (u.c[6] >> 4)) - 1022;
   //把指数部分置为0x03FE
   u.c[7] &= 0x80;
   u.c[7] |= 0x3f;
   u.c[6] &= 0x0f;
   u.c[6] |= 0xe0;
   return u.d;
}

double my_frexp02(double x, int *eptr)
{
   union
   {
      double v;
      struct
      {
        unsigned mantissa2 : 32;
        unsigned mantissa1 : 20;
        unsigned exponent : 11;
        unsigned sign :  1;
      } s;
   } u;
   if (x)
   {
      u.v = x;
      //得到移码,并减去1022得到指数值。
      *eptr = u.s.exponent - 1022;
      //把指数部分置为0x03FE
      u.s.exponent = 1022;
      return(u.v);
   }
   else
   {
      *eptr = 0;
      return((double)0);
   }
}

main()
{
   float x,y;
   int exp;
   y = 64.0;
   x = my_frexp01(y,&exp);
   printf("%f=%.2f*2^%d/n",y,x,exp);
   x = my_frexp01(-y,&exp);
   printf("%f=%.2f*2^%d/n",y,x,exp);
   
   printf("/n************************/n");
   
   x = my_frexp02(y,&exp);
   printf("%f=%.2f*2^%d/n",y,x,exp);
   x = my_frexp02(-y,&exp);
   printf("%f=%.2f*2^%d/n",y,x,exp);
   system("pause");
   return 0;
}  

long double 如何输出

#include <stdio.h>之前添加:#define __USE_MINGW_ANSI_STDIO 1

    // 为了输出long double
    // long double 怎样输出?
    // https://www.zhihu.com/question/64387466
    #define __USE_MINGW_ANSI_STDIO 1

format字符串使用"%LG"

long double a = 999.99;
printf("a = %LG\n", a); // output : a = 999.99

signal handle test

// jave.lin testing the signal
#include <stdio.h>
#include <Windows.h>
#include <signal.h>

// #define SIGTERM         15  // Software termination signal from kill
// 用一个内置的ID,因为自定义的安装不了信号处理
// #define CUSTOM_SIGNAL 1 // 无效
#define CUSTOM_SIGNAL 15

#define SETUP_SIGNAL(SIG,handler)\
    {\
        void(*cb)(int) = signal(SIG, handler);\
        if (cb == SIG_ERR) printf("setup " #SIG " error,%d\n", (int)cb); \
        else printf("setup " #SIG " signal, return : %d\n", (int)cb);\
    }\

// 信号处理回调
void signalHandler(int);
// 中断循环周期
char breakSignal = 0;
// 但循环睡眠时长:毫秒
int sleepMS = 1000;
// 触发自定义事件统计变量
int triggerCounter = 0;
// 触发自定义事件超过指定次数则退出程序
#define TRIGGER_MAX 2

void (*signalCallback)(int);

int main() {

    /*
    signal.h中的定义

    typedef void (__CRTDECL* _crt_signal_t)(int);

    #define NSIG            23  // maximum signal number + 1

    // Signal types
    #define SIGINT          2   // interrupt
    #define SIGILL          4   // illegal instruction - invalid function image
    #define SIGFPE          8   // floating point exception
    #define SIGSEGV         11  // segment violation
    #define SIGTERM         15  // Software termination signal from kill
    #define SIGBREAK        21  // Ctrl-Break sequence
    #define SIGABRT         22  // abnormal termination triggered by abort call

    #define SIGABRT_COMPAT  6   // SIGABRT compatible with other platforms, same as SIGABRT

    // Signal action codes
    #define SIG_DFL ((_crt_signal_t)0)     // default signal action
    #define SIG_IGN ((_crt_signal_t)1)     // ignore signal
    #define SIG_GET ((_crt_signal_t)2)     // return current value
    #define SIG_SGE ((_crt_signal_t)3)     // signal gets error
    #define SIG_ACK ((_crt_signal_t)4)     // acknowledge

    #ifdef _CORECRT_BUILD
        // Internal use only!  Not valid as an argument to signal().
        #define SIG_DIE ((_crt_signal_t)5) // terminate process
    #endif

    // Signal error value (returned by signal call on error)
    #define SIG_ERR ((_crt_signal_t)-1)    // signal error value

    */

    // step signal handler

    SETUP_SIGNAL(SIGINT,signalHandler)
    SETUP_SIGNAL(SIGFPE,signalHandler)
    SETUP_SIGNAL(SIGBREAK,signalHandler)
    SETUP_SIGNAL(CUSTOM_SIGNAL,signalHandler)

    printf("one.\n");
    printf("Sleep(1000);\n");
    // stdlib.h下的sleep(s),unit:seconds,过期函数
    // Windows.h下的Sleep(ms); ms:毫秒
    Sleep(1000);

    float fv = 9999999999999999900000000099999999.99999999999;
    printf("fv=%f.\n", fv); // 这么大都不溢出,有点奇怪,可能编译器截断了
    // let floating point exception
    raise(SIGFPE); // 手动触发信号

    printf("two.\n");

    printf("start loop\n");

    int counter = 0;
    while(!breakSignal) {
        printf("tick! & sleep(%d)\n", sleepMS);
        Sleep(sleepMS);
        if (++counter > 4) {
            counter = 0;
            printf("tick per 5 times raise custom signal\n", sleepMS);
            raise(CUSTOM_SIGNAL); // 手动触发信号
        }
    }

    printf("break loop done!\n");

    return 0;
}

// 信号处理
void signalHandler(int signalCode) {
    switch (signalCode) {
    case SIGINT:
        printf("receive ctrl+c interupt signal to exit.\n");
        exit(0);
        break;
    case SIGFPE:
        printf("receive floating point exception.\n");
        break;
    case SIGBREAK:
        printf("receive ctrl + Break/Pause signal to exit.\n");
        breakSignal = 1;
        break;
    case CUSTOM_SIGNAL:
        printf("receive custom signal.\n");
        if (sleepMS == 1000) {
            printf("setting sleep ms to : 100\n");
            sleepMS = 100;
        } else {
            printf("setting sleep ms to : 1000\n");
            sleepMS = 1000;
        }
        if (++triggerCounter > TRIGGER_MAX) {
            printf("trigger times researched, so safely exit.\n");
            exit(0);
        }
        // setup again
        SETUP_SIGNAL(CUSTOM_SIGNAL,signalHandler)
        break;
    default:
        printf("un handle signal code : %d", signalCode);
        break;
    }
}

下面是自然结束的输出:
也可以手动ctrl+c,或是ctrl+break/pause都可以结束

setup SIGINT signal, return : 0
setup SIGFPE signal, return : 0
setup SIGBREAK signal, return : 0
setup CUSTOM_SIGNAL signal, return : 0
one.
Sleep(1000);
fv=9999999790214768000000000000000000.000000.
receive floating point exception.
two.
start loop
tick! & sleep(1000)
tick! & sleep(1000)
tick! & sleep(1000)
tick! & sleep(1000)
tick! & sleep(1000)
tick per 5 times raise custom signal
receive custom signal.
setting sleep ms to : 100
setup CUSTOM_SIGNAL signal, return : 0
tick! & sleep(100)
tick! & sleep(100)
tick! & sleep(100)
tick! & sleep(100)
tick! & sleep(100)
tick per 5 times raise custom signal
receive custom signal.
setting sleep ms to : 1000
setup CUSTOM_SIGNAL signal, return : 0
tick! & sleep(1000)
tick! & sleep(1000)
tick! & sleep(1000)
tick! & sleep(1000)
tick! & sleep(1000)
tick per 5 times raise custom signal
receive custom signal.
setting sleep ms to : 100
trigger times researched, so safely exit.

convert str to number test

可以去查看文档或是看看stdlib.h中的API,还有N中转换数据接口

/*
C语言中将字符串转换为数字的方法
https://blog.csdn.net/weixin_34364071/article/details/86054032

 atof()     将字符串转换为双精度浮点型值
 atoi()     将字符串转换为整型值
 atol()     将字符串转换为长整型值
 strtod()   将字符串转换为双精度浮点型值,并报告不能被转换的所有剩余数字
 strtol()   将字符串转换为长整值,并报告不能被转换的所有剩余数字
 strtoul()  将字符串转换为无符号长整型值,并报告不能被转换的所有剩余数字4
*/
// 为了long double能正常输出
#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main() {
    char* char_str = "100";
    char* short_str = "32765";
    char* unsigned_str = "65535";
    char* int_str = "20000";
    char* float_str = "3.14";
    char* double_str = "3.14159265359";
    char* longlong_str = "22345678987654322";
    char* longlong64_str = "32345678987654323";
    char* longdouble_str = "9876543214567890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.1234567898765432100000000000";
    char* longdouble_str_convert_left;
    char* long_str_convert_left;

    char char_v = (char)atoi(char_str);     // 没有char的
    short short_v = (short)atoi(short_str); // 也没有short的
    unsigned unsigned_v = atoi(unsigned_str);
    int int_v = atoi(unsigned_str);
    float float_v = (float)atof(float_str); // 没有float的
    double double_v = atof(double_str);
    long long longlong_v = atoll(longlong_str);
    __int64 longlong64_v = _atoi64(longlong64_str);
    long double longdouble_v = strtold(longdouble_str, &longdouble_str_convert_left);
    long long long_v2 = strtoul(longdouble_str, &long_str_convert_left, 10);

    printf("start\n");
    printf("char_v:%c\n", char_v);
    printf("short_v:%d\n", short_v);
    printf("unsigned_v:%d\n", unsigned_v);
    printf("int_v:%d\n", int_v);
    printf("float_v:%f\n", float_v);
    printf("double_v:%f\n", double_v);
    printf("longlong_v:%lld\n", longlong_v);
    printf("longlong64_v:%lld\n", longlong64_v);
    printf("longdouble_v:%LG, left_str:%s\n", longdouble_v, longdouble_str_convert_left);
    printf("long_v2:%lld, left_str:%s\n", long_v2, long_str_convert_left);
    printf("end\n");

    /*
    start
    char_v:d
    short_v:32765
    unsigned_v:65535
    int_v:65535
    float_v:3.140000
    double_v:3.141593
    longlong_v:22345678987654322
    longlong64_v:32345678987654323
    longdouble_v:9.87654E+1341, left_str:
    long_v2:4294967295, left_str:.1234567898765432100000000000
    end

    从上面的输出结果来看,对于long double 的输出真的是服气
    都1K+的10的次方了,还没有溢出剩余的部分,有点可怕的长度

    而long_v2就溢出了可以看到left_str部分,而且还不全
    */

    return 0;
}

offsetof test

#include <stdio.h>
#include <stddef.h>

// jave.lin : 下面是 offsetof 的宏定义,他是以NULL为起始地址来取对象的地址值来计算偏移的
// #define offsetof(s,m) ((size_t)&(((s*)0)->m))

typedef struct Info {
    // 下面c~c3会在一个4 bytes,以最大成员的int的宽度对齐
    char c; // 1 byte
    char c1; // 1 byte
    char c2; // 1 byte
    char c3; // 1 byte
    int a; // 4 bytes
    char* str; // 8 bytes = int 4 bytes for string pointer + int 4 bytes for second level pionter
    int b; // 4 bytes
    char arr[10]; // 10 bytes
} InfoType;

int main() {
    #define PRINT_OFFSET(Type,Mem)\
        printf("Member:'"#Mem "' in Type:'" #Type "' offset is : %d\n", offsetof(Type, Mem));
    printf("start\n");
    printf("sizeof(InfoType) : %d\n", sizeof(InfoType));
    PRINT_OFFSET(InfoType, c);
    PRINT_OFFSET(InfoType, a);
    PRINT_OFFSET(InfoType, str);
    PRINT_OFFSET(InfoType, b);
    PRINT_OFFSET(InfoType, arr);
    printf("end\n");
    return 0;
}
start
sizeof(InfoType) : 28
Member:'c' in Type:'InfoType' offset is : 0
Member:'a' in Type:'InfoType' offset is : 4
Member:'str' in Type:'InfoType' offset is : 8
Member:'b' in Type:'InfoType' offset is : 12
Member:'arr' in Type:'InfoType' offset is : 16
end

atexit test

#include <stdio.h>
#include <stdlib.h>

// atexit 需要 stdlib.h

void beforeNormallyExitAppHandler() {
    printf("==before nromally exit the application handler here.==\n");
}

int main() {
    printf("before setup atexit callback.\n");
    atexit(beforeNormallyExitAppHandler);
    printf("after setup atexit callback.\n");

    printf("before exitting.\n");
    return 0;
}
before setup atexit callback.
after setup atexit callback.
before exitting.
==before nromally exit the application handler here.==

getenv test - 获取环境变量值

#include <stdio.h>
#include <stdlib.h>

// getenv 需要stdlib
// char *getenv(const char *name)

int main() {

    #define PRINT_ENV_VAR(name)\
    printf("[" #name "] : %s\n\n", getenv("" #name));

    PRINT_ENV_VAR(PATH)
    PRINT_ENV_VAR(JAVA_HOME)
    PRINT_ENV_VAR(CLASS_PATH)

    return 0;
}
[PATH] : C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\iCLS\;C:\Program Files\Intel\Intel(R) Management Engine Components\iCLS\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;"D:\Program Files\Java\jdk1.8.0_211\bin;D:\Program Files\Java\jdk1.8.0_211\jre\bin;";C:\MinGW\bin;C:\Users\jave\AppData\Local\Microsoft\WindowsApps;;C:\Users\jave\AppData\Local\Programs\Microsoft VS Code\bin

[JAVA_HOME] : D:\Program Files\Java\jdk1.8.0_211

[CLASS_PATH] : D:\Program Files\Java\jdk1.8.0_211\lib

system test

#include <stdio.h>
#include <stdlib.h>

// system 需要 stdlib.h

int main() {
    printf("list the current directory file infos.\n");
    // system("ls"); // gci/ls/dir 都可以, -r是递归目录
    // system("ls -r"); // gci/ls/dir 都可以, -r是递归目录
    // system("gci"); // gci/ls/dir 都可以, -r是递归目录
    // system("gci -r"); // gci/ls/dir 都可以, -r是递归目录
    system("dir"); // gci/ls/dir 都可以, -r是递归目录
    // system("dir -r"); // gci/ls/dir 都可以, -r是递归目录
    // 上面的测试发现在windows中,带了参数的这样调用是不行的,是有无参数的dir是可以执行的。
    // 直接在power shell或是cmd下,上面的所有指令都是可行的
    printf("press any key to exit.\n");
    // pause
    system("pause");
    return 0;
}
list the current directory file infos.
 驱动器 D 中的卷没有标签。
 卷的序列号是 FAB7-6D0B

 D:\jave\Work Files\C\Studies\33 system test 的目录

2020/04/21  16:02    <DIR>          .
2020/04/21  16:02    <DIR>          ..
2020/04/21  16:02               846 a.c
2020/04/21  15:52    <DIR>          dir1
2020/04/21  15:52    <DIR>          dir2
2020/04/21  16:02            43,265 out.exe
               2 个文件         44,111 字节
               4 个目录 902,984,269,824 可用字节
press any key to exit.
请按任意键继续. . .

windows powershell or cmd直接输入指令是没有问题的

PS D:\jave\Work Files\C\Studies\33 system test> dir -r                                                                  

    目录: D:\jave\Work Files\C\Studies\33 system test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        2020/4/21     15:52                dir1
d-----        2020/4/21     15:52                dir2
-a----        2020/4/21     16:02            846 a.c
-a----        2020/4/21     16:02          43265 out.exe


    目录: D:\jave\Work Files\C\Studies\33 system test\dir1


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2020/4/21     15:52              0 test1.txt
-a----        2020/4/21     15:52              0 test2.txt


    目录: D:\jave\Work Files\C\Studies\33 system test\dir2


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        2020/4/21     15:52              0 albedo.bmp
-a----        2020/4/21     15:52              0 ao.bmp
-a----        2020/4/21     15:52              0 height.bmp
-a----        2020/4/21     15:52              0 normal.bmp
-a----        2020/4/21     15:52              0 specular.bmp

gcc size tools

先查看size工具帮助
一下说明是该工具可以显示二进制内部的块大小,如果没设置输入文件,将以a.out为默认的输入

PS D:\jave\Work Files\C\Studies\36 size test> size -h                                                                   Usage: C:\MinGW\bin\size.exe [option(s)] [file(s)]
 Displays the sizes of sections inside binary files
 If no input file(s) are specified, a.out is assumed
 The options are:
  -A|-B     --format={sysv|berkeley}  Select output style (default is berkeley)
  -o|-d|-x  --radix={8|10|16}         Display numbers in octal, decimal or hex
  -t        --totals                  Display the total sizes (Berkeley only)
            --common                  Display total size for *COM* syms
            --target=<bfdname>        Set the binary file format
            @<file>                   Read options from <file>
  -h        --help                    Display this information
  -v        --version                 Display the program's version

C:\MinGW\bin\size.exe: supported targets: pe-i386 pei-i386 elf32-i386 elf32-iamcu elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex

下面是使用

PS D:\jave\Work Files\C\Studies\36 size test> size .\out.exe -B -d -t                                                      text    data     bss     dec     hex filename
  15456    1528     112   17096    42c8 .\out.exe
  15456    1528     112   17096    42c8 (TOTALS)
PS D:\jave\Work Files\C\Studies\36 size test> size .\out.exe -A -d -t                                                   .\out.exe  :
section           size      addr
.text            11460   4198400
.data               24   4210688
.rdata            1572   4214784
.eh_frame         2424   4218880
.bss               112   4222976
.idata            1448   4227072
.CRT                24   4231168
.tls                32   4235264
.debug_aranges      56   4239360
.debug_info       7884   4243456
.debug_abbrev      329   4251648
.debug_line        452   4255744
.debug_frame        56   4259840
.debug_str         134   4263936
Total            26007

setjmp, longjmp test

在单个函数内执行跳转

// jave.lin 这个例子我们只演示同一个方法内的jmp处理
#include <stdio.h>
#include <setjmp.h>
#include <Windows.h>

// setjmp longjmp test
static jmp_buf stack_frame_buff;

int main() {
    
    int a = 1;
    int b = 2;

    int counter = 0;
    const int max = 5;

    char th_str[4][10] = { "%dst", "%dnd", "%dthd", "%dth" };
    char th_str_v[10];

    int idx = 0;

    printf("before setjmp, a=%d, b=%d, stack_frame_buff=%p\n", a, b, stack_frame_buff);
    int ret = setjmp(stack_frame_buff); // jave.lin:第一次 Label 的地方
    if (ret == 0) {
        printf("=====this is directly call setjmp, return 0.\n");
    } else {
        printf("=====this is longjmp(buff, 1) call, return %d\n", ret);
    }

    ret = setjmp(stack_frame_buff); // jave.lin:第二次 Label 会将前一次的 覆盖掉,当longjmp同一个stack_frame_buff时,只会跳转到最后一个setjmp的地方
    if (ret == 0) {
        printf("-----this is directly call setjmp, return 0.\n");
    } else {
        printf("-----this is longjmp(buff, 1) call, return %d\n", ret);
    }
    printf("after setjmp, a=%d, b=%d, stack_frame_buff=%p\n", a, b, stack_frame_buff);

    b = 1;
    a = 2;
    printf("after modify, a=%d, b=%d\n", a, b);

    printf("Sleep(1000)\n");
    Sleep(1000);

    printf("now longjmp(stack_frame_buff, 1)\n");
    if (counter++ < max) {
        idx = counter - 1;
        idx = idx > 3 ? 3 : idx;
        sprintf(th_str_v, th_str[idx], counter);
        printf("longjmp %s times reaching.\n", th_str_v);
        longjmp(stack_frame_buff, 1); // jave.lin:只跳转到该stack_frame_buff记录的栈帧数据的最后一帧,意思如果重复set的话,只会jmp到最后一次set的stack_frame_buff的帧数据
    } else {
        printf("longjmp %d times reaching.\n", max);
    }

    printf("done!\n");

    return 0;
}
before setjmp, a=1, b=2, stack_frame_buff=00407020
=====this is directly call setjmp, return 0.
-----this is directly call setjmp, return 0.
after setjmp, a=1, b=2, stack_frame_buff=00407020
after modify, a=2, b=1
Sleep(1000)
now longjmp(stack_frame_buff, 1)
longjmp 1st times reaching.
-----this is longjmp(buff, 1) call, return 1
after setjmp, a=2, b=1, stack_frame_buff=00407020
after modify, a=2, b=1
Sleep(1000)
now longjmp(stack_frame_buff, 1)
longjmp 2nd times reaching.
-----this is longjmp(buff, 1) call, return 1
after setjmp, a=2, b=1, stack_frame_buff=00407020
after modify, a=2, b=1
Sleep(1000)
now longjmp(stack_frame_buff, 1)
longjmp 3thd times reaching.
-----this is longjmp(buff, 1) call, return 1
after setjmp, a=2, b=1, stack_frame_buff=00407020
after modify, a=2, b=1
Sleep(1000)
now longjmp(stack_frame_buff, 1)
longjmp 4th times reaching.
-----this is longjmp(buff, 1) call, return 1
after setjmp, a=2, b=1, stack_frame_buff=00407020
after modify, a=2, b=1
Sleep(1000)
now longjmp(stack_frame_buff, 1)
longjmp 5th times reaching.
-----this is longjmp(buff, 1) call, return 1
after setjmp, a=2, b=1, stack_frame_buff=00407020
after modify, a=2, b=1
Sleep(1000)
now longjmp(stack_frame_buff, 1)
longjmp 5 times reaching.
done!

在单个函数重复执行

#include <stdio.h>
#include <setjmp.h>
#include <string.h>

static int get_result_buff_jmp_counter = 0;
static jmp_buf get_result_buff;

void GetResult(int* result) {
    if (get_result_buff_jmp_counter != 0) {
        longjmp(get_result_buff, get_result_buff_jmp_counter++);
    }

    // 不要放这里,因为不会恢复栈帧数据    
    // int num = 1000;
    int ret = setjmp(get_result_buff);
    int num = 1000;

    if (ret == 0) {
        get_result_buff_jmp_counter = 1;
    }
    if (ret < 3 ) {
        *result = num + ret;
    } else {
        *result = -1;
        get_result_buff_jmp_counter = 0;
    }
}

int main() {
    printf("GetResult start\n");

    int result;

    do
    {
        GetResult(&result);
        if (result != -1) {
            printf("Get result : %d\n", result);
        } else  {
            break;
        }
    } while (1);
    
    printf("GetResult end\n");
    return 0;
}
GetResult start
Get result : 1000
Get result : 1001
Get result : 1002
GetResult end

多个方法之间的跳转

#include <stdio.h>
#include <setjmp.h>
#include <string.h>

static jmp_buf buff;

void b_func(int* num) {
    printf("enter b_func. and jmp back to main func.\n");
    (*num)++;
    longjmp(buff, 1);
}

int main() {
    int main_a = 999;
    char main_b[10] = "test";
    int main_c = 1;
    printf("before setjmp main_a=%d, main_b=%s, main_c=%d\n", main_a, main_b, main_c);
    if (setjmp(buff) == 0) {
        strcpy(main_b, "hello");
        printf("first setjmp, to run b_func. main_a=%d, main_b=%s, main_c=%d\n", ++main_a, main_b, ++main_c);
        // 注意这里我们在 b_func 修改了main_c
        // 但是跳转回来后 main_c 的值还是 b_func 修改后的值
        b_func(&main_c);
    } else {
        // 注意这里我们在 b_func 修改了main_c
        // 但是跳转回来后 main_c 的值还是 b_func 修改后的值,并没有恢复到 setjmp 时候的栈帧数据
        printf("jmp back from b_func. main_a=%d, main_b=%s, main_c=%d\n", main_a, main_b, main_c);
    }

    printf("done!\n");

    return 0;
}
before setjmp main_a=999, main_b=test, main_c=1
first setjmp, to run b_func. main_a=1000, main_b=hello, main_c=2
enter b_func. and jmp back to main func.
jmp back from b_func. main_a=1000, main_b=hello, main_c=3
done!

struct initialize test

#include <stdio.h>

typedef struct Person {
    char* name;
    unsigned char age;
} Person;

int main() {
    Person p = { "Name", 18 }; // 无字段名,则需要按字段顺序初始化
    printf("p.name:%s, p.age:%d\n", p.name, p.age);

    Person p1 = { .age = 20, .name = "tony" };  // 有字段名,可以不按字段顺序初始化
    printf("p1.name:%s, p1.age:%d\n", p1.name, p1.age);

    return 0;
}

References

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: nndl-book是指《自然语言处理综述》一书,它是由计算机科学领域的权威学者Christopher Manning和Hinrich Schütze共同编写的一本综述自然语言处理技术的教材。这本书首次出版于1999年,现已有第二版和第三版。nndl-book的内容广泛而深入,涵盖了自然语言处理领域的基础知识和最新进展,包括文本处理、语法分析、语义理解、信息检索、机器翻译等等方面。此外,书中还涉及了许多实用的技术和算法,比如条件随机场、最大熵模型、词向量和深度学习等。nndl-book的读者群体包括学术界和工业界的研究者、开发者和学生,也适合对自然语言处理领域感兴趣的读者学习。总之,nndl-book是自然语言处理领域的一本重要的参考书籍,它为我们深入了解自然语言处理的技术和应用提供了宝贵的指导。 ### 回答2: NNDL-Book是一个著名的Python深度学习库,它是一个开源项目,由加拿大多伦多大学教授Geoffrey Hinton和他的学生Alex Krizhevsky等人创建。NNDL-Book在计算机视觉、自然语言处理和语音识别等领域得到广泛应用,它提供了丰富的神经网络模型和算法,包括卷积神经网络(CNN)、循环神经网络(RNN)和长短时记忆网络(LSTM)等。此外,NNDL-Book还提供了多种数据处理工具和训练技巧,以帮助开发者更高效地构建和训练深度学习模型。总的来说,NNDL-Book是深度学习领域的重要工具之一,对于帮助人们在各种应用场景中实现AI自动化,提高效率和精度都有很大的帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值