学习记录C

学了这么久,终于开始实训项目了。。。。。。。

 

奥里给 !!!

 

压力好大,好喜欢什么也不想的时候

 

记录学习的代码 

分享一下  

 

 

/*
system函数:(        #include<stdlib.h>        )

    system("pause");//暂停
    system("calc");//计算器
    system("notepad");//记事本
    system("mspaint");//画图工具
    system("cls");// 清屏
    system("cmd");//命令行
*/

/*
#include<Windows.h>
Sleep(2000);//睡眠2000ms

*/


//#include<stdio.h>
//#include<stdlib.h>
//#include<Windows.h>
//
//int main() {
//    //float a, b;
//    //printf("请输入身高(cm):\n");
//    //scanf_s("%f", &a);
//    //printf("请输入体重(kg):\n");
//    //scanf_s("%f", &b);
//    printf("\n");
//    for (int i = 0;i < 5;i++) {
//        printf("超重!!!\n");
//    }
//
//    Sleep(2000);//睡眠2000ms
////    system("pause");
////    system("calc");//计算器
////    system("notepad");//记事本
////    system("mspaint");//画图工具
//    system("cls");// 清屏
//    system("cmd");//命令行
//
//    return 0;
//}






/*
gcc.hello.c -o hello.exe

分解开即为:
预处理 编译 汇编 链接
==================================
        源文件        hello.c    

预处理        命令 -E        展开头文件 展开宏定义 替换注释 展开条件编译...

        预处理文件    hello.i

编译        命令 -S        逐行检查语法错误 翻译成汇编文件

        汇编文件    hello.s

汇编        命令 -c        翻译成二进制机器指令

        目标文件    hello.o

链接        命令 无        数据段合并 数据地址回填 库引入

        可执行文件    hello.exe
==================================



*/


//#include<stdio.h>
//int main() {
//    int a;
//    int b;
//    int c;
//
//    _asm {//Visual studio C++ 兼容 c ;c兼容汇编
//        mov a,3
//        mov b,4
//        mov eax,a
//        add eax,b
//        mov c,eax
//    }
//    printf("%d \n", c);
//    return 0;
//}


/*
Visualstudio添加断点:
    快捷键为F9
*/



/*
F10,F11是调试时用的,

俩者区别:
    F10是逐过程调试:不会进入自定义函数内部。
    F11是逐语句调试:会进入自定义函数内部。
    
F11比F10细一些,但是部分代码需要快速跳过,2者结合用效果最佳。
*/
//#include<stdio.h>
//void s() {
//    printf("1    \n");
//    printf("2    \n");
//
//}
//int main() {
//    s();
//    printf("------    \n");
//}
  
/*
visual studio常用快捷键:
    ctrl+k+f        格式化代码
    ctrl+k+c        注释代码
    ctrl+k+u        取消注释代码
    F9                设置断点
    F5                调试运行
    ctrl+F5            运行(不调试)
    ctrl+shift+b    编译不运行
    F10                next调试(next下一个)
    F11                step调试(step步长)


*/



   

//#include<stdio.h>
//#include<Windows.h>
//int main(void) {
//    system("F:\SunloginClient_12.0.1.39931.exe");//打开向日葵远程
//    printf("Hello world \n");
//    return 0;        
//}







/*
常量:不会变化的数据
    1."hello"字符串常量,'A'字符常量,10 整型常量,3.1415926 浮点常量(实型常量)
    2.#define PI 3.1415        定义宏 定义语法:#define 宏名 宏值。
    3.const int a=10;
        const关键字:被该关键字修饰的变量,表示为只读变量。

变量:会变化的数据
    1.定义语法:类型名 变量名=变量值(一般方法)
    2.变量三要素:类型名 变量名 变量值。int r=3;float s=PI*r*r;(变量值为表达式)
    3.变量的定义:int a=40;
    4.变量的声明:
        1).int a;没有变量值的变量定义叫做声明。
        2).extern int a;添加了关键字extern。
        变量定义会开辟内存空间:变量声明不会开辟内存空间。
        变量要使用必须有定义。 变量使用之前必须看到变量定义。若没有变量定义,编译器会自动寻找一个变量声明提升为定义。如果该变量的声明前有extern关键字无法提升。
        定义变量不要重名。

标识符:变量和常量的统称
    命名规则:
        1.常量是用大写,变量使用小写。大小写严格区分。
        2.只能使用字母数字下划线命名标识符。且数字不能开头。a-z/A-Z/0-9/_
        3.禁止使用关键字和系统函数作为标识符名称。 main/system/printf/sleep
          
整形:
    int类型:
        int 名 = 值;
    short类型:
        short 名 = 值;        short s1=3;
    long类型:
        long 名 = 值;        long len = 4;
    long long 类型:
        long long 名=值;    long long llen=0;



 

        
*/
//#include<stdio.h>
//int main() {
//    const int a = 5;
//    printf("a=%d",a);
//}









/*
sizeof关键字:
    sizeof不是函数,所以不需要包含任何头文件,它的功能是计算一个数据类型的大小,单位为字节。
    sizeof的返回值为size_t
    size_t类型在32位操作系统下是unsigned int,是一个无符号整数 
    使用%u接收返回值。

使用方式:
    1.sizeof(a)
    2.sizeof a

*/

//#include<stdio.h>
//int main() {
//    int a = 0;
//    unsigned int b = 0;
//    printf("%d\n", sizeof(a));
//    printf("%d\n", sizeof  b);
//}



//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    printf("int\t大小为:%d \n",sizeof(int ));
//    printf("short\t大小为:%d \n",sizeof(short));
//    printf("long\t大小为:%d \n",sizeof(long));
//    printf("long long\t大小为:%d\n",sizeof(long long));
//
//    system("pause");
//}



/*
有符号整形:
    signed:有符号(超级不常用,通常省略):int a=10;
    int 类型:%d        4字节
        int 名 = 值;
    short类型:%hd        2字节
        short 名 = 值;
    long类型:%ld        4字节
    windows:32/64:4字节;Linux:32位:4字节,64位:8字节
        long 名 = 值;
    long long类型:%lld    8字节
        long long 名=值;


无符号整型:
    unsigned:无符号    只表示数据量,而没有方向(没有正负)
    unsigned int类型:%u        4字节
        unsigned int 名 = 值;
        unsigned int a=40;
        unsigned int a=-4;//错误 无符号!
    unsigned short类型:%hu        2字节
        unsigned short 名 = 值;
    unsigned long类型:%lu        4字节
    windows:32/64:4字节;Linux:32位:4字节,64位:8字节
        unsigned long 名 = 值;
    unsigned long long类型:%llu    8字节
        unsigned long long 名=值;



char字符类型:1字节
    存储一个字符:本质是ASCII码'A' 'a' '%' '#' '0'
    格式匹配符:%c
    'A':65
    'a':97
    '0':48
    '\n':10
    '\0':0
    转义字符:'\'将普通字符转为特殊意义,将特殊字符转为本意。


实型(浮点型,小数):
    float:单精度浮点型            4字节
        float v1=4.345
        默认保留六位小数,如果为%.4f则为保留4位小数,第五位做四舍五入。
    double:双精度浮点型        8字节【赋值时不加f 默认位double 】









*/

//#include<stdio.h>
//void main() {
//    //unsigend int a = -5;
//    int a = -5;
//    9LL;
//
//    printf("%d    \n", a);
//
//    float m = 3.14159;
//    double n = 3.14159;
//    printf("m=%08.2f\n", m);
//    printf("n=%Lf\n", n);
//}






/*
 传统方式赋值:
    float a=3.14f;//或者3.14F
    double b=3.14;

    printf("a=%f \n",a);
    printf("b=%lf \n",b);

科学方式赋值:
    a=3.2e3f;//3.2*1000=3200;e也可写为E
    printf("a1=%f    \n",a);

    a=100e-3f;//100*0.001=0.1
    printf("a2=%f    \n",a);

    a=3.1415926f;
    printf("a=%f    \n", a);//结果为3.141593

*/

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//        printf("\a");
//        Sleep(300);
//        printf("%08.2f    \n", 8.8888);
//        printf("% 8.3f    \n", 8.8888);
//        printf("%8.2f    \n", 8.8888);
//        float a = 3.1415926f;
//        printf("a=%f    \n", a);
//}



/*
进制和转换:
    bin二进制    不能直接给变量赋值二进制
    oct八进制    0开头每位数为0-7
    dec十进制    
    hex十六进制

    十进制转为二进制:除二反向取余法
    二进制转为十进制: 
        2^10    =1024
        2^9        =512
        2^8        =256
        2^7        =128
        2^6        =64
        2^5        =32
        2^4        =16
        2^3        =8
        2^2        =4
        2^1        =2
        2^0        =1


    八进制转换为十进制
        定义八进制数语法:
            056:零开头,每位数0-7之间---46
            0124    ---84
        
    八进制转换为二进制
        按照421码转化
        056:5--》101        6---》110
            101110
        05326:5---》101        3---》012        2---》010        6---》110
            101011010110
    不允许给变量直接赋值二进制数据

    2进制转换为8进制:
         1 010 111 010 110:12726
         从右开始三位一算,按421码,高位不足三位前面补0,为12726

    16进制:
        语法:0x开头,每位取0-9/A-F/a-f
            A--10
            B--11
            C--12
            D--13
            E--14
            F--15
        16--->10:
            0X1A:16+10=26
            0x13F:F=15---16^1*3---16^2*1=15+48+256=319
        16--->2:
            0x1A:00011010
            0x13F:000100111111
        2--->16:
            0001 0011 1111:13F
            自右向左,每四位一组,按8421码转换,高位不足三位补0






    %d:有符号整型
    %u:无符号整型
    %x:十六进制
    %c:字符
    %s:字符串
*/


/*
存储知识:
    1bit位 就是一个二进制位
    一个字节 1B=8bit
    1KB    =1024B
    1MB    =1024KB
    1GB    =1024MB
    1TB    =1024GB


原码反码补码:
    源码:
        ...
    反码:
        ...
    补码:
        ...

    -128的补码为什么是1000 0000
    了解即可!



*/





//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    //int a = 56;
//    int a = 0x2C;
//    printf("10进制显示    a=%d\n", a);
//    printf("8进制显示    a=0%o\n", a);
//    printf("16进制显示    a=0x%x\n", a);
//    system("Pause");
//}

/*
总结:
    输出格式:
        %d 十进制
        %u 无符号十进制
        %o 八进制
        %x 十六进制
        %hd %hu %ld %lu %lld %llu
        %c 字符
        %f 浮点数
        %lf double类型
        %s 字符串

*/



//#include<stdio.h>
//int main() {
//    char ch = 127 + 2;
//    printf("%d", ch);
//}



/*
extern:
    表示声明,没有内存空间,不能提升。
const:
    限定一个变量为只读变量。
volatile:
    防止编译器优化代码。(变量开始赋一个值,执行中赋几个值,有特殊含义的话,结束时还是初值的时候,编译器会把中间的值给省略掉)
register:
    定义一个寄存器变量。寄存器变量没有内存地址。
字符串:
    C语言中,用双引号引着的一串字符,称之为字符串,一定有一个结束标记’\0‘
    char ch = 'A';一个字节
    "asd"---->'a' 's' 'd' '\0'
    'a'不等价于"a"字符a和字符串a(有\0结尾)
    
printf();
    %s--->挨着从字符串第一个字符开始,打印到'\0'结束。
    %d:打印整数
    %c:打印字符
    %m.n:打印实型,一共有m位(整数,小数,小数点),n位小数。
    %0m.nf:打印实型,一共有m位(整数,小数,小数点),不足m位使用0填充,n位小数。
    %%显示一个%,转义字符'/'对于%转义无效。
    %Ns显示N个字符串,不足N使用空格向左填充。

putchar函数:
    输出一个字符到屏幕。
    直接使用ASCII码。(字符的本质就是ASCII码。)
    不能输出字符串
    'abc'既不是一个有效字符,也不是一个有效字符串。
    常用putchar('\n');来打印换行。同    printf("\n");

scanf函数:
    从键盘接收用户输入。
    1.接收整数 %d
        int a,b,c;创建变量空间,
        scanf("%d%d%d",&a,&b,&c);
    2.接收字符%c
        char a,b,c;
        scanf("%c%c%c",&a,&b,&c);
    3.接收字符串%s
        char  str[10];//定义一个数组,用来接收用户输入的字符串。
        scanf("%s",str);//变量名要取地址传递给scanf,数组名本身表示地址,不用&符。
    接收字符串:
        1. 具有安全隐患,如果存储空间不足,数据能存到内存中,但不被保护【空间不足不要使用】
        2.scanf函数接收字符串时,碰到空格和换行会自动终止,不能使用 scanf 的 %s 接收带有空格的字符串。

    将    #define _CRT_SECURE_NO_WARNINGS添加到程序第一行。可以解决scanf的4996错误。

getchar()函数:
    从键盘获取用户输入到屏幕的一个字符。
    返回该获取的字符的ASCII码。
    



*/


//#include<stdio.h>
//int main() {
//    printf("%5s        \n", "aa");
//    putchar('a');
//    putchar('\n');
//    putchar('a');
//}

/*
scanf
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    char sr[5] = {'a','b','c','d','e'};
//    scanf_s("%s", sr,5);
//    //char sr1[5] = {'a','b','c','d','/0'};
//
//    printf("\n");
//
//    printf("%s",sr);
//
//    //scanf_s("%s", sr, 10);
//    //printf("//    \n");
//    //printf("/%    \n");
//    //printf("%%    \n");
//    system("Pause");
//}


/*
输入除回车以外的字符 回车后 原样打印该字符串
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int c;
//    while ((c = getchar()) != '\n') {
//        printf("%c", c);
//    }
//}





/*
算术运算符:
    先* / % 后 + -
    除法运算后,得到的结果赋值给整型变量时,取整数部分。
    除0:错误操作,不允许。
    对0取余:错误操作,不允许。
    不允许对小数取余:
        35%3.4——>>错误 3.4 位置只能是整数。
    对负数取余,结果为余数的绝对值。
    printf("%d    \n", 10 % 3);---------->1
    printf("%d    \n", 10 % 3.0);------------->错误----->不能取余一个小数
    printf("%d    \n", 10 % -3);---------->1
    printf("%d    \n", -10 % 3);---------->-1




++和--:
    前缀自增 自减:
        先自增 自减,再取值。

    后缀自增 自减:
        先取值,再自增 自减。 

%取余(模):
    3%5----->    3
    20%6----->    2
    6%20----->    6


*/

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    printf("%d    \n", 10 % 3);
////    printf("%d    \n", 10 % 3.0);            //不能取余一个小数
//    printf("%d    \n", 10 % -3);
//    printf("%d    \n", -10 % 3);
//
//    system("pause");
//}




//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 10;
//    printf("a=    %d    \n", ++a);
//    printf("a=    %d    \n", a++);
//    system("pause");
//}






/*
赋值运算符:
    int a=5;
    a+=10;//a=a+10;
    a-=20;//a=a-20;
    a%=5;//a=a%5; 


比较运算符:
    ==    判等;
    !=    不等于;
    <    小于;
    <=    小于等于;

    13<var<16是数学上的写法,在计算机中不允许。
    13<var && var<16 是在计算机中的表示方法。


逻辑运算符:0为假,非0为真(一般以1来表示);
    
    !    逻辑非;            非真为假,非假为真;

    &&    逻辑与;(并且)    同真为真,其余为假;

    ||    逻辑或:(或)        有真为真,同假为假;


运算符优先级:(++a++不同操作系统运行结果不同 )
    []        ()        >        ++        --(后缀高于前缀)        (强转)        sizeof        >        算术运算



三目运算符:        ?:
    表达式1 ? 表达式2 : 表达式3;
    表达式1是一个判别表达式。如果为真,整个三目运算取值表达式2。
                            如果为假,整个三目运算取值表达式3。    


逗号运算符:    (优先级最低)
    自左到右

    

*/

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 34;
//    int b = !a;
//    printf("b=%d", b);
//}

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 1;
//    int b = 1;
//    printf("%d", a&&b);
//}

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 1;
//    int b = 0;
//    printf("%d", a || b);
//}


//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 1;
//    int b = 2;
//
//    a > b ? printf("表达式2") : printf("表达式3");
//    putchar('\n');
//    a < b ? printf("表达式2") : printf("表达式3");
//    putchar('\n');
//    a < b ? (a++, printf("a:%d    b:%d    \n", a, b)) : (a=5, printf("a:%d    b:%d    \n", a, b));//三目运算的嵌套
//
//
//
//    putchar('\n');
//    system("pause");
//}



//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int  a = 10, b = 20, c = 30;
//
//    int x = (a = 1, b = 2, c = 3);//逗号运算符。    每个逗号运算符的值都是最后一个表达式的值
//    
//    printf("x    =    %d    \n", x);
//    printf("a    =    %d    \n", a);
//    printf("b    =    %d    \n", b);
//    printf("c    =    %d    \n", c);
//
//    system("pause");
//}


/*

优先级:

优先级        运算符            名称或含义                使用形式                                结合方向                说明
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    1            []            数组下标                数组名[常量表达式]                        自左到右
    1            ()            圆括号                    (表达式)/函数名(形参表)                自左到右
    1            .            成员选择(对象)        对象.成员名                                自左到右
    1            ->            成员选择(指针)        对象指针->成员名                        自左到右
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    2            -            负号运算符                -表达式                                    右到左                    单目运算符
    2            ~            按位取反运算符            ~表达式                                    右到左                    单目运算符                    称为 “飘号”
    2            ++            自增运算符                ++变量名/变量名++                        右到左                    单目运算符        
    2            --            自减运算符                --变量名/变量名--                        右到左                    单目运算符        
    2            *            取值运算符                *指针变量                                右到左                    单目运算符
    2            &            取址运算符                &变量名                                    右到左                    单目运算符
    2            !            逻辑非运算符            !表达式                                右到左                    单目运算符
    2            (类型)        强制类型转换            (数据类型)表达式                        右到左                        
    2            sizeof        长度运算符                sizeof(表达式)                        右到左                    
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    3            /            除                        表达式/表达式                            自左到右                双目运算符    
    3            *            乘                        表达式*表达式                            自左到右                双目运算符    
    3            %            余数(取模)            整形表达式%整形表达式                    自左到右                双目运算符    
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    4            +            加                        表达式+表达式                            自左到右                双目运算符    
    4            -            减                        表达式-表达式                            自左到右                双目运算符     
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    5            <<            左移                    变量<<表达式                            自左到右                双目运算符         
    5            >>            右移                    变量>>表达式                            自左到右                双目运算符         
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    6            >            大于                    表达式>表达式                            自左到右                双目运算符
    6            >=            大于等于                表达式>=表达式                            自左到右                双目运算符
    6            <            小于                    表达式<表达式                            自左到右                双目运算符
    6            <=            小于等于                表达式<=表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    7            ==            等于                    表达式==表达式                            自左到右                双目运算符
    7            !=            不等于                    表达式!=表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    8            &            按位与                    表达式&表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    9            ^            按位异或                表达式^表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    10            |            按位或                    表达式|表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    11            &&            逻辑与                    表达式&&表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    12            ||            逻辑或                    表达式||表达式                            自左到右                双目运算符
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    13            ?:            条件运算符                表达式1  ?  表达式2  :  表达式3            右到左                    三目运算
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    14            =            赋值运算符                变量=表达式                                右到左                                    
    14            /=            除后赋值                变量/=表达式                            右到左                
    14            *=            乘后赋值                变量*=表达式                            右到左                
    14            %=            取模后赋值                变量%=表达式                            右到左                
    14            +=            加后赋值                变量+=表达式                            右到左                
    14            -=            减后赋值                变量-=表达式                            右到左                
    14            <<=            左移后赋值                变量<<=表达式                            右到左                
    14            >>=            右移后赋值                变量>>=表达式                            右到左                
    14            &=            按位与后赋值            变量&=表达式                            右到左                
    14            ^=            按位异或后赋值            变量^=表达式                            右到左                
    14            |=            按位或后赋值            变量|=表达式                            右到左                
--------------------------------------------------------------------------------------------------------------------------------------------------------------
    15            ,            逗号运算符                表达式,表达式                            自左到右

*/



//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    char str[10] = "hello";
//
//    printf("%c    \n", str[0]);
//    printf("%c    \n", str[0]);
//    printf("%c    \n", str[0]+=2);
//
//}



/*
类型转换:            
    1.隐式类型转换:
        由编译器自动完成。
        由赋值产生的类型转换:小转大没问题,大转小会发生数据丢失。
            
            高            double    <-------------float
            /\                /\
            |                |
            |                |
            |                long
            |                /\
            |                |
            |                |
            |                unsigned int
            |                /\
            |                |
            |                |
            低        signed int <--------char,short

        由赋值产生的类型转换:
            int r=3;
            float s=3.14*r*r;            //3.14默认为double类型,乘r时都转换为double,运算结束,转换为float类型


        321:    256        128        64        32        16        8        4        2        1
        二进制:1        0        1        0        0        0        0        0        1
        char ch=        0        1        0        0        0        0        0        1 所以值为65

    2.强制类型转换:
        语法:    (目标类型)带转换变量
                (目标类型)带转换表达式
        大多数用于函数调用期间,实参给形参传值。
        例如:int *p = (int *)malloc(100);

*/


//隐式类型转换
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 321;
//    char ch = a;
//    printf("%d    \n", ch);
//
//    system("Pause");
//}


//强制类型转换
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    float price = 3.6;
//    int weight = 4;
//    //double sum = price * weight;
//    //double sum = (int )price * weight;
//    double sum = int(price * weight);
//
//    printf("价格:%.2lf    \n", sum);
//
//    system("Pause");
//    return 1;
//}




/*
4.1概述
    C语言支持最基本的三种程序运行结构:顺序结构,选择结构,循环结构。
        顺序结构:程序按顺序执行,不发生跳转。
        选择结构:依据是否满足条件,有选择地执行相应功能。
        循环结构:依据条件是否满足,循环执行某段代码。
        

if分支语句:    匹配一个范围,属于模糊匹配
    if(判别表达式1){
        判别表达式为真,执行代码。
    }
    else if(判别表达式2){
        判别表达式1为假,并且判别表达式2,执行代码。
    }
    else if (判别表达式3){
        判别表达式1为假,判别表达式2为假,判别表达式3,执行代码。
    }
    。。。
    。。。
    。。。
    else{
        以上所有判别表达式都为假,执行代码。
    }




*/






//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    printf("请输入a的值:a=");
//    int a;
//    scanf_s("%d", &a);
//
//    if (a > 0) {
//        printf("a>0!    \n");
//    }
//    else {
//        printf("a<=0!    \n");
//
//    }
//    system("Pause");
//}

/*
判断成绩:
100-90        :优秀
90-70        :良好
70-60        :及格
<60            :差劲
*/





/*
该宏定义可以解决scanf的4996错误。
    #define _CRT_SECURE_NO_WARNINGS
或者使用:
    #pragma warning(disable:4996)

*/




////#define _CRT_SECURE_NO_WARNINGS
////#pragma warning(disable:4996)
//#include<stdio.h>
//#include<windows.h>
//void main001() {
//    printf("请输入成绩:\n");
//
//    int score;
//    //scanf("%d", &score);
//    scanf_s("%d", &score);
//
//    if (score >= 90 && score <= 100) {
//        printf("优秀!    \n");
//    }
//    else if (score < 90 && score >= 70) {
//        printf("良好!    \n");
//    }
//    else if (score < 70 && score >= 60) {
//        printf("及格!    \n");
//    }
//    else {
//        printf("error!    \n");
//    }
//    
//}
//
//int main() {
//    for (int i = 0;i < 3;i++) {
//        main001();
//    }
//    system("Pause");
//}


/*
练习:三只小猪称体重:
    屏幕输入三只小猪的重量,借助if分支语句,找出最重的小猪的重量
  
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int p1, p2, p3;
//
//    printf("请输入三只小猪的体重:\n");
//    printf("请输入 1 只小猪的体重:\n");
//    scanf_s("%d", &p1);
//    printf("请输入 2 只小猪的体重:\n");
//    scanf_s("%d", &p2);
//    printf("请输入 3 只小猪的体重:\n");
//    scanf_s("%d", &p3);
//
//    system("Pause");
//
//    if (p1 > p2) {
//        if (p1 > p3) {
//            printf("第一支小猪最重,为:%d", p1);
//        }
//        else {
//            printf("第三支小猪最重,为:%d", p3);
//        }
//    }
//    else {
//        if (p2 > p3) {
//            printf("第二支小猪最重,为:%d", p2);
//        }
//        else {
//            printf("第三支小猪最重,为:%d", p3);
//        }
//    }
//}



/*
switch分支:
    switch(判别表达式)            ---判别表达式:可以是一个普通的变量,也可以是运算表达式
    {
        case 1:
            执行语句1;
            break;
        case 2:
            执行语句2;
            break;
        case 3:
            执行语句3;
            break;
        ......
        case N:
            执行语句N;
            break;
        default:
            break;
    }

    case穿透:        ---break是用来防止case穿透的
        在一个case分支中如果没有break,那么他会向下继续执行下一个case分支。
        可以利用case的穿透特性。


*/

/*
使用switch语句判断成绩在什么范围:
*/
//#include<stdio.h>
//#include<Windows.h>
//void main001() {
//    int score;
//    scanf_s("%d", &score);
//
//    switch (score/10) {
//    case 10:
//    case 9:
//        printf("优秀!    \n");
//        break;
//    case 8:
//    case 7:
//        printf("良好!    \n");
//        break;
//    case 6:
//        printf("及格!    \n");
//        break;
//    default:
//        printf("Error!    \n");
//        break;
//    }
//
//    system("Pause");
//}
//
//int main() {
//    for (int i = 0;i < 3;i++) {
//        main001();
//    }
//}


/*
if分支语句和switch分支语句的区别:
    if发分支语句:匹配一个范围,属于模糊匹配。
    switch分支语句:精确匹配。

*/

/*
while循环:
    
    while(条件判别表达式){
        循环体;
    }


do while 循环:
    无论如何先执行循环体一次,然后再判断是否继续循环。

    do{
        循环体;
    }while(条件判别表达式);
    

*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 1;
//    printf("请输入一个数:    \n");
//
//    while (a < 10) {
//        scanf_s("%d", &a);
//        printf("刚输入的数为:%d        \n", a);
//    }
//}

/*
练习:敲7:1-100数数,逢7的倍数,敲桌子。
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 0;
//    while (a++, a<100) {
//        /*if (a % 7 == 0 ) {
//            printf("敲桌子:%d    \n", a);
//        }
//        else if(a%10==7) {
//            printf("敲桌子:%d    \n", a);
//        }
//        else if (a / 10 == 7) {
//            printf("敲桌子:%d    \n", a);
//        }
//        else {
//            printf("%d    \n", a);
//        }*/
//        //------------------------------------
//
//        if (a % 7 == 0 || a % 10 == 7 || a / 10 == 7) {
//            printf("敲桌子:%d    \n", a);
//        }
//        else {
//            printf("%d    \n", a);
//        }
//
//        //------------------------------------
//    }
//    printf("\n");
//
//    system("Pause");
//}


/*
do while 循环demo
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 0;
//    do {
//        printf("a的值为:%d        \n", a);
//    } while (a++,a < 10);
//
//    system("Pause");
//}

/*
使用do while 循环求水仙花数(一个三位数,各个位上的数字的立方和等于本数字。)
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a=99;
//    printf("求水仙花数!\n\n\n\n\n");
//    int b=0;
//    int c=0;
//    int d=0;
//    int aaa;
//    do {
//        b = a % 10;
//        c = (a/10) % 10;
//        d = a / 100;
//        aaa = d * d*d + c * c*c + b * b*b;
//        if (a == aaa) {
//            printf("个位数为:%d    %d立方为:%d    \n", b, b, b*b*b);
//            printf("十位数为:%d    %d立方为:%d    \n", c, c, c*c*c);
//            printf("百位数为:%d    %d立方为:%d    \n", d, d, d*d*d);
//            
//            printf("    三个数的立方和为:---------------------%d    \n",d*d*d+c*c*c+b*b*b);
//            printf("              a的值为 :----------------------%d    \n",a);
//            printf("==================================================================\n\n\n");
//        }
//    } while (a++, a<1000 );
//}
  





/*
for循环:
    for(表达式1 ;表达式2 ;表达式3 ){
        循环体;
    }

    执行顺序:
        表达式1--->表达式2--->为真--->循环体--->表达式3
                --->表达式2--->为真--->循环体--->表达式3
                。。。。。。。。。
                --->表达式2--->为真--->循环体--->表达式3
                --->表达式2--->为假--->结束循环


    循环因子:
        定义在for之外,for循环结束,也能使用。
        定义在for之内,for循环结束,不能使用。


    for的三个表达式,均可变换 省略,但是分号不能省略。

*/

/*
使用for循环求1-100的和
*/
////基础for循环
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int sum = 0;
//    for (int i = 1;i <= 100;i++) {
//        sum += i;
//    }
//    printf("%d    \n", sum);
//
//    system("Pause");
//}




/*
猜数字游戏:
    1.生成一个随机数
        1).添加一个随机数种子。需要用到函数:srand(time(NULL));
        2).使用该函数需要添加两个头文件:    
            #include<stdlib.h> 
            #include<time.h>
        3).生成随机数:int n=rand() % 100 ; 调用该函数,该函数会返回一个随机数(该数较大,且正负数都有,模100之后值域为0-99)。
    2.循环输入数据猜。
        int num;
        while(1){
            接收用户输入的scanf("%d",&num);
            比较用户的数和随机生成数的大小。
            if(n>num)
            else{
            
            }
        }
    3.跳出循环
        break;跳出一重循环。


*/


//#include<stdio.h>
//#include<Windows.h>
//#include<stdlib.h>
//#include<time.h>
//int main() {
//    printf("随机生成了一个数字,请猜一猜这个数是多少:    \n");
//    srand(time(NULL));
//    //srand(100);//使用一个固定数生成的随机数也是固定的
//    int n = rand() % 100;
////    printf("%d    \n", n);
//    int num = 0;
//
//    while (1) {
//        scanf_s("%d", &num);
//        if (num==n) {
//            printf("Yes    !!!        \n");
//            break;
//        }
//        else if(num<n){
//            printf("猜小了!    \n");
//        }
//        else {
//            printf("猜大了!    \n");
//        }
//    
//    }
//
//    printf("随机生成的数字是:%d    \n", n);
//    system("Pause");
//    return 0;
//}


/*
break:
    作用一:跳出一重循环。for循环,while循环,do while循环。
    作用二:防止case穿透。switch循环。


嵌套循环:
    外层循环执行一次,内层循环执行一周。

    for (int i = 0;i < 10;i++) {
        for (int j = 0;j < 10;j++) {
            for (int k = 0;k < 10;k++) {
                循环体;
            }
        }
    }

*/

/*
练习:模拟电子表的打印:
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    for (int i = 0;i < 24;i++) {
//        for (int j = 0;j < 60;j++) {
//            for (int k = 0;k < 60;k++) {
//                printf("%02d:%02d:%02d        \n", i, j, k);
//                Sleep(2);
//                system("cls");
//            }
//        }
//    }
//}

/*
练习:打印9*9乘法表
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    for (int i = 1;i <= 9;i++) {
//        for (int j = 1;j <= i;j++) {
//            printf("%d*%d=%d    ", j, i, i*j);
//        }
//        printf("\n");
//    }
//}

/*
倒着打印乘法表
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    for (int i = 9;i > 0;i--) {
//        for (int j = 1;j <= i;j++) {
//            printf("%d*%d=%d    ", j, i, i*j);
//        }
//        printf("\n");
//    }
//}




/*
跳转语句:
break:
    作用一:跳出一重循环。for,while,do while
    作用二:防止case穿透,switch

    一个break只能跳出一重循环。


continue:
    作用:结束【本次】循环。continue关键字之后的循环体,在本次循环中不执行。


goto:【太灵活,用起来麻烦,了解即可。】
    使用步骤:(只在一个函数内生效,跳出一个函数就不生效了)
        1.设定一个标签。
        2.使用“goto 标签名”跳转到标签的位置。

*/

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    for (int i = 10;i--;) {
//        if (i % 2 == 0) {
//            continue;
//        }
//        printf("i=%d    \n", i);
//    }
//    system("Pause");
//}



//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int i = 10;
//    while (i--) {//括号内的(i--)相当于(i--!=0),两个方式写谁都可以。
//        if (i % 2 == 0) {
//            continue;
//        }
//        printf("i=%d    \n", i);
//    }
//    system("Pause");
//}



/*
goto语句的示例
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    for (int i = 0;i < 10;i++) {
//        if (i == 5) {
//            goto ABX234;
//        }
//        printf("i=%d", i);
//    }
//
//    ABX234:
//    for (int i = 0;i < 5;i++) {
//        printf("第二个 i=%d", i);
//    }
//}

/*
goto过于灵活,导致使用时可能出现安全隐患
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int i = 0;
//    int j = 2;
//    for (int i = 0;i < 10;i++) {
//        if (i == 5) {
//            goto ABX234;
//        }
//        printf("i=%d    \n", i);
//    }
//
//    for (j = 0;j < 5;j++) {
//    ABX234://直接跳过了该for循环的赋值
//        printf("*** j=%d    \n", j);
//    }
//}




/*
取值 取址的区别:
--------------------------------------------------------------------------------------------------------------------
5.1概述:
    
    
    数组:
        在程序设计中,为了方便处理数据把具有相同类型的若干变量按有序性形式组织起来,称为数组。----------------------------------------即:相同数据类型的有序连续存储
        数组就是在内存中连续的相同类型的变量空间。同一个数组所有成员都是相同的数据类型,同时所有的成员在内存中的地址是连续的。

        各元素的内存地址连续。
        数组名为地址,是数组首元素的地址。
        printf("数组大小:%u        \n",sizeof(arr) );
        printf("数组元素大小:%u        \n",sizeof(arr[0])    );
        printf("数组元素个数:%d        \n",sizeof(arr)/sizeof(arr[0])    );
        数组第一个元素下标为0;
        printf("数组最后一个元素下标:%d        \n",sizeof(arr)/sizeof(arr[0])-1    );




*/

//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 1, b = 2, c = 5;
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,55 };
//
//    printf("&arr[0] = %x    \n", &arr[0]);
//    printf("&arr[1] = %x    \n", &arr[1]);
//    printf("&arr[2] = %x    \n", &arr[2]);
//    printf("&arr[3] = %p    \n", &arr[3]);
//    printf("&arr[4] = %p    \n", &arr[4]);
//    printf("&arr[5] = %p    \n", &arr[5]);
//
//    printf("    \n");
//    
//    printf("a=%p    \n", &a);//int在windows之中可以通过看连续的变量定义的地址之间的差值 判断每个元素占用的内存的大小。
//    printf("b=%p    \n", &b);
//    printf("c=%p    \n", &c);
//
//    system("Pause");
//}



/*
求:数组大小,数组元素个数,数组大小 的方法:
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int a = 1, b = 2, c = 5;
//    int arr[12] = { 1,2,3,4,5,6,7,8,9,55 };
//
//    printf("sizeof(&arr ):%d    \n", sizeof(arr));
//    printf("sizeof(&arr[0] ):%d    \n", sizeof(arr[0]));
//    printf("arr[]元素个数:%d    \n", sizeof(arr)/sizeof(arr[0]));
//    
//    printf("    \n");
//    
//    printf("sizeof(a):%d    \n", sizeof(a));
//
//    system("Pause");
//}



/*
数组的初始化以及打印各个元素:
    数组初始化:
        int arr[12]={1,2,3,4,5,6,7,8,9,10,11,12};
        int arr[12]={1,2,3,4,5};//剩余未初始化的元素,默认值为0;
        int arr[12]={0};//初始化一个全为0的数组;
        int arr[12];//初始化随机数的数组;
        int arr[]={1,2,3,4,5,6};//操作系统(编译器)会自动转为int arr[6]={1,2,3,4,5,6};
        int arr[]={0};//只有一个元素的数组,数组元素的值为0;

        int arr[10];    arr[0]=1;    arr[1]=5;//除了0,1号元素其余为随机数;

*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int arr[15] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//    //int arr[12] = { 1,2,3,4,5 };
//    //int arr[12] = { 0 };
//    //int arr[12];
//    //int arr[] = { 1,2,3,4,5,6 };
//    //int arr[] = { 0 };
//
//    int n = sizeof(arr) / sizeof(arr[0]);
//    for (int i = 0;i < n;i++) {
//        printf("arr[%d]=%d    \n", i, arr[i]);
//    }
//
//    printf("\n\n\n");
//    return 0;
//}


/*
练习:逆序输出数组:
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int arr[15] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//
//    int m = sizeof(arr) / sizeof(arr[0]);
//    for (int i = m-1;i >=0 ;i--) {
//        printf("arr[%d]=%d    \n", i, arr[i]);
//    }
//}


//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    //main00();
//
//    int arr[15] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//
//    int flag = sizeof(arr) / sizeof(arr[0]);
//
//    int n = 0;
//    int m = flag-1;
//    int temp = 0;
//
//    for (int i = 0;i < flag;i++) {
//        printf("arr[%d]=%d  ", i, arr[i]);
//    }
//    printf("\n");
//
//    printf("元素倒叙输出_首末元素位置转换开始:************************    \n");
//    for ( ;n<m ;n++,m--) {
//        temp = arr[n];
//        arr[n] = arr[m];
//        arr[m] = temp;
//    }
//        
//    for (int i = 0;i < flag;i++) {
//        printf("arr[%d]=%d  ", i, arr[i]);
//    }
//    printf("\n");
//}



/*
冒泡排序:        一般双层循环,外层控制行,内层控制列

    int ***[] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
    int n = sizeof(***) / sizeof(***[0]);
    int temp = 0;    //临时变量
    //完成乱序数组的冒泡排序
    for (int i = 0;i < n - 1;i++) {//外层控制行
        for (int j = 0;j < n - i - 1;j++) {//内层控制列
            if (***[j] > ***[j + 1]) {//满足条件 三杯水交换
                temp = ***[j];
                ***[j] = ***[j + 1];
                ***[j + 1] = temp;
            }
        }
    }


*/


/*
-----------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------
冒泡排序练习:
-----------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int arr[10] = { 5,6,8,4,0,3,5,5,4,10 };
//    int n = sizeof(arr) / sizeof(arr[0]);
//
//    for (int i = 0;i < n;i++) {
//        printf("%d  ", arr[i]);
//    }
//    printf("\n");
//
//    int temp = 0;
//    for (int i = 0;i < n - 1;i++) {
//        for (int j = 0;j < n - 1 - i;j++) {
//            if (arr[j] > arr[j + 1]) {
//                temp = arr[j];
//                arr[j] = arr[j + 1];
//                arr[j + 1] = temp;
//            }
//        }
//    }
//
//    for (int i = 0;i < n;i++) {
//        printf("%d  ", arr[i]);
//    }
//    printf("\n");
//}


/*
冒泡排序:
for (i = 0; i < n - 1; ++i)  //比较n-1轮
{
    for (j = 0; j < n - 1 - i; ++j)  //每轮比较n-1-i次,
    {
        if (a[j] < a[j + 1]) {
            buf = a[j];
            a[j] = a[j + 1];
            a[j + 1] = buf;
        }
    }
}
*/




/*
二维数组:
    定义语法:
        int arr[2][3]={    {2,5,8},{7,9,10}    };
    打印:
        for(int i=0;i<行;i++){
            for(int j=0;j<列;j++){
                printf("%d\t",arr[i][j]);
            }
            printf("\n"); 
        }
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int arr[2][3] = { {2,5,8},{7,9,10} };
//    for (int i = 0;i < 2;i++) {
//        for (int j = 0;j < 3;j++) {
//            printf("%d\t", arr[i][j]);
//        }
//        printf("\n");
//    }
//    
//    system("Pause");
//}


/*
int arr[2][3] = { {2,5,8},{7,9,10} };

大小:
    int arr[2][3] = { {2,5,8},{7,9,10} };
    
    printf("数组的大小:%d    \n",sizeof(arr) );
    printf("一行的大小:%d    \n", sizeof(arr[0]));//二维数组的一行,就是一个一维数组。
    printf("一个元素的大小:%d    \n",sizeof(arr[0][0]) );
    row =    printf("行数:%d    \n",sizeof(arr)/sizeof(arr[0]) );
    col =    printf("列数:%d    \n",sizeof(arr[0])/sizeof(arr[0][0]) );

地址合一:
    printf("%p\n", arr);//数组的首地址
    printf("%p\n", &arr[0][0]);//数组的首元素地址
    printf("%p\n", arr[0]);//数组首行地址
    三地址合一:
    数组首地址==数组的首元素地址==数组的首行地址
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int arr[2][3] = { {2,5,8},{7,9,10} };
//    
//    printf("数组的大小:%d    \n",sizeof(arr) );
//    printf("一行的大小:%d    \n", sizeof(arr[0]));//二维数组的一行,就是一个一维数组。
//    printf("一个元素的大小:%d    \n",sizeof(arr[0][0]) );
//    printf("行数:%d    \n",sizeof(arr)/sizeof(arr[0]) );
//    printf("列数:%d    \n",sizeof(arr[0])/sizeof(arr[0][0]) );
//
//    //地址合一:
//    printf("%p\n", arr);//数组的首地址
//    printf("%p\n", &arr[0][0]);//数组首元素地址
//    printf("%p\n", arr[0]);//数组首行地址
//    
//    system("Pause");
//
//    int i = 10;
//    int arr1[10] = { 0 };
//    int flag = sizeof(arr1) / sizeof(arr1[0]);
//    for (int j = 0; j < flag; j++) {
//        printf("%d ", arr1[j]);
//    }
//    printf("\n ");
//}



/*
二维数组的初始化:
    1.常规初始化:
        int arr[3][5]={  {2,3,45,56,7} , {2,67,4,35,9} , {1,4,16,3,78}  };
    2.不完全初始化:
        int arr[3][5]={  {2,3,45} , {2,67,4} , {1,4,16,3,78}  };    //未被初始化的数值为0
        int arr[3][5]={0};        //初始化一个值全部为0的二维数组
        int arr[3][5]={2,3,2,67,4,1,4,16,78};//少见 系统自动分配行列
    3.不完全指定行列初始化:
        int arr[][2]={1,3,4,6,7};//二维数组定义可以不指定行,但是必须指定列

         
*/

/*
练习:
    求出5名学生3门功课的总成绩。(一个学生的总成绩,一门功课的总成绩)
*/
//#include<stdio.h>
//#include<Windows.h>
//int main() {
//    int scores[5][3];
//
//    int row = sizeof(scores) / sizeof(scores[0]);//求出该二维数组共有几行
//    int col = sizeof(scores[0]) / sizeof(scores[0][0]);//求出该二维数组共有几列
//
//    for (int i = 0; i < row; i++) {
//        for (int j = 0; j < col; j++) {
//    //        printf("请输入第%d个学生的第%d门成绩:", i+1, j+1);
//            scanf_s("%d", &scores[i][j],1);
//        }
//    //    printf("\n");
//    }
//
//    ////求一个学生总成绩
//    printf("求一个学生总成绩\n");
//    for (int i = 0; i < row; i++) {
//        int sum = 0;
//        for (int j = 0; j < col; j++) {
//            sum += scores[i][j];
//        }
//        printf("第%d名学生的总成绩为%d。\n", i + 1, sum);
//    }
//
//    ////求一门功课的总成绩
//    printf("求一门功课的总成绩\n");
//    for (int j = 0; j < col; j++) {
//        int sum = 0;
//        for (int i = 0; i < row; i++) {
//            sum += scores[i][j];
//        }
//        printf("第%d门功课的总成绩为%d。\n", j + 1, sum);
//    }
//
//
//    ////打印全部学生成绩
//    printf("打印全部学生成绩\n");
//    for (int i = 0; i < row; i++) {
//        for (int j = 0; j < col; j++) {
//            printf("%d\t", scores[i][j]);
//        }
//        printf("\n");
//    }
//}







/*
快捷导入代码:

    代码片段管理器:
    Visual--->工具--->代码片段管理器

已完成快读导入代码设置:#3
*/



/*
多维数组:
    三维数组:[层][行][列]
    数组类型: 数组名[层][行][列]
    int arr[2][2][4];
    {                                //层
        {                    //第零层
            {1,2,3,4},        
            {1,2,3,4}    
        },    
        {                    //第一层
            {1,2,3,4},
            {1,2,3,4}    
        }    
    }

    写法:以下两种写法均可。
    int a[2][2][3] = {  {   {1,2,3},{4,5,6}   },{   {7,8,9},{2,2,2}   }   };
    int a[2][2][3] = {  1,2,3,4,5,6,7,8,9,2,2,2  };

*/




//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
//int main() {
////    int a[2][2][3] = {  {   {1,2,3},{4,5,6}   },{   {7,8,9},{2,2,2}   }   };
//    int a[2][2][3] = {  1,2,3,4,5,6,7,8,9,2,2,2  };
//
//    printf("打印三维数组:\n");
//    for (int i = 0; i < 2; i++) {
//        for (int j = 0; j < 2; j++) {
//            for (int k = 0; k < 3; k++) {
//                printf("%d\t", a[i][j][k]);
//            }
//            printf("\n");
//        }
//        printf("\n");
//        printf("\n");
//    }
//    return 0;
//}



/*
字符数组 和 字符串区别
    字符数组:
        char str[5] = { 'h','e','l','l','o' };
    字符串://字符串必须有\0结束标记
        char str[6] = { 'h','e','l','l','o','\0' };
        char str[] = "hello";
        printf("%s");使用printf打印字符串的时候,必须碰到\0结束。

*/

//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
//int main() {
//
//    char str[50] = { 0 };
//    int flag = sizeof(str) / sizeof(str[0]);
//    //scanf_s("%s", str,50);
//    for (int i = 0; i < flag; i++) {
//        scanf_s("%c", &str[i]);
//    }
//    
//    Sleep(1);
//
//    //printf("%s", str);
//    for (int i = 0; i < flag; i++) {
//        printf("%c", str[i]);
//    }
//
//    system("Pause");
//    return 0;
//}

/*        
    练习:键盘输入字符串,存至str[]中,统计每个字母出现次数。
*/

//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
//int main() {
//    char str[50] = { 0 };
//    char az[26] = { 0 };
//    //for (int i = 0; i < 50; i++) {
//    //    if (i==51) {
//    //        //rewind(stdin);
//    //        break;
//    //    }
//    //    scanf_s("%c", &str[i]);
//    //}
//    scanf_s("%[^\n]s", str,49);
//
//    printf("输入的字符串为:\n");
//    for (int i = 0; i < 50; i++) {
//        printf("%c",str[i]);
//    }
//    printf("\n");
//
//    int flag = 0;
//    //遍历后记录每个元素出现次数
//    for (int i = 0; i < 50; i++) {
//        if (str[i]!=0) {
//            flag = str[i] - 'a';
//            az[flag]++;
//        }
//    }
//
//    for (int i = 0; i < 26; i++) {
//        if (az[i]!=0) {
//            printf("%c在整个字符串中出现了%d次    \n", i + 'a', az[i]);
//        }
//    }
//    return 0;
//}


/*
字符串获取:
    scanf_s("%c",&a);
    注意:
        1.用于存储字符串的空间必须足够大,防止溢出。char str[5];
        2.获取字符串 %s 遇到空格 和 \n终止。
    借助“正则表达式”获取带有空格的字符串。scanf("%[^\n]s",str);        //[^\n]尖括号表示 除了\n之外的所有。该正则表达式表示除了\n之外的所有字符都可输入,完成了过滤空格。

字符串操作函数:
    gets;(现在该函数更名为:gets_s)获取一个字符串,返回字符串首地址。可以获取带有空格的字符串。
        char *gets(char *c);
            参数:用来存储字符串空间。
            返回值:返回实际获取到的字符串首地址。
        gets(str)与scanf("%s",str)的区别:        //由于scanf和gets都无法知道字符串s的大小,必须遇到换行符或者读到文件结尾为止才接收输入,因此容易导致字符数组越界(缓冲区溢出)的情况。
            gets(str)允许输入的字符串含有空格。
            scanf("%s",str)不允许含有空格。

    fgets;从stdin获取一个字符串,预留\0的存储空间。空间足够读取\n,空间不足舍弃\n。【安全】
        char *fgets(char *s,int size,FILE *stream);
            参一:用来存储字符串的空间地址
            参二:描述空间大小
            参三:读取字符串位置。标准输入:键盘--》stdin(从键盘读取的标准输入)    //参三可以是文件(即 不从键盘读取输入,从文件读取)
            返回值:返回实际获取字符串的首地址

    puts;将一个字符串写出到屏幕。printf("%s\n","hello");/printf("hello\n");/puts("hello");该函数输出字符串后会自动添加\n换行符
        int puts(const char *s);
            参一:待写出到屏幕的字符串。
            返回值:成功(返回非负数)失败(返回 -1);                //一般成功返回0,失败返回-1;

    fputs;将一个字符串写出到stdout 输出字符串后不添加换行符
        int fputs(const char * str,FILE * stream);
            参一:待写出到屏幕的字符串。        屏幕————》标准输出:stdout
            参数:写出到的位置 stdout
            返回值:成功(返回非负数)失败(返回 -1);                //一般成功返回0,失败返回-1;

    strlen;获取字符串的有效长度,不包含\0,碰到\0结束。
        size_t strlen(const char *s);
            参一:代求长度的字符串
            返回:有效字符个数

字符追加:

*/

//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
////#include<string.h>
//int main() {
//    char str[] = "hello world";
//    char str1[] = "hello \0 world";
//    
//    //printf("%s\n", gets_s(str));
//    //printf("%s\n", fgets(str, sizeof(str), stdin));
//    
//    puts(str);
//    puts("hello world");
//
//    fputs(str, stdout);
//    fputs("\n", stdout);
//    fputs("hello world", stdout);
//    fputs("\n", stdout);
//
//    printf("sizeof(str)=%d    \n", sizeof(str));
//    printf("strlen(str)=%d    \n", strlen(str));
//    
//    printf("sizeof(str1)=%d    \n", sizeof(str1));
//    printf("strlen(str1)=%d    \n", strlen(str1));
//
//    system("Pause");
//    return 0;
//}



/*
练习:
    实现strlen函数:传入一个字符串首地址,返回一个int类型数字,表示该字符串的有效长度不包括\0
*/

//int strlen123(char *a) {
//    int i = 0;
//    while (a[i]!='\0') {
//        i++;
//    }
//    return i;
//}
//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
//int main() {
//    char str[] = "hello world";
//    char str1[] = "hello \0 world";
//
//    printf("%d    \n", strlen123(str) );
//    printf("%d    \n", strlen123(str1) );
//
//    return 0;
//}



/*
字符串拼接:
    
*/
//int splice(char *aaa, char *b, char *c) {
//    int i = 0, j = 0;
//    while (b[i]!=0) {
//        aaa[i] = b[i];
//        i++;
//    }
//
//    aaa[i] = '+';
//    i++;
//
//    while (c[j]!=0) {
//        aaa[i + j ] = c[j];
//        j++;
//    }
//    aaa[i + j ] = 0;
//
//    return 0;
//}
//
//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
//int main() {
//    char str[] = "hello";
//    char str1[] = "world";
//    char str100[100] ;
//    
//    splice(str100, str, str1);
//    fputs(str100, stdout);
//
//    return 0;
//}




/*
函数的作用:
        1.提高代码复用率
        2.提高程序的模块化组织性

    函数分类:
        系统库函数:标准c库 libc
            1.引入头文件---声明函数
            2.根据函数原型调用
        用户自定义:
            除了需要提供函数原型外,还需要提供函数实现。

    随机数:
        1.播种随机数种子:srand(time(NULL));
        2.引入头文件#include<stdlib.h> <time.h>
        3.生成随机数:rand()%100;

    函数定义:
        包含 函数原型(返回值类型,函数名,形参列表) 和 函数体(大括号一对,具体代码实现)
        形参列表:形式参数列表,一定包含 类型名 形参名。
        int add(int a,int b,int c){
            return a+b+c;
        }

    函数调用:
        包含 函数名(实参列表);
        int ret = add(10,4,28);

        实参(实际参数):在调用时,传参必须严格按照形参填充。(参数的 个数 类型 顺序)没有类型描述符

    函数声明:
        包含 函数原型(返回值类型,函数名,形参列表)+“;”
        要求在函数调用之前,编译必须见过函数定义。否则,需要函数声明。

        隐式声明:【不要依赖】
            默认编译器做隐式声明函数时,返回值都是int ,根据调用语句补全函数名和形参列表。

        #include<xxx.h>----->包含有函数的声明    

    exit函数:    //该函数头文件为:#include<stdlib.h>
        return:返回当前函数调用,将返回值返回给调用者。
        exit()函数:退出整个当前程序。

        在main函数中调用exit和return结果是一样的,
        但在子函数中调用return只是代表子函数终止了,
        在子函数中调用exit,那么程序终止。

    多文件编程:
        <>包裹的头文件为系统库头文件
        ""英文的双引号 引起来的为用户自定义头文件

        将多个含有不同函数功能的.c文件模块,编译到一起,生成一个.exe文件。

        防止头文件重复包含:    头文件守卫
            1.#pragma once-----windows中
            2.    #ifndef _HEAD_H_        《--大家默认的书写规范:__头文件名_h__    含义为:如果没有定义则为真
                #define _HEAD_H_                                                  含义为:定义该宏                
                ....
                头文件内容                                                    里面写入 头文件内容
                //include 头文件
                //函数声明
                //类型定义
                //宏定义
                ....
                #endif                                                              含义为:结束该if                
*/

/*
写一个冒泡排序的函数,并通过主函数调用。
*/
//#include<stdio.h>
//#include<stdlib.h>
//#include<string.h>
//#include<Windows.h>
//#include<math.h>
//#include<time.h>
//
//int bubble_sort(int arr[],int len) {
//    int temp = 0;
//    for (int i = 0; i < len-1; i++) {
//        for (int j = 0; j < len-i-1; j++) {
//            if (arr[j] > arr[j + 1]) {
//                temp = arr[j];
//                arr[j] = arr[j + 1];
//                arr[j + 1] = temp;
//            } 
//        }
//    }
//    return 0;
//}
//
//int main() {
//    int arr[] = { 2,3,45,56,7 ,2,67,4,35,9 , 1,4,16,3,78 };
//    int len = sizeof(arr) / sizeof(arr[0]);
//    printf("len:    %d \n", len);
//
//    printf("返回值为:%d \n", bubble_sort(arr,len) );
//
//    int flag = sizeof(arr) / sizeof(arr[0]);
//    for (int i = 0; i < flag; i++) {
//        printf("%d ", arr[i]);
//    }
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

/*
写在一个文件内的冒泡排序 整理后得到下面
*/

//#include "head.h"
//
//int main() {
//    int arr[] = { 2,3,45,56,7 ,2,67,4,35,9 , 1,4,16,3,78 };
//    int len = sizeof(arr) / sizeof(arr[0]);
//    printf("len:    %d \n", len);
//
//    printf("返回值为:%d \n", bubble_sort(arr,len) );
//
//    int flag = sizeof(arr) / sizeof(arr[0]);
//    for (int i = 0; i < flag; i++) {
//        printf("%d ", arr[i]);
//    }
//
//    //exit(EXIT_SUCCESS);
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------
*/



/*
指针和内存单元:

    指针:地址。
    内存单元:    计算机中内存最小的存储单位---内存单元。大小一个字节。
                每一个内存单元都有一个唯一的编号。我们称这个内存单元的编号为“地址”。
    指针变量:存地址的变量。


指针定义和使用:    *取值    &取址
    int a=10;        //整型变量a
    int *p=&a;        //整形指针p            int* p;            int *p;            int * p;都是正确的;
    *p=250;            //通过指针访问数据。指针的解引用。间接引用。

    int a,*b,*c,d;    //此种定义方式可以,即:定义了两个整型变量,两个整形指针变量。

    int a =10;
    int b=2;
    int *p=&a;        //此时的*叫类型描述符
    *p==&b;            //此时的*叫解引用运算符(间接引用运算符)
    int x=a*b;        //此时的*叫做乘号

    ***********************************************************************************            
    *******        *p:将p变量的内容取出,当成地址看待,找到该地址对应的内存空间。    *******            
    *******            如果做左值:存数据到空间中。                                *******            
    *******            如果做右值:取出空间中的内容。                                *******            
    ***********************************************************************************
    任意“指针”类型大小
        指针的大小与类型无关。只与当前使用的平台架构有关。    32位:4字节。        64位:8字节。


野指针:
    1.没有一个有效的地址空间的指针。
            int *p;            //Linux下面不会报错(即 指针指向了一块随即的空间) 
                            windows下的visual studio会帮助检查,报:使用了未定义的变量。
            *p=2000;
    2.p变量有一个值,但该值不是可访问的内存区域。
            int *p=10;        //0-255是留给操作系统使用的            //此种方式赋值易出错
            *p=2000;
    【杜绝使用野指针】


空指针:
    int *p=NULL;        #define NULL ((void *)0)        //该种方式很好的屏蔽掉了,*p是一个随机的地址,访问到不该访问的内容。
    *p时p所对应的存储空间一定是一个无效的访问区域。100%出错!
    *****写程序一般要养成好习惯,不用的时候要把指针置空!!!*****


万能指针/泛型指针(void *):                (int *)1000;//强制类型转换为int类型的指针。
    可以接收任意一种变量地址。但是,在使用必须借助“强转”具体化数据类型,才可以使用。
        char ch='R';
        void *p;//泛型指针
        p=&ch;
        printf("%c    \n",*(char *)p);//使用时要把泛型指针转化为对应类型的指针


const关键字:
    修饰变量:
        该变量为常量,不能被修改;
    修饰指针:
        const int *p;
            可以修改p;
            不可以修改*p;
        int const *p;
            同上;
        int * const p;
            可以修改*p;
            不可以修改p;
        const int * const p;
            不可以修改p;
            不可以修改*p;
        总结:const向右修饰,被修饰部分即为只读。
        常用:在函数形参内,用来限制指针所对应的内存空间为只读。


指针和数组:
    数组名:     ++ -- += -= %= /=   //带有副作用的运算符,运算之后变量值会改变;    int a=10;a+5;//此运算后a的值不会改变
        【数组名是地址常量】---不可以被赋值;
        指针是变量,可以用数组名给指针赋值。
    取数组元素:     //加上后面指针++的方式 共有五种操作数组的方式。
        int arr[6]={1,2,3,4,5,6};
        int *p=arr;
        for(int i=0;i<6;i++){
            //共这四种方式:
            //    arr[i]==*(arr+i)==p[i]==*(p+i)
            printf("%d",arr[i]);    
        }
    指针和数组的区别:
        1.指针是变量,数组名为常量
        2.    sizeof(指针)===>4/8取决于取决于平台架构
            sizeof(数组)===>数组的实际字节数
    指针++操作数组:
            int arr[]={1,2,3,4,5,4,4,4};
            int *p=arr;
            for (int i = 0; i < flag; i++) {
                printf("%d    ", *(p++));        //p++一次加一个int的大小,一个元素。
            }
            p的值会随着循环不断变化。打印结束后,p指向了一块无效的地址空间(野指针)。

指针加减运算:
    数据类型对指针的作用:
        1.间接引用:
            决定了从指针存储的地址开始,向后读取的字节数。(与指针本身存储空间无关)
        2.加减运算:
            决定了指针进行+1/-1操作向后加的字节数。
            即:
                int *p;
                p+1;//表示p加上一个int的字节数
    指针* / %:
        Error!!!
    指针+-整数:
        1.普通指针变量+-整数
            char    *p; 打印p,p+1偏过1字节(偏过一个元素)
            short    *p; 打印p,p+1偏过2字节(偏过一个元素)
            int        *p; 打印p,p+1偏过4字节(偏过一个元素)
        2.在数组中+-整数
            int arr[]={1,2,3,4,5};
            int *p=arr;
            p+3;    //向右(后)偏过三个元素
            p-2;    //向左(前)偏过两个元素
        3.&数组名+1
            加过一个数组的大小( 数组元素个数 乘 sizeof(数组元素类型) )

    指针+-指针:
        指针 + 指针:Error!!!
        指针 - 指针:
            1.普通变量来说,没有实际意义
            2.数组来说,偏移过的元素个数。
        
*/


/*
区分定义的数据类型:(判断是不是指针类型)
    int arr[];    //该数据类型为:int[],因为定义变量 变量名只能使用:字母,数字,下划线 []不是这个范围内的字符,所以除去arr之外的全部都是类型int []。

    int a=0;    //除去变量名a之外的 就是类型

    int double short 等是基础类型。
    int *  int []    等是复合类型。由基础类型和符号组合成的。
*/


//#include "head.h"
//
//int main() {
//    int arr[] = { 2,3,45,56,7 ,2,67,4,35,9 , 1,4,16,3,78 };
//    int len = sizeof(arr) / sizeof(arr[0]);
//    printf("len:    %d \n", len);
//
//    printf("返回值为:%d \n", bubble_sort(arr,len) );
//
//    int flag = sizeof(arr) / sizeof(arr[0]);
//    print_arr(arr, flag);
//
//    //exit(EXIT_SUCCESS);
//    system("Pause");
//    return EXIT_SUCCESS;
//}

//#include"head.h"
//int main() {
//    int a = 10;
//    int *p = &a;
//
//    *p = 20;//通过地址对变量进行操作        解引用方式
//    printf("%d    \n", a);//变量方式读
//    printf("%d    \n", *p);//解引用方式读
//
//    a = 30;//通过变量的方式操作
//    printf("%d    \n", a);
//    printf("%d    \n", *p);
//
//    //指针无关乎类型,大小和操作系统有关。
//    printf("int *=%u    \n", sizeof(int *));
//    printf("short *=%u    \n", sizeof(short *));
//    printf("double *=%u    \n", sizeof(double *));
//    printf("float *=%u    \n", sizeof(float *));
//
//    printf("void *=%u    \n", sizeof(void *));
//
//    system("Pause");
//    return 0;
//}



//#include"head.h"
//int main() {
//    
//    //int *p = (int *)888000;
//    //*p = 888000;
//    //printf("*p=%d\n", *p);
//
//    //int *p = NULL;//NULL可以理解为等于0;
//    //*p = 80000;//会报访问权限冲突
//    //printf("*p=%d\n", *p);
//
//    //int *p = NULL;
//    ////...
//    ////n多代码
//    ////...
//    //if (p!=NULL) {    //进行判空,不进行的话 可能引起空指针异常
//    //    *p = 80000;
//    //    printf("*p=%d\n", *p);
//    //}
//
//    //int *p = NULL;
//    ////...
//    ////n多代码
//    ////...
//    //int a = 0;p = &a;
//    //if (p != NULL) {
//    //    *p = 80000;
//    //    printf("*p=%d\n", *p);
//    //}
//
//    int a = 9;
//    void *p;//万能指针,泛型指针
//    p = &a;
//    printf("%d    \n", *(int *) p);//强转为int类型的指针,然后解引用
//    char ch = 'R';
//    p = &ch;
//    printf("%c    \n", *(char *) p);//强转为char类型的指针,然后解引用
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
const给常量赋值
*/
//#include"head.h"
//int main() {
//    const int a[] = { 10 ,2,3,5,6};
//    int *p = a;//该赋值方式 现在不被允许 报错!!!
//    *p = 256;
//    printf("%d", a);
//
//    system("Pause");
//    return 0;
//}

/*
const给变量赋值
*/
//#include"head.h"
//int main() {
//    int a = 1;
//    int b = 2;
//
//    //const int *p = &a;
//    int const *p = &a;
//    //不可修改*p
//    //*p = 10;
//    //但是除了被const修饰过的*p以外,其他可以修改被指针p指向的内存空间的值
//    a = 10;
//    printf("%d    \n", a);
//    printf("%d    \n", *p);
//    //可修改p
//    p = &b;
//    printf("%d    \n", *p);
//    
//    printf("---------\n");
//    printf("---------\n");
//    printf("---------\n");
//    printf("a:%d    b:%d    \n",a,b);
//    printf("---------\n");
//    
//    int *const p1 = &a;
//    //不可修改 p1
//    //p1 = &b;
//    //可修改*p
//    *p1 = 111;
//    printf("%d    \n", *p1);
//
//    printf("---------\n");
//    printf("---------\n");
//    printf("---------\n");
//    printf("a:%d    b:%d    \n",a,b);
//    printf("---------\n");
//
//    const int *const p2 = &a;
//    //不可修改p2
//    //p2 = b;
//    //不可修改*p2
//    //*p2 = 20;
//
//    system("Pause");
//    return 0;
//}





//#include"head.h"
//
//int print_array(int *p, int flag) {
//
//    for (int i = 0; i < flag; i++) {
//        printf("%d \t", *(p + i));
//    }
//    printf("\n");
//    return 0;
//}
////int print_array(double *p, int flag) {
////
////    for (int i = 0; i < flag; i++) {
////        printf("%lf \t", *(p + i));
////
////    }
////    printf("\n");
////    return 0;
////}
//
//int print_array(double *p, int flag) {
//    
//    for (int i = 0; i < flag; i++) {
//        printf("%lf \t", *(p + i));
//    }
//    printf("\n");
//    return 0;
//}
//
//int main() {
//    int a[10] = {0,1,2,3,4,5,6,7,8,9};
//    double b[10] = { 0.0 };
//
//    //print_array(a, 10);
//    //print_array(b, 10);
//
//    for (int i = 0; i < 10; i++) {
//        //【重要!!!】     a[i] 等价于 *(a+i)        !!!!!!!!!!!!!!!!!!!!!!!
//        //【重要!!!】     a[i] 等价于 *(a+i)        !!!!!!!!!!!!!!!!!!!!!!!
//        //【重要!!!】     a[i] 等价于 *(a+i)        !!!!!!!!!!!!!!!!!!!!!!!
//        printf("%d \t", a[i]);
//    }
//
//    printf("\n");
//
//    for (int i = 0; i < 10; i++) {
//        printf("%d \t", *(a + i));
//    }
//        
//    printf("\n");
//
//    int *pp = a;
//    for (int i = 0; i < 10; i++) {
//        printf("%d \t", *(pp + i));
//    }
//
//    printf("\n");
//
//    for (int i = 0; i < 10; i++) {
//        printf("%d \t", *((char *)a + i));
//    }
//        
//    printf("\n");
//
//    for (int i = 0; i < 10; i++) {
//        printf("%d \t", *((double *)a + i));//证明了:什么类型的指针+1,代表加了该指针类型的长度。
//    }
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
指针和数组的区别
*/
//#include"head.h"
//int main() {
//    int arr[] = { 1,2,3,4,5,6,7,8,9 }; 
//    int arr1[] = { 1,2,3,4,5 };
//    int *p = arr;//指针为变量,可以把常量的值赋给变量。
//    //arr = arr1;//禁止该操作,数组名为常量,禁止赋值。
//
//    printf("sizeof(arr)=%u        \n", sizeof(arr));
//    printf("sizeof(p)=%u        \n", sizeof(p));
//    //sizeof求数组和指针的大小,得出的值分别为数组的实际字节数和指针的大小(4或8)
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
指针++操作数组:
*/

//#include"head.h"
//int main() {
//    int arr[] = { 1,2,3,4,5,6,7,8,9 }; 
//    int flag = sizeof(arr) / sizeof(arr[0]);
//
//    int *p = arr;
//
//    //不改变p本身的值
//    for (int i = 0; i < flag; i++) {
//        printf("%d    ", *(p+i));
//    }
//
//    printf("\n\n");
//
//    //改变了p的值
//    for (int i = 0; i < flag; i++) {
//        //p=p+1;一次加过一个int大小。一个元素。
//        printf("%d    ", *(p++));
//    }
//    //printf("%d    ", *(p++));//该指针已变为野指针
//
//    printf("\n\n");
//
//
//    //通过指针求元素个数!!!
//    //两个指针相减 得到的是元素个数
//    int len = p - arr;
//    printf("通过指针求元素个数:%d    \n", len);
//    //通过指针求元素个数!!!
//
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

/*
练习:
    写一个数组,通过*(arr+i)的方式输入值
    再分别使用 *p和 p++的方式打印值
*/
//#include"head.h"
//#define MAX 10
//int main() {
//    int arr[MAX];
////    printf("%d    \n", sizeof(arr[0]));
//    int *p = arr;
//
//    for (int i = 0; i < MAX; i++) {
//        scanf_s("%d", &arr[i], 1);
//    }
//
//    printf("\n\n");
//    printf("\n\n");
//
//    for (int i = 0; i < MAX; i++) {
//        printf("%d    ", *(p + i));
//    }
//
//    printf("\n\n");
//    printf("\n\n");
//
//    for (int i = 0; i < MAX; i++) {
//        printf("%d    ", *(p++));
//    }
//    
//    printf("\n\n");
//    printf("\n\n");
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}




/*
数据类型对指针的作用
    间接引用
*/
/*
指针+1操作的特性:
    加一操作
*/
//#include"head.h"
//int main() {
//    int a = 0x12345678;
//
//    int *p = &a;//加过一个指针类型的长度
//    printf("%p    \n", *p);
//    printf("%p    \n", p);
//    printf("%p    \n", p+1);
//
//    printf("\n    \n");
//
//    char *p1 = (char *)&a;
//    printf("%p    \n", *p1);
//    printf("%p    \n", p1);
//    printf("%p    \n", p1+1);
//
//    printf("\n    \n");
//
//    short *p2 = (short *)&a;
//    printf("%p    \n", *p2);
//    printf("%p    \n", p2);
//    printf("%p    \n", p2+1);
//
//    printf("\n    \n");
//
//    long long *p3 = (long long *)&a;
//    printf("%p    \n", *p3);
//    printf("%p    \n", p3);
//    printf("%p    \n", p3+1);
//
//    printf("\n    \n");
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

/*
指针算术运算:
*/
//#include"head.h"
//int main() {
//    int a = 10;
//
//    int *p = &a;
//    //乘除取余都会报错
//    printf("%p    \n", p * 2);
//    printf("%p    \n", p / 2);
//    printf("%p    \n", p % 2);
//    //加减不会报错
//    printf("%p    \n", p + 2);
//    printf("%p    \n", p - 2);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}



/*
指针在数组中+-整数(加减几,代表前后偏几个元素)
    给指针赋值时,不一定要赋值首元素。
*/

//#include"head.h"
//int main() {
//    int arr[] = { 1,2,3,4,5,6,7,8,9 }; 
//
//    int *p = &arr[5];
//
//    printf("%d    ", *(p - 2));
//    printf("%p    ", p - 2);// 使用指针方式找到了4的地址
//
//    printf("%d    ", arr[3]); 
//    printf("%p    ", &arr[3]);// 使用数组方式找到了4的地址
//    printf("\n");
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
&数组名+1
*/
//#include"head.h"
//int main() {
//    //int arr[] = { 0,1,2,3,4,5,6,7,8,9 }; 
//    short arr[] = { 0,1,2,3,4,5,6,7,8,9 }; 
//
//    printf("%p    ", arr);
//    printf("%p    ", &arr[0]);
//
//    printf("%p    ", arr + 1);
//
//    printf("%p    ", &arr);
//    printf("%p    ", &arr+1);
//    //取数组地址后再加1,为加过一个数组的大小(数组元素个数 乘 sizeof(数组元素类型))。
//    //相当于增加了一个数组short [10]的大小
//    
//    printf("\n");
//    //int *p;p+1;//+1加了int *的大小
//    int *p=NULL;
//    printf("%p    ", p);
//    printf("%p    ", p+1);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

/*
指针+-指针(指针加减指针)
        
        指针 + 指针:Error!!!
        指针 - 指针:
            1.普通变量来说,没有实际意义
            2.数组来说,偏移过的元素个数。
*/
//#include"head.h"
//int main() {
//    int a = 10;
//    int b = 20;
//    int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
//
//    int *p = &a;
//    int *p1 = &b;
//    printf("%p    \n", p);
//    printf("%p    \n", p1);
//    printf("%p    \n", p-p1);
//
//    printf("\n\n");
//
//    int *pp = &arr[3];
//    //值代表偏移过的元素个数
//    printf("%d    \n", pp - arr);
//    //值代表偏移过的元素个数
//    int *ppp = &arr[5];
//    printf("%d    \n", ppp - pp);
//
//    system("Pause");
//    return EXIT_SUCCESS; 
//}




/*
strlen函数实现:
    方式一:借助指针实现strlen函数
        int my_strlen(char str[]) {
            char *p = str;
            while (*p!='\0') {
                p++;
            }
            int flag = p - str;//即为数组有效元素的个数
            return flag;
        }

    方式二:借助数组实现strlen函数
        int my_strlen(char str[]){
            int i=0;
            while(str[i]!='\0'){
                i++;
            }
            return i;
        }

*/
//#include"head.h"
//int main() {
//    char str[] = "hello c000 \0";
//    printf("%d    \n", my_strlen(str));
//
//    system("Pause");
//    return 0;
//}


/*
指针比较运算:(指针可以进行比较运算)(包括:判断是否等于NULL)
    > < ==

    1.普通变量来说:语法允许,但无实际意义。
    2.数组来说:地址之间可进行比较大小
                可以得到:元素存储的先后顺序
    3.判空比较:
        if (p != NULL) {
            printf("p is not NULL! ");
        }
        else {
            printf("p is NULL! ");
        }
*/
//#include"head.h"
//int main() {
//    int a = 2;
//    int b = 3;
//    int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
//
//    int *p0 = &a;
//    int *p1 = &b;
//
//    //int *p0 = &arr[2];
//    //int *p1 = &arr[5];
//
//    if (p0 > p1) {
//        printf("p1先存在!    \n");
//    }
//    else if (p0<p1) {
//        printf("p0先存在!    \n");
//    }
//    else {
//        printf("==!    \n");
//    }
//
//    system("Pause");
//    return 0;
//}
//#include"head.h"
//int main() {
//    int *p = NULL;
//
//    if (p != NULL) {
//        printf("p is not NULL! ");
//    }
//    else {
//        printf("p is NULL! ");
//    }
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
指针数组:
    一个存储地址的数组。数组内所有元素都是地址。
    指针数组本质,是一个二级指针。
    二维数组,也是一个二级指针。


多级指针:
    int a=0;                
    int *p=&a;                //一级指针是 变量的地址
    int **pp=&p;                //二级指针是 一级指针的地址    
    int ***ppp=&pp;            //三级指针是 二级指针的地址
    int ****pppp=&ppp;        //四级指针是 三级指针的地址    【了解即可】
    .............
    多级指针不能跳跃定义
    .............


    对应关系:
    ppp == &pp;            三级指针
    *ppp == pp == &p;        二级指针
    **ppp == *pp == p == &a;        一级指针
    ***ppp == **pp == *p == a;            普通整型变量



*/

//#include"head.h"
//int main() {
//    int a = 10;
//    int b = 20;
//    int c = 30;
//
//    int *p1 = &a;
//    int *p2 = &b;
//    int *p3 = &c;
//
//    int * arr[] = { p1,p2,p3 };//整形指针数组arr,存的都是整形地址。
//
//    printf("%d    \n", *(arr[0]));
//    printf("%d    \n", *( *(arr+0) ) );
//    printf("%d    \n", *( *arr) );
//    printf("%d    \n", **arr );//被称为二级指针
//    
//    system("Pause");
//    return EXIT_SUCCESS;
//}

//#include"head.h"
//int main() {
//    int a[] = { 10,11 };
//    int b[] = { 20,21 };
//    int c[] = { 30,31 };
//
//    int * arr[] = { a,b,c };//整形指针数组arr,存的都是整形地址。
//
//    printf("%d    \n", *(arr[0]+0));
//    printf("%d    \n", *(arr[0]+1));
//    printf("%d    \n", *( *(arr+0)+0));
//    printf("%d    \n", **arr);        //二维数组,也是一个二级指针。
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
多级指针:
        不能跳跃定义。
*/
//#include"head.h"
//int main() {
//    int a = 20;
//    int *p = &a;
//    int **pp = &p;
//    int ***ppp = &pp;
//    
//    //以下可以等价代换
//    printf("%d    \n", ***ppp);
//    printf("%d    \n", **pp);
//    printf("%d    \n", *p);
//    printf("%d    \n", a);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
***********************************
栈帧概念!*************************
***********************************


指针和函数:
    栈帧:
        当函数调用时,系统会在 stack 空间上申请一块内存区域。用来提供函数调用,主要用来存放形参和局部变量(定义在函数内部的变量)。
        当函数调用结束,这块内存区域自动被释放(消失,其实是标记一下这块空间不再使用,操作系统负责分配是否给其他使用)。
        【先有的栈,才有的栈帧。】

        函数开始执行即产生一块栈帧
        main函数开始执行,stack内会产生一块栈帧。main函数右大括号结束,该栈帧消失。

    传值和传址:
            传值:函数调用期间,实参将自己的值,拷贝一份给形参。
            传址:函数调用期间,实参将地址值,拷贝一份给形参。
                    【地址值---》在swap函数内部,修改了main函数栈帧内部的局部变量。】

    指针做函数参数:
        int swap001(int *a, int * b) ;
        调用时,传有效的地址值。

    数组做函数参数:
        int bubble_sort(int arr[20]);==int bubble_sort(int arr[]) ;==int bubble_sort(int *arr) ;    //三种写法均可
        传递不是整个数组,而是数组的首地址。(一个指针,sizeof()求大小的话就是指针的大小,和操作系统有关)
        所以当整形数组做函数参数时,我们通常在函数定义中封装两个参数。一个表数组首地址,一个表元素个数。
        
    指针做函数返回值:
        int *test_func(int temp) ;
        指针做函数返回值,不能返回该函数【局部变量的地址值】。(该函数调用结束 空间即释放 )
            
    数组做函数返回值:
        C语言,不允许!!!只能写成指针形式。


*/

////传值!!
//#include"head.h"
////传值 不会改变main函数内的值,因为值是由参数传递进swap函数(是copy的)。
//int swap(int a, int b) {
//    int temp = 0;
//
//    temp = a;
//    a = b;
//    b = temp;
//
//    return EXIT_SUCCESS;
//}
////传址,其实也是传值,只是值是一个地址。
//int swap001(int *a, int * b) {
//    int temp = 0;
//
//    temp = *a;
//    *a = *b;
//    *b = temp;
//
//    return EXIT_SUCCESS;
//}
////传址,其实也是传值,只是值是一个地址。数组和指针都一样只是写法不同。
//int swap002(int a[], int b[]) {
//    int temp = 0;
//
//    temp = *a;
//    *a = *b;
//    *b = temp;
//
//    return EXIT_SUCCESS;
//}
//
//int main() {
//    int a = 10, b = 20;
//
//    printf("a=%d,b=%d    \n", a, b);
//    swap(a, b);
//    printf("a=%d,b=%d    \n", a, b);
//    swap001(&a, &b);
//    printf("a=%d,b=%d    \n", a, b);
//    swap002(&a, &b);
//    printf("a=%d,b=%d    \n", a, b);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}



/*
数组作为参数传递
*/
//#include"head.h"
////数组作为函数参数传递的不是整个数组,而是数组的首地址。
//int bubble_sort(int arr[]) {
//    int flag = sizeof(arr) / sizeof(arr[0]);
//    printf("bubble_sort flag :%d \n", flag);
//
//    int temp = 0;
//    for (int i = 0; i < flag-1; i++) {
//        for (int j = 0; j < flag-1-i; j++) {
//            if ( arr[j]>arr[j+1] ) {
//                temp = arr[j];
//                arr[j] = arr[j+1];
//                arr[j+1] = temp;
//            }
//        }
//    }
//    return EXIT_SUCCESS;
//}
////数组作为函数参数传递时,一般设置两个参数,一个是数组地址,一个是length。
//int bubble_sort001(int arr[],int flag) {
//    printf("bubble_sort flag001 :%d \n", flag);
//    int temp = 0;
//    for (int i = 0; i < flag-1; i++) {
//        for (int j = 0; j < flag - 1 - i; j++) {
//            if (arr[j] > arr[j+1]) {
//                temp = arr[j];
//                arr[j] = arr[j + 1];
//                arr[j + 1] = temp;
//            }
//        }
//    }
//    return EXIT_SUCCESS;
//}
//
//int my_print_sort(int *arr ,int flag) {
//    for (int i = 0; i < flag; i++) {
//        printf("%d \t", arr[i]);
//    }
//    printf("\n");
//    return EXIT_SUCCESS;
//}
//
//int main() {
//    int arr[] = { 5,3,20,3,66,52,30,0,1,2,1 };
//    bubble_sort(arr);
//
//    int flag = sizeof(arr) / sizeof(arr[0]);
//    printf("main flag :%d \t\n", flag);
//    my_print_sort(arr, flag);    
//
//    bubble_sort001(arr,flag);
//    my_print_sort(arr, flag);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
指针做函数返回值
*/

//#include"head.h"
//
//int a = 10;//全局变量 对应空间消失==》只有程序结束。
//
//int *test_func(int temp) {
//    return &a;
//}
//
//int main() {
//    
//    printf("%p \t\n", &a);
//    printf("%p \t\n", test_func(2) );
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}





//**************************************************
///*
//关机恶搞小程序。
//*/
//#include"head.h"
//int main() {
//
//    system("title 关机程序     倒计时结束,将会启动电脑自毁程序!!!"); //设置cmd窗口宽度
//    system("mode con cols=60 lines=20");//窗口宽度高度
//    system("color 16");//设置默认控制台前景个背景色
//    system("shutdown /s /t 180"); //启动计划关机 时间为3分钟
//
//    //倒计时时钟 显示
//    for (int j = 10;j > 0;j--) {
//        for (int k = 59;k > 0;k--) {
//            printf("%02d:%02d        ", j, k);
//            Sleep(1);
//            system("cls");
//        }
//    }
//
//
//    char str[50];
//    printf("输入“爸爸”即可取消关机!!!        \n");
//
//    //循环判断输入字符串是不是 爸爸
//    while (1) {
//        gets_s(str);
//        if (strcmp(str,"爸爸") == '\0') {
//            break;
//        }
//        printf("输入有误无法取消关机!!!        \n");
//    }
//    
//    //取消关机
//    system("shutdown -a");
//    printf("已取消关机!!!        \n");
//
//    return EXIT_SUCCESS;
//}
//**************************************************



/*

指针和字符串:
    1.
        char str0[] = { 'h','i','\0' };
        char str1[] = "hi";
        //char *str2 = "hi";                //报错
        //char *str3 = { 'h','i','\0' };    //报错
    2.
        当字符串(字符数组),做函数参数时,不需要提供两个参数。因为每个字符串都有'\0'结尾。

    练习:
        比较两个字符串:strcmp();实现
        比较str1和str2,如果相同返回0,不同则一次比较ASCII码,str1>str2返回1,否则返回-1

*/

/*
字符串的创建方式
*/
//#include"head.h"
//int main() {
//    char str0[] = { 'h','i','\0' };
//    char str01[] = { 'h','i','\0' };
//    char str1[] = "hi";
//    char str11[] = "hi";
//    //char *str2 = "hi";                //报错
//    //char *str3 = { 'h','i','\0' };    //报错
//
//    printf("%c \t\n", str0[0]);
//    printf("%c \t\n", str1[0]);
//
//    str0[0] = 'R';
//    str1[0] = 'R';
//
//    printf("%c \t\n", str0[0]);
//    printf("%c \t\n", str1[0]);
//
//    printf("%p \t\n", &str0[0]);
//    printf("%p \t\n", &str01[0]);
//    printf("%p \t\n", &str1[0]);
//    printf("%p \t\n", &str11[0]);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*

    练习:比较两个字符串;
        比较str1和str2,如果相同则返回0,不同则依次比较ASCII码,str1 > str2返回1,否则返回 - 1;

    练习:字符串拷贝;

    练习:在字符串中查找字符出现的位置;

    练习:字符串去空格


*/

/*
练习:比较两个字符串;
        比较str1和str2,如果相同则返回0,不同则依次比较ASCII码,str1 > str2返回1,否则返回 - 1;
*/

/*
方式1
*/

//#include"head.h"
//int my_string_compare(char *str1, char *str2) {
//    while (*str1) {
//        if (*str1==*str2) {
//            str1++;
//            str2++;
//            continue;
//        }
//        else {
//            return *str1 > *str2 ? 1 : -1;
//        }
//    }
//    if (*str1 == *str2) {
//        return 0;
//    }
//    else {
//        return *str1 > *str2 ? 1 : -1;
//    }
//}
//int main() {
//    //str01大
//    char str00[] = "hello c++";
//    char str01[] = "hello java";
//        
//    ////str00大
//    //char str01[] = "hello c++";
//    //char str00[] = "hello java";
//
//    ////str00==str01
//    //char str00[] = "hello c++";
//    //char str01[] = "hello c++";
//
//    printf("函数my_string_compare返回值为:%d \t\n", my_string_compare(str00, str01)  );
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

/*
方式2
*/

//#include"head.h"
//int my_string_compare(char *str1, char *str2) {
//    while (*str1==*str2) {
//        if (*str1==0) {
//            return 0;
//        }
//        str1++;
//        str2++;
//    }
//    return *str1 > *str2 ? 1 : -1;
//}
//int main() {
//    ////str01大
//    //char str00[] = "hello c++";
//    //char str01[] = "hello java";
//
//    ////str00大
//    //char str01[] = "hello c++";
//    //char str00[] = "hello java";
//
//    //str00==str01
//    char str00[] = "hello c++";
//    char str01[] = "hello c++";
//
//    printf("函数my_string_compare返回值为:%d \t\n", my_string_compare(str00, str01));
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}



/*
    练习:字符串拷贝;
*/

//#include"head.h"
//int my_string_copy(char *source, char *destine,int flag) {
//    while ( *source && flag-1) {
//        *destine = *source;
//        destine++;
//        source++;
//        flag--;
//    }
//    *destine = 0;
//    if (flag-1<0 || flag-1==0) {
//        //printf("Error: 1 \n");
//        return 1;
//    }
//    return EXIT_SUCCESS;
//}
//int my_printf_string(char *string) {
//    printf("%s \n",string);
//    return EXIT_SUCCESS;
//}
//int main() {
//    char source[] = "hello c++";
//    char destine[3] = { 0 };
//    int flag = sizeof(destine) / sizeof(destine[0]);
//
//    my_printf_string(destine);
//    my_string_copy(source, destine, flag);
//    my_printf_string(destine);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


/*
    练习:在字符串中查找字符出现的位置;
*/

//#include"head.h"
//char * my_search_char(char *string, char *destine_char) {
//    while (*string) {
//        if (*string == *destine_char) {
//            return string;
//        }
//        string++;
//    }
//    return NULL;
//}
//int main() {
//    char string[] = "hello c++,I love you ;";
//    char destine_char = 'o';
//    char * flag = my_search_char(string, &destine_char);
//    if (flag==NULL) {
//        printf("没有出现该字符;\n");
//    }
//    else {
//        //printf("%s \n", flag);
//        printf("该字符首次出现的的位置以及后续字符:");
//        while (*flag) {
//            printf("%c", *flag);
//            flag++;
//        }
//    }
//    system("Pause");
//    return EXIT_SUCCESS;
//}



/*
    练习:字符串去空格
*/
//#include"head.h"
//void string_remove_space(char *source , char *destine) {
//    while (*source!='\0') {
//        if (*source!=' ') {
//            *destine = *source;
//            destine++;
//        }
//        source++;
//    }
//}
//int main() {
//    char source[] = "ni chou sha , chou ni za di .";
//    char destine[100] = { 0 };
//
//    printf("%s \t\n", destine);
//    string_remove_space(source, destine);
//    printf("%s \t\n", destine);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}




/*
带参数的main函数:
    无参main函数: int main(void)==int main()
    带参数的main函数:int main(int argc,char *argv[]) == int main(int argc,char **argv)
        参数一:表示给main函数传递的参数的总个数
        参数二:是一个数组!数组的每一个元素都是字符串 char *

    测试1:
        命令行终端中,使用gcc编译生成可执行文件。如:test.exe
        test.exe abc xyz zhangsan nichousha
        -->
        argc---5
        test.exe---argv[0]
        abc---argv[1]
        xyz---argv[2]
        zhangsan---argv[3]
        nichousha---argv[4]

    测试2:
        再Visualstudio中,
        项目名称上--》右键--》属性--》调试--》命令行参数--》将 
        test.exe abc xyz zhangsan nichousha 写入
        -->
        argc---5
        test.exe---argv[0]
        abc---argv[1]
        xyz---argv[2]
        zhangsan---argv[3]
        nichousha---argv[4]
*/

//#include"head.h"
//int main(int argc,char *argv[] ,char *envp[] ) {
//
//    printf("argc = %d \n", argc);
//    for (size_t i=0 ; i < argc; i++) {
//
//        printf("argv[%d] = %s \n",i, argv[i] );            
       ////注意:此处打印字符串,虽然是二级指针但是%s需要的是一个地址,也就是该指针数组的其中一个元素即可。
//    }
//
//    printf("\n\n\n");
//    printf("envp: \t\n");
//    for (int i = 0; envp[i] ; i++) {
//        printf("%s \n", envp[i]);
//    }
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}





/*

str中substr出现的次数:

    先熟悉一下函数strstr:
    在str中找substr出现的位置
    char *strstr(char *str,char *substr)    --->需引入头文件:#include<string.h>
            参数一:原串
            参数二:子串
            返回值:字串在原串中的位置。(地址值) 
                    如果没有返回:(null)
*/

////测试strstr函数
//#include"head.h"
//int main() {
//    char str01[] = "hellollollollo";
//    char str02[] = "llo ";
//    
//    printf("%s \n", strstr(str01, str02));
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

////str中substr出现的次数:
//#include"head.h"
//
//int string_times(char *string, char *substr) {
//    int flag = 0;
//    char *p = strstr(string, substr);
//    
//    while ( p!=NULL ) {
//        flag++;
//        p = p + strlen(substr);
//        p = strstr(p, substr);
//    }
//    return flag;
//}
//
//int main() {
//    char str01[] = "hellollollollollo";
//    char str02[] = "llo";
//    //printf("%s \n", strstr(str01, str02));
//        
//    printf("%d \n", string_times(str01, str02) );
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}





/*
求非空字符串个数:
*/
//#include"head.h"
//
//int statistic_no_space_string(char *string) {
//    int flag = 0;
//    while (*string) {
//        if (*string == ' ') {
//            string++;
//            continue;
//        }
//        flag++;
//        string++;
//    }
//    return flag;
//}
//
//int main() {
//    char string[] = "ni chou sha";
//    printf("%d \n", statistic_no_space_string(string) );
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}



/*
字符串逆置:str_inverse
*/

//#include"head.h"
//
//char * string_inversion(char *string) {
//    char *base = string;                            //记录首元素地址 返回值即为此
//    char *strl = string + strlen(string) - 1;        //得出最后一个元素的地址
//    while ( string < strl ) {
//        char temp = { 0 };                            //设置三杯水法的转接变量
//        temp = *string;
//        *string = *strl;
//        *strl = temp;
//        string++;                                    //元素后移
//        strl--;                                        //元素前移
//    }
//    return base;;
//}
//int main() {
//    char str[] = "hello heihei";
//    printf("%s \n", str); 
//    printf("%s \n", string_inversion(str) );
//
//    return EXIT_SUCCESS;
//}



/*
判断字符串是否是回文
    回文:正着读倒着读都是一样的。例如asdsa
*/

//#include"head.h"
//
//int string_inversion(char *string) {
//    char *base = string;                            //记录首元素地址 返回值即为此
//    char *strl = string + strlen(string) - 1;        //得出最后一个元素的地址
//    while ( string < strl ) {
//        if ( *string != *strl ) {
//            return -1;
//        }
//        string++;                                    //元素后移
//        strl--;                                        //元素前移
//    }
//    return 0;
//}
//int main() {
//    char str[] = "hhsdshh";
//    printf("%s \n", str );
//    int flag = string_inversion(str);
//    if (flag==0) {
//        printf("回文! \n");
//    }
//    else if (flag==-1) {
//        printf("不是回文! \n");
//    }
//    else {
//        printf("Error! \n");
//    }
//    return EXIT_SUCCESS;
//}




/*
字符串处理函数:#include<string>        //对于函数来说 就是一个工具 就像鼠标一样 知道怎么用就好 
    
    字符串拷贝: 
        strcpy :
            char *strcpy(char *dest,const char *source);
            将source的内容,拷贝给dest。返回dest。要保证dest空间足够大。
            函数调用结束 返回值和dest参数结果一致。 
        strncpy:
            char *strncpy(char *dest ,const char *source,size_t n);
            将source的内容,拷贝给dest。只拷贝n个字节。通常n与dest对应的空间一致。
            默认不添加'\0'
            特性:
                n>source:只拷贝source的大小
                n<source:只拷贝n字节大小。不添加'\0'

    字符串拼接:
        strcat():
            char *strcat(char *dest,const char *source);
            将source内容,拼接到dest后。返回拼接后的字符串。保证dest空间足够大。
        strncat():
            char *strncat(char *dest,const char *source,size_t n );
            将source的前n个字符,拼接到dest后,形成一个新的字符串。保证dest空间足够大。

    字符串比较:        不能使用 > < >= <= == !=
        strcmp:
            int strcmp(const char *s1,sonst char *s2);
            比较s1和s2两个字符串,如果相等返回0,如果不相等,进一步表示s1和s2对应位ASCII码值。
            s1>s2 返回1
            s1<s2 返回-1
        strncmp:
            int strncmp(const char *s1,sonst char *s2,size_t n);
            比较s1和s2两个字符串的前n个字符
            如果相等返回0,不相等进一步比较s1和s2对应位的ASCII码值。
            s1>s2 返回1
            s1<s2 返回-1

    字符串格式化输入输出:        s-->string
        sprintf();
            int sprintf(char *str,const char *format,...);
            对应printf,将原来写到屏幕的“格式化字符串”,写到参数1 str中。
            printf("%d+%d=%d\n",10,24,10+24);
            --->
            char str[100];
            sprintf(str,"%d+%d=%d\n",10,24,10+24); 格式串写入str数组中。
        sscanf();
            int sscanf(const char *str,const char *format,...);
            对应scanf,将原来从屏幕获取的“格式化字符串”,从参数1 str中获取。
            scanf("%d+%d=%d",&a,&b,&c);
            --->
            char str[]="10+24=45";
            sscanf(str,"%d+%d=%d",&a,&b,&c);
            
    字符串查找字符、字串:
        strchr();
            在字符串str中 找一个字符出现的位置,返回字符在字符串中的地址。
            printf("%s \n",strchr("hehehahahoho",'a') );--->"ahahoho"
        strrchr();
            自右向左,在字符串str中 找一个字符出现的位置,返回字符在字符串中的地址。
            printf("%s \n",strrchr("hehehahahoho",'a') );--->"ahoho"
        strstr();
            在字符串str中,找子串substr第一次出现的位置,返回地址。
            char *strstr(const char *str,const char *substr);
            printf("%s \n",strstr("hehehahahoho",'ha') );--->"hahahoho"
            printf("%s \n",strstr("hehehahahoho",'aa') );--->NULL
            

    字符串分割:    在后面

*/

////字符串copy
//#include"head.h"
//
//int main() {
//    char str[] = "hhhjjjkkk";
//    char str01[100] = { 0 };
//    char str02[100] = { 0 };
//
//    int n = sizeof(str01);
//    printf("str01[100]:%s \n", str01);
//    printf("str02[100]:%s \n", str02);
//    strcpy_s(str01, str);
//    strncpy(str02, str,100);
//    printf("str01[100]:%s \n", str01);
//    printf("str02[100]:%s \n", str02);
//
//    return EXIT_SUCCESS;
//}

////字符串拼接
//#include"head.h"
//
//int main() {
//    char str[100] = "hhhjjjkkk";
//    char str01[100] = "aaa";
//    char str02[100] = "bbb";
//
//    int n = sizeof(str01);
//    printf("str01:%s \n", str01);
//    printf("str02:%s \n", str02);
//    strcat_s(str01, str);
//    strncat_s(str02, str,2);
//    printf("str01:%s \n", str01);
//    printf("str02:%s \n", str02);
//
//    return EXIT_SUCCESS;
//}


////字符串比较
//#include"head.h"
//
//int main() {
//    char str[100] = "hhhjjjkkk";
//    char str01[100] = "hhh";
//    char str02[100] = "hi";
//
//    printf("strcmp(sre,str01):%d \n", strcmp(str, str01));
//    printf("strncmp(sre,str01,):%d \n", strncmp(str, str01, 3));
//    printf("strcmp(sre,str02):%d \n", strcmp(str, str02));
//
//    return EXIT_SUCCESS;
//}




////    字符串格式化输入输出:
//#include"head.h"
//int main() {
//    char str[100] = "hhhjjjkkk";
//    char str01[] = "6.6=6.0";
//
//    printf("%s \n", str);
//    printf("%d \n", sprintf_s(str, "%d+%d=%d", 10, 24, 10 + 24));
//    printf("%s \n", str);
//
//    printf("--------------- \n");
//
//    double a = 0, b = 0;
//    printf("%s \n", str01);
//    printf("a=%lf \n", a);
//    printf("b=%lf \n", b);
//    sscanf_s(str01, "%lf=%lf", &a, &b);
//    printf("%s \n", str01);
//    printf("a=%lf \n", a);
//    printf("b=%lf \n", b);
//
//    return EXIT_SUCCESS;
//}


////    字符串查找字符、子串:
//#include"head.h"
//int main() {
//    char str[100] = "hhhjjjkkk";
//    char str01 = 'j';
//    char str02[] = "jj";
//
//    printf("%s \n", strchr(str, str01));//自左向右找
//    printf("%s \n", strrchr(str, str01));//自右向左找
//    printf("%s \n", strstr(str, str02));//查找字符串
//
//    return EXIT_SUCCESS;
//}






/*
字符串分割:!!!


    后面学习正则表达式后 拆分使用正则表达式。
        scanf("%s",str);
        scanf("%[^\n]",str);

    字符串分割:
        strtok():按照既定的分隔符,来拆分字符串。
        char *strtok(char *str,const char *delim);
            参一:待拆分字符串
            参二:分隔符组成的“分割串”
            返回:字符串拆分后的首地址        拆分:将分隔符用'\0'替换
        特性:
            strtok拆分字符串是直接在原串上操作,所以要求参1必须可读可写.
            第一次拆分,参1传 待拆分的原串。第1+次拆分是,参1传NULL
            所以    写法strtok("www.baidu.com",".");是不可以的
    练习:
        "www.itcast.cn$This is a strtok$test"


    atoi/atof/atol:
        atoi:a表示字符串 to表示转 i表示整数 int
        atof:a表示字符串 to表示转 f表示浮点数 float
        atol:a表示字符串 to表示转 l表示长整数 long

        使用这类函数进行转换,要求原串必须是可转换的字符串

        int atoi(const char *nprt);



*/

////    字符串分割:
//#include"head.h"
//int main() {
//    char str[100] = "https://blog.csdn.net/jay_zzs/article/details/106883832";
//    char str01[100] = "://./";
//    char *str02 = NULL;
//
//    //遍历打印str原串
//    printf("<<----------遍历打印str原串 \n");
//    for (int i = 0; i < 60; i++) {
//        printf("%c        %d \n", str[i], str[i]);
//    }
//    printf("遍历打印str原串---------->> \n");
//
//    char *p = strtok_s(str, str01, &str02);
//
//    //遍历打印看看str原串 有什么改变
//    printf("<<----------遍历打印看看str原串 有什么改变 \n");
//    for (int i = 0; i < 60; i++) {
//        printf("%c        %d \n", str[i],str[i]);
//    }
//    printf("遍历打印看看str原串 有什么改变---------->> \n");
//
//    printf("str :%s \n", str);
//    printf("p :%s \n", p);
//    printf("str02 :%s \n", str02);
//
//    return EXIT_SUCCESS;
//}

////    字符串分割:
//#include"head.h"
//int main() {
//    char str[100] = "https://blog.csdn.net/jay_zzs/article/details/106883832";
//    char str01[100] = "://./_";
//    char *str02 = NULL;
//
//    char *p = strtok_s(str, str01, &str02);//第一次拆分 参1传待拆分的原串
//    printf("%s \n", p);
//    while (p!=NULL) {
//        p = strtok_s(NULL, str01, &str02);//第1+次拆分是,参1传NULL
//        printf("%s \n", p);
//    }
//    printf("------------ \n");
//    printf("str :%s \n", str);
//    printf("p :%s \n", p);
//    printf("str02 :%s \n", str02);
//
//    return EXIT_SUCCESS;
//}

////    字符串分割:
//#include"head.h"
//int main() {
//    char str[100] = "www.itcast.cn$This is a strtok$test";
//    char str01[100] = ". $";
//    char *str02 = NULL;
//
//    char *p = strtok_s(str, str01, &str02);//第一次拆分 参1传待拆分的原串
//    printf("%s \n", p);
//    while (p != NULL) {
//        p = strtok_s(NULL, str01, &str02);//第1+次拆分是,参1传NULL
//        printf("%s \n", p);
//    }
//    printf("------------ \n");
//    printf("str :%s \n", str);
//    printf("p :%s \n", p);
//    printf("str02 :%s \n", str02);
//
//    return EXIT_SUCCESS;
//}




////atoi,atof,atol------字符串转换为整数 浮点数 长整型
//#include"head.h"
//int main() {
//    char ai[] = "   28  \t";//转的时候会自动忽略掉空格等
//    char af[] = "28.234  \n";
//    char al[] = "2860";
//    char test[] = "2sss86sss01sss";//使用这类函数进行转换,要求原串必须是可转换的字符串
//    char test01[] = "a2sss86sss01sss";
//
//    printf("%d  \n", atoi(ai));
//    printf("%lf  \n", atof(af));
//    printf("%ld  \n", atol(al));
//
//    printf("test:  \n");
//    printf("%ld  \n", atol(test));
//    printf("%d  \n", atoi(test));
//    printf("%lf  \n", atof(test));
//    printf("test01:%d  \n", atoi(test01));
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}








/*
//168集 局部变量

内存管理:

*/

/*
局部变量:
    概念:定义在函数内部的变量
    作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。
    生命周期:

全局变量:(全局变量的 int的初值默认为0)
    概念:定义在函数外部的变量
    作用域:从定义位置开始,默认到本文件内部。其他文件如果想使用,可以通过声明方式将作用域导出。

static全局变量:(静态全局变量)
    定义语法:在全局变量定义之前添加static关键字。        static int a = 10 ;
    作用域:被限制在本文件内部,不允许通过声明导出到其他文件。(相对于全局变量作用域缩小了)

static局部变量:
    定义语法:在局部变量定义之前加static关键字。
    特性:静态局部变量只定义一次。相当于定义在了全局位置。        通常用来做计数器。
    作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。

*/

////全局变量 局部变量
//#include"head.h"
//int iiiii = 2;//全局变量
//void test(void) {
//    for (int i = 0; i < 10; i++) {   //i只在for循环内有效
//        printf("test:for:%d \n", i);
//    }
//    {
//        int ii = 5;//ii只在代码块(语句块)内有效
//        printf("test:{}:%d \n", ii);
//    }
//    int iii = 3;//iii只在test函数内有效
//    printf("test:%d \n", iii);
//}
//int main() {
//    printf("函数外iiiii:%d \n", iiiii);
//
//    test();
//
//    int iiii = 8;
//    printf("test:%d \n", iiii);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}

/*
多文件联编时的全局变量:

    多个.c文件联合编译时,在某个.c文件内有个变量x,想要在其他.c文件内使用该x:
        默认是不可以使用的,该变量在声明位置到.c文件结束时就没有了,
        其他文件想要使用,可以通过声明方式将作用域导出。        如果该变量被static修饰,则其他文件不能使用。

*/

////全局变量 局部变量
//#include"head.h"
//int i= 2;//全局变量
//
////该变量位bubble_short内的变量,定义时正常定义,但是在使用时需声明该变量是外部的。
//extern int xxx;
//
//void test(void) {
//    {
//        printf("test:%d \n", i);
//    }
//}
//int main() {
//    test();
//    printf("test:%d \n", i);
//
//    //可以直接访问外部的变量
//    printf("bubble_sort的变量xxx:%d \n", xxx);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}


////静态static全局变量 静态static局部变量
//#include"head.h"
//static int i= 0;//全局变量
//
////该变量位bubble_short内的变量,定义时正常定义,但是在使用时需声明该变量是外部的。
//extern int yyy;
//
//void test00(void) {
//    {
//        printf("test:i:%d \n", i++);
//    }
//}
//void test01(void) {
//    {
//        static int ii = 0;//只定义一次,再次调用时会略过这行代码。
//        printf("test:ii:%d \n", ii++);
//    }
//}
//void test02(void) {
//    {
//        int iii = 0;
//        printf("test:iii:%d \n", iii++);
//    }
//}
//
//int main() {
//    //全局静态变量
//    for (int i = 0; i < 5; i++) {
//        test00();
//    }
//    printf("--------------- \n" );
//    //静态局部变量,相当于在全局位置定义了该变量,但是变量作用域还是局部的。所以被用来做计数器
//    //printf("test:ii:%d \n", ii++);////无法访问该局部静态变量
//    for (int i = 0; i < 5; i++) {//
//        test01();
//    }
//    printf("--------------- \n" );
//    //无论调用几次 结果都不会累加,每次调用结束,函数内的iii都会被清掉然后再次 声明定义。
//    for (int i = 0; i < 5; i++) {
//        test02();
//    }
//    printf("--------------- \n" );
//
//    //当外部的变量被static修饰时,不可以再访问。
//    //printf("bubble_sort的变量yyy:%d \n", yyy);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}



/*

全局函数:就是大家通常说的函数
    定义语法: 函数原型 + 函数体

static函数:
    定义语法:static + 函数原型 + 函数体
    static函数:只能在本文件内使用。其他文件即使声明也无效。

*/

//#include"head.h"
//
//int test02(int *a);//外部bubble_sort的全局函数
//
////int test03(int *a);//外部bubble_sort的static全局函数--------报错:全局函数加static之后作用域就被限定在了该函数所在的文件。
//
//int test01(int *a) {//本文件的全局函数
//    int temp =  *a;
//    return temp;
//}
//
//int main() {
//    int a = 20;
//
//    printf("%d \n", test01(&a) );
//    printf("%d \n", test02(&a) );
//    //printf("%d \n", test03(&a) );
//}

/*
生命周期:
    局部变量:从变量定义开始,函数调用完成。-----函数内部
    全局变量:程序启动开始,程序终止结束。-------程序执行期间
    static局部变量:程序启动开始,程序终止结束---程序执行期间
    static全局变量:程序启动开始,程序终止结束---程序执行期间
    全局函数:程序启动开始,程序终止结束---------程序执行期间
    static函数:程序启动开始,程序终止结束-------程序执行期间
    
*/

/*
内存四区模型:

    代码段:.text段。程序源代码(二进制形式)。            只读
    数据段:只读数据段.rodata段。常量                    只读
        初始化数据段.data段。初始化为非0的全局变量和静态变量。        读写
        未初始化数据段.bss段。初始化为0,未初始化的全局变量和静态变量。程序加载执行前,会将该段整体赋值为0.        读写
    stack:
            栈。在其上开辟 栈帧。比较小,系统制动管理,自动分配,自动释放。
            特性是FILO,先进后出。        
            windows:1M-10M        Linux:8M-16M
    heap:
            堆。空间足够大。给用户自定义数据提供空间。    
            约1.3G+        使用时需要程序员申请


*/

/*
全局变量 和 局部变量 重名
局部变量 和 static局部变量等
    遵循就近原则。但是不建议这么使用,明白即可。    使用数字 字母 下划线 任意组合即可。

*/
//#include"head.h"
//int ss = 1996;
//int main() {
//    int ss = 5;
//    printf("ss=%d \n", ss);
//    printf("************************ \n");
//
//    int i = 5;
//    for (int i = 0; i < 10; i++) {
//        printf("i=%d \n", i);
//    }
//    
//    return EXIT_SUCCESS;
//}



/*

开辟释放heap空间:
    
    void * malloc(size_t size) 申请size大小的空间
        返回实际申请到的内存空间首地址。【我们通常拿来当作数组使用】
    void free(void *ptr) 释放申请的空间
        参数:malloc返回的地址值。(如果不是则会报错)

使用heap空间:
    空间连续,当成数组来使用。
    free后的空间,不会立即失效。通常将free后的 地址置为NULL。
    free地址必须是malloc申请的地址。否则出错。
    如果malloc之后的地址一定会变化,那么使用临时变量tmp保存。

*/

//#include"head.h"
//
//int main() {
//    ////在栈上,超过100 0000就会报错
//    //int arr[1000000] = { 14,32,3 };
//
//    int * const raw_p = (int *)malloc(sizeof(int) * 100000000);
//    if (raw_p==NULL) {
//        printf("malloc raw_p error ! \n");
//        exit(-1);
//    }
//    int *p = raw_p;
//
//    //访问 申请出来的空间
//    for (int i = 0; i < 10; i++) {
//        p[i] = i;
//    }
//
//    //使用申请出来的空间
//    for (int i = 0; i < 10; i++) {
//        printf("%d  ", p[i]);
//    }
//    printf("\n******* \n");
//
//    //释放 malloc申请的空间
//    free(raw_p);
//    
//    return EXIT_SUCCESS;
//}





/*


二级指针对应的heap空间:  使用malloc申请
    申请外层指针:    char **p=(char **)_malloc(sizeof(char *)*5);
    申请内层指针:
        for(int i=0;i<5;i++){
            p[i]=(char *)malloc(sizeof(char )*10);
        }
    使用:不能修改p的值。
        for(int i=0;i<5;i++){
            strcpy(p[i],"hello heap");
        }
    释放内层:
        for(int i=0;i<5;i++){
            free(p[i]);
        }
    释放外层:
        free(p);

*/


//使用malloc申请一个二级指针,外层为3个元素,内层为5个元素。使用并释放。
//#include"head.h"
//int main() {
//    int **p = (int **)malloc(sizeof(int *) * 3);
//    for (int i = 0; i < 3; i++) {
//        p[i] = (int *)malloc(sizeof(int) * 5);
//    }
//
//    //使用元素
//    for (int i = 0; i < 3; i++) {
//        for (int j = 0; j < 5; j++) {
//            p[i][j] = i + j;
//        }
//    }
//
//    //打印出元素
//    for (int i = 0; i < 3; i++) {
//        for (int j = 0; j < 5; j++) {
//            printf("%d  ", p[i][j]);
//        };
//        printf("\n");
//    }
//
//    //释放内层
//    for (int i = 0; i < 3; i++) {
//        free(p[i]);
//    }
//
//    //释放外层
//    free(p);
//    return EXIT_SUCCESS;
//}


/*
栈的存储特性:
    局部变量:
    形参:

内存操作函数:
    memset:
    memmove:
    memcmp:

内存常见问题:
    1.申请0字节空间
    2.free空指针
    3.越界访问
    4.free ++后的地址
    5.子函数malloc空间,main中2用。

*/


/*

创建一个结构体数组并使用        
结构体和结构体变量是两个不同的概念:
    结构体:是一种数据类型,是一种创建变量的模板。
    结构体变量:包含实实在在的数据,需要内存存储。


通过结构体指针可以获取结构体成员,一般形式为:(*pointer).memberName或者:pointer->memberName
    第一种写法:        .的优先级高于*,(*pointer)两边的括号不能少。
                    如果去掉括号写作*pointer.memberName,那么就
                    等效于*(pointer.memberName),这样意义就完全不对了。

    第二种写法:        ->是一个新的运算符,习惯称它为“箭头”,有了它,
                    可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。

上面的两种写法是等效的,我们通常采用后面的写法,这样更加直观。
*/

//#include"head.h"
//
//int main() {
//    struct stu {//定义结构体类型stu时给与了初值
//        int a = 0;
//        double b = 22.22;
//        char c = 'A';
//    }s = { 7,7.7,'t' },*sp =&s ;
//    typedef struct stu Sstu;//重新定义该结构体的名字
//
//    int i = 0;
//    Sstu cc[3] ;//创建一个stu结构体变量数组
//    Sstu *p = NULL;
//
//    cc[0] = { 2,0.5,'a' };
//    for (i = 0; i < 3; i++) {
//        //p = &cc[i];
//        p = cc;
//        printf("cc[%d].a:%d \t\t", i, cc[i].a);
//        printf("(*p).a:%d \t\t", (*p).a);
//        printf("p->a:%d \n", p->a);
//
//        //以下两个方式打印的结果不一样
//        printf("%lf \t\t", cc[i].b);//        22.22
//        printf("%lf \n", p->b);//        0.05
//
//        printf("%c \t\t", cc[i].c);
//        printf("%c \n", p->c);
//        printf("----------\n");
//    }
//
//    printf("%d \t\t", cc[i].a);//*pointer.memberName写法
//    printf("%d \t\t", (*sp).a);//*pointer.memberName写法,前面为指针时
//    printf("%d \n", p->a);
//
//    return EXIT_SUCCESS;
//}




//#include "head.h"
//
//int main() {
//    enum day {
//        M1=1,T2,W3,T4,F5,S6,S7
//    };
//    //enum day days = (enum day)5;
//    enum day days = T4;
//    switch (days) {
//    case M1:puts("Monday");
//        break;
//    case T2:puts("Tuesday");
//        break;
//    case W3:puts("Wednesday");
//        break;
//    case T4:puts("Thursday");
//        break;
//    case F5:puts("Friday");
//        break;
//    case S6:puts("Saturday");
//        break;
//    case S7:puts("Sunday");
//        break;
//    default:puts("Error!");
//        break;
//    }
//
//    return EXIT_SUCCESS;
//}





/*
文件操作函数和字符串操作函数是最多的
*/


/*

printf---sprintf---fprintf:
    变参函数:参数形参中有“...”,最后一个固参通常是格式描述串(包含格式匹配符),函数的参数个数,类型,顺序由这个固参决定。
    例如:
        printf("hello");
        printf("%s",hello);
        printf("ret=%d+%d \n",10,5);
        printf("%d=%d%c%d \n"10+5,10,'+',5);        --->写出到屏幕

        char buf[1024];//缓冲区
        sprintf(buf,"%d=%d%c%d \n"10+5,10,'+',5);    --->写出到buf中

        FILE * fp=fopen();
        fprintf(fp,"%d=%d%c%d \n"10+5,10,'+',5);    --->写出到fp对应的文件中
        

scanf---sscanf---fscanf:
    scanf("%d",&m);                键盘--->m
    char str[]="98";
    sscanf(str,"%d",&m);        str--->m
    FILE *fp=fopen("r");
    fscanf(fp,"%d",&m);            fp--->m        //把fp指向的文件中的整数拿出来放到m中



文件操作函数:#include<stdio.h>

    fprintf()函数:
        int fprintf(FILE * stream,const char * format,...);

    fscanf()函数:
        int fscanf(FILE * stream,const char * format,...);
        1.边界溢出。存储读取的数据空间,在使用之前清空。
        2.fscanf函数,每次调用时都会判断下一次调用是否匹配参数2,如果不匹配提前结束文件读操作。(feof(fp)为真)。
         
*/








/*

文件的打开:

    打开模式:
    r或rb        以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)
    w或wb        以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)
    a或ab        以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件
    r+或rb+        以可读、可写的方式打开文件(不创建新文件)
    w+或wb+        以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建)
    a+或ab+        以添加方式打开可读可写文件,若文件不存在则创建文件;若文件存在则在文件尾添加数据(即 文件原先内容会被保留)

    b是二进制模式的意思,b只在Winsows有效,在Linux用r和rb的结果是一样的
    Linux会自动区分二进制文件与文本文件

    Unix和Linux 下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾

    在Windows平台下,以“文本”方式打开文件,不加b:
        当读取文件的时候,系统会将所有的”\r\n“转换成”\n“
        当写入文件的时候,系统会将”\n“转换为”\r\n“写入
        以”二进制“方式打开文件,则读写都不会进行这样的转换

    在Unix/Linux平台下,”文本“与”二进制“模式没有区别,”\r\n“作为两个字符原样输入输出

*/








////文件读写操作
//#include"head.h"
//int write_file() {
//    FILE *fp;
//
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\FILE_fopen_test.txt", "w+")) {
//        perror("fopen error !");
//        return -1;
//    }
//
//    fprintf(fp, "%d hello  file word!%d+%d=%d",500, 10, 5, 15);
//
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int read_file() {
//    FILE *fp;
//
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\FILE_fopen_test.txt", "r+")) {
//        perror("fopen error !");
//        return -1;
//    }
//    int temp[4] = { 0 };
//    fscanf_s(fp, "%d hello file word!%d+%d=%d" ,&temp[0],&temp[1],&temp[2],&temp[3]);
//
//    fclose(fp);
//    return temp[0];
//}
//int main() {
//    write_file();
//
//    getchar();
//
//    printf("%d \n", read_file());
//
//    return EXIT_SUCCESS;
//}

////使用fpringf和fscanf函数的文件读写操作
//#include"head.h"
//
//int write_file() {
//    FILE *fp;
//
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\FILE_fopen_test.txt", "w+")) {
//        perror("fopen error !");
//        return -1;
//    }
//
//    fprintf(fp, "%d\n%d\n%d\n%d\n5\n", 500, 10, 5, 15);
//
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int read_file() {
//    FILE *fp;
//
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\FILE_fopen_test.txt", "r+")) {
//        perror("fopen error !"); 
//        return -1;
//    }
//    int temp =  0 ;
//    while ( 1 ) {
//        fscanf_s(fp, "%d\n", &temp);
//        printf("%d \n", temp);
//        if ( feof(fp) ) {
//            return -1;
//        }
//    }
//
//    //while ( !feof(fp) ) {
//    //    fscanf_s(fp, "%d\n", &temp);
//    //    printf("%d \n", temp);
//    //}
//
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int main() {
//    write_file();
//
//    read_file();
//
//    return EXIT_SUCCESS;
//}



////使用fgets循环读文件
//#include"head.h"
//int write_file() {
//    FILE *fp;
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\FILE_fopen_test.txt", "w+")) {
//        perror("fopen error !");
//        return -1;
//    }
//    fprintf(fp, "%d\n%d\n%d\n%d\n5\n\n\n\n", 500, 10, 5, 15);
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//int read_file() {
//    FILE *fp;
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\FILE_fopen_test.txt", "r+")) {
//        perror("fopen error !"); 
//        return -1;
//    }
//    char buf[1024] = { 0 };
//    while ( 1 ) {
//        //buf[0] = 0;
//        memset(buf, 0, 1024);
//
//        //不同于fscanf需要匹配,有字符就会读取,空格换行也不例外
//        fgets(buf, 1024 , fp );//会读取换行符,所以下面打印的不需加\n
//        printf("%s", buf);
//        if ( feof(fp) ) {//为真是文件结尾
//            return -1;
//        }
//    }
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//int main() {
//    write_file();
//
//    read_file();
//
//    return EXIT_SUCCESS;
//}



/*
练习:生成随机数,将文件内乱序随机数读出,排好再写回文件。
*/

//#include"head.h"
////生成随机数,并将随机数写入文件
//int write_rand() {
//    FILE * fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\write_rand.txt", "w+");
//
//    if ( !fp ) {            //此处有两种情况:1.假使fp为NULL,取反则为真,执行if。        2.fp不为NULL(不为NIULL就是真),取反则为假,不执行if
//        perror("fopen error");
//        return -1;
//    }
////printf("%d \n", NULL);
////printf("%d \n", !NULL);

//
//    srand(time(NULL));
//
//    for (int i = 0; i < 10; i++) {
//        //printf("%d  ", rand() % 100);
//        fprintf(fp, "%d\n", rand()%100 );
//    }
//    fclose(fp);
//
//    return EXIT_SUCCESS;
//}
//
////将随机数读出并写入数组内,将数组排序后写入文件内
//int print_file() {
//    FILE * fp;
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\write_rand.txt", "r+") ) {
//        perror("fopen error!");
//        return -1;
//    }
//
//    int arrays[10] = { 0 };
//    for (int i = 0; i < 10; i++) {
//        fscanf_s(fp, "%d\n", &arrays[i] );
//        if ( feof(fp) ) {
//            break;
//        }
//    }
//
//    //对内存中的数组排序
//    bubble_sort(arrays, sizeof(arrays)/sizeof(arrays[0]) );
//
//    //关闭文件  为了重新打开之后可以覆盖掉未排序文件
//    fclose(fp);
//
//    //打开文件
//    if (fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\write_rand.txt", "w")) {
//        perror("fopen error!");
//        return -1;
//    }
//
//    //将排好序的数组写入文件
//    for (int i = 0; i < 10; i++) {
//        fprintf(fp, "%d\n", arrays[i]);
//    }
//
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int main() {
//    //printf("write_rand():%d\n", write_rand() );
//    
//    printf("print_file():%d\n", print_file() );
//
//    return EXIT_SUCCESS;
//}





/*
perror函数用法

    perror()函数括号内双引号括起来的在输出错误信息时将显示在错误信息的前面

fopen_s函数 w和r的区别(读和写的区别)
    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\perror_test.txt", "r");
    该文件是以读的方式打开,当该文件不存在该目录内就报错
    若将“r”改为“w” 当该文件不存在该目录内就会自动创建一个
*/

//#include"head.h"
//int main() {
//    FILE *fp;
//    rename("C:\\Users\\a\\source\\repos\\ConsoleApplication7\\perror_test.txt", "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\perror_test_1.txt");
//
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\perror_test.txt", "r");
//    if (fp==NULL) {
//        perror("AA");//报错显示为:AA: No such file or directory   
//        return -1;
//    }
//    fclose(fp);
//
//    return EXIT_SUCCESS;
//}






/*

字符
    fgetc---fputc
字符串
    fgets---fputs
默认处理文本文件
    fprintf--fscanf


fwrite()函数:            既可以处理文本,又可以处理二进制
    写出数据到文件中。多用于处理二进制文件。
    size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
        参1:代写出的数据的地址
        参2:待写出数据的大小
        参3:写出的个数        ---参2  乘  参3  =  写出数据的总大小
        参4:文件指针(写出到哪个文件)
        返回值:
            成功:永远是参3的值        --通常将参2传1,将参三传实际写出字节数。
            失败:0(失败返回0)

fread()函数:            既可以处理文本,又可以处理二进制
    从文件fp中读出数据
    size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
        参1:读取到的数据的存储位置
        参2:一次读取的字节数
        参3:读取的次数        ---参2  乘  参3  =  读出数据的总大小
        参4:文件指针(从哪个文件读取)
        返回值:
            成功:永远是参3的值        --通常将参2传1,将参三传欲读出字节数。
            失败:0(失败返回0)
        返回值为0时有两种情况:
            1.读失败
            2.本次读到了文件结尾---》feof(fp)为真---》到达文件结尾 

*/



/*
fwrite()函数
*/

//#include"head.h"
//
//typedef struct {
//    int age;
//    char name[10];
//    int num;
//}stu_t;//使用typedef给struct n重命名为stu_t,再次使用时直接写stu_t即可,不需再写struct n
//
//int fwrite_test() {
//    stu_t stu[4] = {//创建了包含四个结构体的结构体数组
//    10,"aa",100,
//    10,"bb",100,
//    10,"cc",100,
//    10,"dd",100
//    };
//
//    //打开文件,并建立文件指针
//    FILE *fp;
//    //两种文件路径的书写方式均可。
//    //fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fwrite_test", "wb");
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fwrite_test", "wb");
//    if (!fp) {
//        perror("fopen error");
//        return -1;
//    }
//    //使用fwrite函数并将返回值赋给ret
//    int ret = fwrite(stu, 1, sizeof(stu_t) * 4, fp);//*4表示写出4个结构体
//    if (ret == 0) {
//        perror("fwrite error");
//        return -1;
//    }
//    //打印该函数的返回值====》参数三的值
//    printf("%d \n", ret);
//    //关闭文件
//    fclose(fp);
//}
//
//int fread_test() {
//    //打开文件,并建立文件指针
//    FILE *fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fwrite_test", "rb");
//    if (!fp) {
//        perror("fopen error");
//        return -1;
//    }
//
//    stu_t stu[10] = { 0 };
//    int b = 1, i = 0;
//
//    ////每次读取一个结构体
//    //while (b) {
//    //    b = fread(&stu[i], 1, sizeof(stu_t), fp);
//    //    ////调试时使用b,来观察函数是否执行成功,或者是否到了结尾。
//    //    //printf("b=%d \n", b);
//    //    //用来解决会打印多一次的问题,原因为:上面b的值为0时,表示本次读取到了文件末尾,但是还没有到while判断的时候,紧接着打印就会打印多一组错误的数据
//    //    if (b==0) {
//    //        break;
//    //    }
//    //    printf("%d,%s,%d \n", stu[i].age, stu[i].name, stu[i].num);
//    //    i++;
//    //}
//
//    ////一次性把4个结构体都读取了
//    b = fread(&stu[i], 1, sizeof(stu_t)*4, fp);
//    while (i<10) {
//        printf("%d,%s,%d \n", stu[i].age, stu[i].name, stu[i].num);
//        i++;
//        if (stu[i].age == 0 ) {
//            break;
//        }
//    }
//}
//
//int main() {
//    fwrite_test();
//    fread_test();
//    return EXIT_SUCCESS;
//}



/*
练习:大文件拷贝
    已知一个任意类型的文件,对该文件复制,产生一个相同的新文件。
    1.打开两个文件,一个“r”,另一个“w”
    2.从r中fread,fwrite到w文件中
    3.判断到达文件结尾 终止。
    4.关闭
*/

//#include"head.h"
//
//int main() {
//    ////文本文件
//    ////建立要读取的文件的指针
//    //FILE *fp_r;
//    //fopen_s(&fp_r, "C:\\Users\\a\\Desktop\\7788记录.txt", "r");
//    //if (!fp_r) {
//    //    perror("fopen error fp_r");
//    //    return -1;
//    //}
//
//    //二进制文件
//    //建立要读取的文件的指针
//    FILE *fp_r;
//    fopen_s(&fp_r, "C:\\Users\\a\\Desktop\\PQArt_Sim_x64_Setup_5372.exe", "rb");
//    if (!fp_r) {
//        perror("fopen error fp_r");
//        return -1;
//    }
//
//    //**********************************************************
//
//    ////文本文件
//    ////建立保存的文件的指针
//    //FILE *fp_w;
//    //fopen_s(&fp_w, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\7788记录.txt", "w+");
//    //if (!fp_w) {
//    //    perror("fopen error fp_w");
//    //    return -1;
//    //}
//
//    //二进制文件
//    //建立保存的文件的指针
//    FILE *fp_w;
//    fopen_s(&fp_w, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\PQArt_Sim_x64_Setup_5372.exe", "wb");
//    if (!fp_w) {
//        perror("fopen error fp_w");
//        return -1;
//    }
//
//    //将文件读进内存,再保存到指定的位置
//    double buf[1024] ;
//    int flag_r = 1;
//    int flag_w = 1;
//    while ( flag_r ) {
//        memset(buf, 0, 1024);
//        flag_r = fread(buf, 1, sizeof(buf[0])*1024, fp_r);
//        printf("flag_r:%d \n", flag_r);
//        flag_w = fwrite(buf, 1, flag_r, fp_w);
//        printf("flag_w:%d \n", flag_w);
//    }
//    fclose(fp_r);
//    fclose(fp_w);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}






/*
函数参数为结构体数组名(数组名为地址)时,大小,结构体数组的大小,结构体的大小
*/

//#include"head.h"
//
//typedef struct{
//    int a:5;
//    int b:5;
//}int_double;
//
//void print_sizeof_struct(int_double *p) {
//    printf("p:%d \n", sizeof(p));
//}
//
//int main() {
//    int_double a[10] ;
//
//    printf("int_double:%d \n", sizeof(int_double ));
//    printf("a[0]:%d \n", sizeof(a[0]));
//    printf("a:%d \n", sizeof(a));
//
//    print_sizeof_struct( a );
//
//    return EXIT_SUCCESS;
//}




/*
随机位置读:
    
    文件读写指针:在一个文件内只有一个。

    fseek():文件读写指针位置的修改
        int fseek(FILE *stream,long offset,int whence);
            参1:文件
            参2:偏移量(矢量:+向后        -向前)单位为字节
            参3:    
                SEEK_SET:文件开头位置
                SEEK_CUR:当前位置
                SEEK_END:文件结尾位置
        返回值:
            成功:0
            失败:-1

    ftell():获取文件读写指针位置
        long ftell(FILE *stream);
        返回:从文件当前读写位置(读写指针所在位置)到起始位置的偏移量
        借助ftell+fseek(SEEK_END);来获取文件内大小

    rewind():回卷文件读写指针(将读写指针移动到起始位置)
        void rewind(FILE *stream);
        
        
        
*/


/*


//    stu_t stu[4] = {//创建了包含四个结构体的结构体数组
//    10,"aa",100,
//    10,"bb",100,
//    10,"cc",100,
//    10,"dd",100
//    };

*/

//#include"head.h"
//
//typedef struct {
//    int age;
//    char name[10];
//    int num;
//}stu_t;
//
//int main() {
//    FILE *fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fwrite_test", "rb+");
//
//    //将文件读取指针移动到文件末尾
//    int flag_fseek = fseek(fp, 0, SEEK_END);
//    if (flag_fseek) {
//        perror("fseek ");
//        return -1;
//    }
//
//    //此时文件读写指针在文件末尾,可以打印从这里到起始位置的偏移量            即整个文件大小
//    printf("ftell:%d \n", ftell(fp));
//
//    //回卷文件读写指针
//    rewind(fp);
//    //创建缓存变量
//    stu_t stu[10];
//    //读取一个结构体到缓存变量
//    fread(stu, 1, sizeof(stu[0]), fp);
//    //打印被赋值后的缓存变量的值
//    printf("%d   %s   %d   \n", stu[0].age, stu[0].name, stu[0].num);
//    
//    //将文件读取指针移动到文件开头,再向后移动一个结构体的位置
//    flag_fseek = fseek(fp, sizeof(stu[0]), SEEK_SET);
//    //读取一个结构体到缓存变量
//    fread(stu, 1, sizeof(stu[0]), fp);
//    //打印被赋值后的缓存变量的值
//    printf("%d   %s   %d   \n", stu[0].age, stu[0].name, stu[0].num);
//
//    return EXIT_SUCCESS;
//}



/*
fputs()函数:
fgets()函数:

*/

//#include"head.h"
//int main() {
//    FILE *fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fputs_fgets.txt", "w+");
//    
//    //返回0表示成功
//    int ret = fputs("11111", fp);
//    printf("ret 1:%d \n", ret);
//
//    ret = fputs("22222", fp);
//    printf("ret 2:%d \n", ret);
//
//    ret = fputs("33333", fp);
//    printf("ret 3:%d \n", ret);
//
//    //创建缓存变量
//    char buf[1024] = { 0 };
//    //将文件读写指针往后移动
//    fseek(fp, 5, SEEK_SET);
//    char *ptr = fgets(buf, 1024, fp);
//    if (ptr==NULL) {
//        printf("ptr==NULL \n");
//    }
//    printf("ptr:%s \n",ptr);
//    printf("buf:%s \n",buf);
//    
//    //将文件读写指针往后移动
//    fseek(fp, 5*2, SEEK_SET);
//    ptr = fgets(buf, 1024, fp);
//    if (ptr == NULL) {
//        printf("ptr==NULL \n");
//    }
//    printf("ptr:%s \n", ptr);
//    printf("buf:%s \n", buf);
//
//    //将文件读写指针回卷到起始位置
//    rewind(fp);
//    ptr = fgets(buf, 1024, fp);
//    if (ptr == NULL) {
//        printf("ptr==NULL \n");
//    }
//    printf("ptr:%s \n", ptr);
//    printf("buf:%s \n", buf);
//
//    return EXIT_SUCCESS;
//}






/*
Linux和Windows文件区别:
    1.对于二进制文件操作:
        windows:使用“b”
        Linux:二进制和文本没有区别
    2.文本文件:
        windows:
            读取文件时会把\r\n转换为\n
            写入文件时会把\n转换为\r\n
        Linux:
            回车=换行
    3.对文件指针:
        先写后读:windows和linux效果一致
        先读后写:////////////经过测试 该问题已修复////////////
            Linux无需修改。
            windows下需要在写操作之前,使用fseek(fp,0,SEEK_CUR),来获取文件读写指针使之生效

*/


//#include"head.h"
//int main() {
//    FILE *fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fputs_fgets.txt", "w+");
//
//    //返回0表示成功
//    int ret = fputs("11111", fp);
//    printf("ret 1:%d \n", ret);
//
//    ret = fputs("22222", fp);
//    printf("ret 2:%d \n", ret);
//
//    ret = fputs("33333", fp);
//    printf("ret 3:%d \n", ret);
//
//    //先写后读            没毛病,应该是读出来AAAAA33333
//    //创建缓存变量
//    char buf[1024] = { 0 };
//    //将文件读写指针往后移动
//    fseek(fp, 5, SEEK_SET);
//    ret = fputs("AAAAA", fp);
//    fseek(fp, 5, SEEK_SET);
//    char *ptr = fgets(buf, 1024, fp);
//    if (ptr == NULL) {
//        printf("ptr==NULL \n");
//    }
//    printf("ptr:%s \n", ptr);
//
//
//    ////先读后写            不加SEEK_CUR        读到文件末尾了,再增加AAAAA应该为末尾增加,但是没有
//    ////将文件读写指针往后移动
//    //fseek(fp, 5 * 2, SEEK_SET);
//    //ptr = fgets(buf, 1024, fp);
//    //printf("ptr:%s \n", ptr);
//    //if (ptr == NULL) {
//    //    printf("ptr==NULL \n");
//    //}
//    //ret = fputs("AAAAA", fp);
//
//    //先读后写            加SEEK_CUR
//    //将文件读写指针往后移动
//    fseek(fp, 5 * 2, SEEK_SET);
//    ptr = fgets(buf, 1024, fp);
//    printf("ptr:%s \n", ptr);
//    if (ptr == NULL) {
//        printf("ptr==NULL \n");
//    }
//    fseek(fp, 0, SEEK_CUR);
//    ret = fputs("AAAAA", fp);
//
//
//    fclose(fp);
//    return EXIT_SUCCESS;
//}




/*
获取文件状态:
    打开文件,对于系统而言,系统资源消耗过大。
    int stat(const char *patch,struct stat *buf);
    需要头文件:<sys/types.h>        <sys/stat.h>
        参1:访问文件的路径
        参2:文件属性结构体
        返回值:成功:0        失败:-1
    
    
    
    
*/

/*
获取文件属性-大小

struct stat{
    dev_t st dev;    //文件的设备编号
    ino_t st ino;    //节点
    ......            //文件的类型和存取的权限
                    //连接到该文件的硬连接数目,刚健立的文件值为1
                    //用户ID
                    //组ID
                    //(设备类型)若此文件为设备文件,则为其设备编号
                    //文件字节数(文件大小)
                    //块大小(文件系统的i/o缓冲区大小)
                    //块数
                    //最后一次访问时间
                    //最后一次修改时间
                    //最后一次改变时间(指属性)
}

*/

/*
获取文件大小stat结构体不打开文件获取大小            开销较小
*/
//#include"head.h"
//#include<sys/types.h>
//#include<sys/stat.h>
//int main() {
//    struct stat buf;
//    //传出参数:在函数调用结束时,充当函数返回值。
//    int ret = stat("C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fputs_fgets.txt", &buf);
//    //不打开文件获取文件大小
//    printf("文件大小为:%d 字节 \n", buf.st_size);
//    return EXIT_SUCCESS;
//}


/*
获取文件大小 文件指针方式            开销较大
*/
//#include"head.h"
//int main() {
//    FILE *fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fputs_fgets.txt", "r+");
//    fseek(fp, 0, SEEK_END);
//    int len = ftell(fp);
//    printf("文件大小为:%d 字节 \n", len );
//    fclose(fp);
//
//    return EXIT_SUCCESS;
//}




/*
删除、重命名文件:
    int remove(const char *pathname);删除文件
        
    int rename(const char *oldpath,const char *newpath);重命名


缓冲区刷新:
    缓冲区:内存中的一块区域,操作系统创建,类似于用户创建的char buf[1024];
        一次物理访问磁盘过程中,尽可能多的获取磁盘数据,保存在内存中。


            //写给屏幕的数据,都是先存缓冲区中,由缓冲区一次性刷新到物流设备(屏幕)。
            标准输出:        屏幕---stdout---stdout缓冲区         
            //从键盘读取的数据,直接读到缓冲区,由缓冲区给程序提供数据。
            标准输入:        键盘---stdin---stdin缓冲区

        预读入,缓输出
            行缓冲:printf() 遇到\n就会将缓冲区中的数据刷新到物理设备上
            全缓冲:一般指文件。缓冲区存满,数据刷新到物理设备上。
            无缓冲:perror,缓冲区中只要有数据,就立即刷新到物理设备。

            文件关闭时fclose(fp),缓冲区会被自动刷新。        
            隐式回收,关闭文件,刷新缓冲区,释放malloc

            手动刷新缓冲区:
                int fflush(FILE *stream); 
                    返回值:
                        成功:0
                        失败:-1 
*/

//#include"head.h"
//int main() {
//    FILE *fp;
//    fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fflush_test.txt", "w+");
//    char c = 0;
//    while (true) {
//        scanf_s("%c", &c);
//        if (c == ';') {
//            break;
//        }
////视频中为实时刷新到了文档中,但是实际测试为:打开txt文件显示:另一个程序正在使用此文件,进程无法访问
//        fflush(fp); 
//        fputc(c, fp);
//    }
//    //文件关闭时会自动刷新缓冲区
//    fclose(fp);
//    system("Pause");
//    return EXIT_SUCCESS;
//}




/*
共用体和联合体:
    union    test{
        char ch;
        short sh;
        int var;
    };
    联合体:
        1.内部所有成员变量地址一致,等同于整个联合体地址。
        2.联合体的大小:是内部成员变量中,最大的那个成员变量的大小。(涉及到对齐的问题,暂不讨论)
        3.修改其中任意一个成员变量的值,其他成员变量会随之修改
*/

//#include"head.h"
//
//typedef union {
//    int a;
//    char ch;
//    short sh;
//}test_t;
//
//int main() {
//    //1.内部所有成员变量地址一致,等同于整个联合体地址。
//    test_t a ;
//    printf("&a:%p \n", &a);
//    //点的优先级比取地址符的优先级高,所以先找到该元素,再取地址
//    printf("&a.a:%p \n", &a.a);
//    printf("&a.ch:%p \n", &a.ch);
//    printf("&a.sh:%p \n", &a.sh);
//
//    //2.联合体的大小:是内部成员变量中,最大的那个成员变量的大小。
//    printf("sizeof(test_t):%d \n", sizeof(test_t));
//    printf("sizeof(a):%d \n", sizeof(a));
//    printf("sizeof(a.a):%d \n", sizeof(a.a));
//    printf("sizeof(a.ch):%d \n", sizeof(a.ch));
//    printf("sizeof(a.sh):%d \n", sizeof(a.sh));
//
//    //3.修改其中任意一个成员变量的值,其他成员变量会随之修改
//    a.a = 0X87654321;
//    //此处要打印%x不然看不出来变化
//    printf("a.a:%x \n", a.a);
//    //此处要打印%x不然看不出来变化
//    printf("a.ch:%x \n", a.ch);
//    //此处要打印%x不然看不出来变化
//    printf("a.sh:%x \n", a.sh);
//
//    a.sh = 0X00;
//    printf("a.a:%x \n", a.a);
//    printf("a.ch:%x \n", a.ch);
//    printf("a.sh:%x \n", a.sh);
//
//    return EXIT_SUCCESS;
//}


/*
枚举:
    枚举常量通常是整型常量,不能是浮点数,可以是负值。
    默认初值从0开始,后续常较前一个常量+1
    可以给任意一个常量赋任意初值,后续常量较前一个常量+1

    enum color{枚举常量};
    enum color{red,green,blue,black,pink,yellow};
        
*/

//#include"head.h"
//
////enum color{red,green,blue,black };
//enum color{red=5,green,blue,black };
//
//int main() {
//
//    printf("%d \n", red);
//    printf("%d \n", green);
//    printf("%d \n", blue);
//
//    int flag = 2;
//    
//    if (flag==green) {
//        printf("green ==2 \n");
//    }
//    else {
//        printf("green !=2 \n");
//        printf("green ==%d \n",green );
//    }
//
//    return EXIT_SUCCESS;
//}




/*
读写文件与printf scanf关联:
    printf    --屏幕--标准输出
    scanf    --键盘--标准输入
    perror    --屏幕--标准错误

系统文件:
    这三个标准的函数对应三个标准的系统文件,文件有个标号
    
    标准输入    --stdin--0
    标准输出    --stdout--1
    标准错误    --stderr--2
    应用程序启动时,自动被打开,程序执行结束时自动被关闭。---结束时隐式回收

*/

//// 关闭stdout文件,则无法进行屏幕输出
//#include"head.h"
//int main() {
//    fclose(stdout);
//
//    printf("hello stdout");
//
//    return EXIT_SUCCESS;
//}



/*
文件指针和普通指针的区别:
    FILE *fp=NULL;
    借助文件操作函数来改变fp为空,野指针的状况。
    fopen();--->相当于fp=malloc();        //fopen来给指针做初始化
    操作文件:使用文件读写函数来完成。fputc,fgetc,fputs,fgets,fread,fwrite
    文件指针不能做++操作。
    
    以往其他避免野指针或空指针的的方式为:
        int *p;        int a;        p = &a ;
        int *p;        int a;        p = malloc() ;


    硬盘(也叫磁盘)上的数据不能直接访问,必须加载到内存中,才能正常访问。
    在c语言中用一个指针变量指向一个文件,这个指针称为文件指针
        //该结构体创建之后在heap堆上存储,调用fopen之后就会创建了
        //该结构体保存的是:打开的文件的描述信息
        typedef struct{            
            short level;            //缓冲区“满”或者“空”的程度
            unsigned flags            //文件状态标志
            char fd;                //文件描述符
            unsigned char hlod;        //如无缓冲区不读取字符
            short bsize;            //缓冲区大小
            unsigned char *buffer;    //数据缓冲区的位置
            unsigned ar;            //指针,当前的指向
            unsigned istemp;        //临时文件,指示器
            short token;            //用于有效性的检查
        }
    FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型,结构中含有
            文件名,文件状态和文件当前位置等信息。
    
    声明FILE结构体类型的信息包含在头文件“stdio.h”中,一般设置一个指向FILE类型
        变量的指针变量,然后通过它来引用这些FILE类型变量,通过文件指针就可以对它
        所指的文件进行各种操作。
    
    


文件分类:
    设备文件:
        屏幕、键盘、磁盘、网卡、声卡、显卡、扬声器。。。
    磁盘文件:
        文本文件:ASCII
        二进制文件:0101二进制编码


文件操作的一般步骤:
    1.打开文件 fopen
    2.对文件进行读写操作 fputc、fgetc、fputs、fgets、fread、fwrite
    3.关闭文件 fclose
    
    还有众多文件打开和关闭的函数,需要一一对应,不能乱匹配
    fopen--》fclose
    open--》close
    popen--》pclose


打开关闭文件函数:
    FILE * fopen(const char *filename,const char *mode);
        参1:待打开文件的文件名(访问路径)
        参2:文件的打开权限:
            r、r+:读的方式,文件不存在会报错。
            w、w+:写的方式打开,文件不存在会创建一个空文件,文件存在会清空并打开
            a、a+:追加方式 ...
        返回值:
            成功:返回打开文件的文件指针
            失败:NULL
    int fclose(FILE *stream);
        参1:打开文件的fp(fopen的返回值)
        返回值“
            成功:0
            失败:-1



文件访问路径:
    绝对路径:
        从系统磁盘的 根盘符开始,找到待访问的文件路径
        windows书写方法:
            1.C:\\Users\\a\\source\\repos\\ConsoleApplication7\\fwrite_test        使用转义字符\转义
            2.C:/Users/a/source/repos/ConsoleApplication7/fwrite_test        是适用于Linux
    相对路径:
        1.如果在VS环境下,编译执行,文件相对路径是指相对于ConsoleApplication7.vcxproj文件所在目录位置。
        2.如果是双击xxx.exe文件执行,文件的相对路径是相对于xxx.exe所在目录位置。(即 在哪个文件夹双击exe文件 就相对于哪个文件夹的位置)。

        fopen("test.exe","w";
        是不可以的,exe是可运行程序,内部应当有可运行的例程。直接fopen不能创建出来
        需要借助某些手段,例如 gcc 或者 vs工具 

*/




/*
绝对路径 或者 相对路径 测试!
*/

//#include"head.h"
//
//int main() {
//    FILE *fp;
//    //fopen_s(&fp, "C:\\Users\\a\\source\\repos\\ConsoleApplication7\fopen_s_test.txt", "w+");
//    //fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fopen_s_test.txt", "w+");
//    
//    //该文件为相对路径:在该文件执行的路径下新建文件
//    fopen_s(&fp, "fopen_s_test_相对路径.txt", "w+");
//    if (fp==NULL) {
//        perror("fopen error");
//        return -1;
//    }
//    fclose(fp); 
//
//    system("Pause");
//    return 0;
//}




/*
按字符写文件:fputc:
    int fputc(int ch,FILE *stream);
        参1:待写入的字符    
        参2:    打开文件的fp(fopen的返回值)
        返回值:
            成功:写入文件中的字符对应的ASCII码
            失败:-1

*/



/*
fputc练习:

使用fputc将26个英文字母写到文件中

*/

//#include"head.h"
//int main() {
//    FILE *fp;
//    //fopen函数的第二个参数,可以是一个字符串指针
//    char f_flage[] = "../../../fputc_test.txt";
//    //表示上级路径的 上级路径的 上级路径 
//    //fopen_s(&fp, "../../../fputc_test.txt", "w+");
//    fopen_s(&fp, f_flage, "w+");
//    if (fp==NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//
//    char temp = 'A';
//    int fputc_flage = 0;
//    while (true) {
//        fputc_flage = fputc(temp++, fp);
//        if (fputc_flage==-1) {
//            perror("fputc");
//            return -1;
//        }
//        fputc_flage = fputc(' ', fp);
//        if (fputc_flage==-1) {
//            perror("fputc");
//            return -1;
//
//        }
//        if (temp>'Z') {
//            break;
//        }
//    }
//
//    return EXIT_SUCCESS;
//}




/*
按字符读取文件 fgetc     一次读一个字符
    int fgetc(FILE *stream);
        参1:待读取的文件fp(fopen的返回值)
        返回值:
            成功:读到的字符对应的ASCII码
            失败:-1



    文本文件的结束标记:EOF---》-1
    为宏定义
    如果为二进制文件,那么-1就可能是文件的内容,所以需要使用feof函数

feof()函数:
    用来判断到达文件结尾。
    int feof(FILE *stream);
        参1:fopen的返回值
        返回值:
            到达文件结尾:----非0【真】
            没到达文件结尾:----0【假】
    作用:
        用来判断到达文件结尾。既可以判断文本文件,也可以判断二进制文件。 
    特性:
        想要使用feof()检测文件结束标记,必须在该函数调用之前,使用该文件函数(配合读文件函数一起使用)。
        feof()调用之前,必须有读文件函数调用,否则不起作用。

*/


//#include"head.h"
//
//int write_fputc() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fputc_test.txt", "w+");
//    if (fp==NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//
//    char temp = 'A';
//    int fputc_flage = 0;
//    while (true) {
//        fputc_flage = fputc(temp++, fp);
//            if (fputc_flage==-1) {
//                perror("fputc");
//                return -1;
//            }
//            if (temp>'Z') {
//                break;
//            }
//    }
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int read_fgetc() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fputc_test.txt", "r");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//    int temp ;
//    while (true) {
//        //多次调用fgetc时会发现 文件读取指针会自动往后挪
//        temp = fgetc(fp);
//        printf("%c", temp);
//        //该判断方式为是否等于-1,假设文章中间有-1时会判断已经到了结尾。
//        //if (temp == EOF) {
//        //    break;
//        //}
//
//        //该判断方式为判断是否到文章末尾。
//        if (feof( fp )) {
//            break;
//        }
//    }
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int main() {
//    write_fputc();
//
//    read_fgetc();
//
//    //验证EOF为-1
//    printf("%d \n", EOF);
//
//    system("Pause");
//    return 0;
//}



/*
EOF 和 feof函数
*/

//#include"head.h"
//
//int write_fputc() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fputc_test.txt", "w+");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//
//    char temp = 'A';
//    int fputc_flage = 0;
//    while (true) {
//        fputc_flage = fputc(temp++, fp);
//        if (fputc_flage == -1) {
//            perror("fputc");
//            return -1;
//        }
//        if (temp=='C') {
//            //在字符之间插入-1,后面使用EOF或者feof函数区别
//            fputc_flage = fputc(EOF, fp);
//        }
//        if (temp > 'Z') {
//            break;
//        }
//    }
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int read_fgetc_1() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fputc_test.txt", "r");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//    int temp;
//    while (true) {
//        temp = fgetc(fp);
//        printf("%c", temp);
//        if (temp == EOF) {
//            break;
//        }
//    }
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
//int read_fgetc_2() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fputc_test.txt", "r");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//    int temp;
//    while (true) {
//        temp = fgetc(fp);
//        printf("%c", temp);
//        if (feof(fp)) {
//            break;
//        }
//    }
//    fclose(fp);
//    return EXIT_SUCCESS;
//}
//
////结果两个函数执行结果一致
//int main() {
//    write_fputc();
//
//    read_fgetc_1();
//    
//    printf("\n--------------\n");
//    
//    read_fgetc_2();
//
//    system("Pause");
//    return 0;
//}


/*
5174行同样演示fputs和fgets

fgets()函数:
    获取一个字符串,以\n作为结束标记。自动添加\0。空间足够大时读取\n,空间不足时舍弃\n,但必须有\0。
    char *fgets(char *str ,int size, FILE *strea,);
        参数str:保存的字符串的缓冲变量
        参数size:指定最大读取字符串的长度(size-1)(最后结尾有\0)
        参数stream:文件指针,如果读键盘输入的字符串,固定格式为stdin
        返回值:
            成功:成功读取的字符串
            失败:NULL            读取到文件尾或者出错:NULL
        char buf[10];        hello--->hello\n\0

fputs()函数:
    写出一个字符串,如果字符串中没有\n,不会写\n。
    int fputs(const char *str,FILE *stream);
        返回值:
            成功:0
            失败:-1

*/


/*
练习:获取用户键盘输入,写入文件中

进阶版,当用户输入 :wq时退出输入
*/

//#include"head.h"
//
//int fgets_stdin(char *buf,int a) {
//    fgets(buf, a, stdin);
//    return EXIT_SUCCESS;
//}
//
//int fputs_FILE(char *buf) {
//    FILE *fp;
//    //此处有问题,第一行执行会报错fopen_s: Invalid argument,但是第二行却不会报错。
//    //分析后发现第一行的参数二的左边引号之后有一个东西,会占用一个光标移动的位,但是却看不出来是什么???bug???待定!
//    //fopen_s(&fp, "‪C:/Users/a/source/repos/ConsoleApplication7/fgets_stdin_fputs_FILE.txt","w+" );
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fgets_stdin_fputs_FILE.txt","w+" );
//    if (fp==NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//
//    fputs(buf, fp);
//    fclose(fp);
//    return EXIT_SUCCESS;
//}

////练习:获取用户键盘输入,写入文件中
//int main() {
//    char buf[10] = { 0 };
//    fgets_stdin(buf,sizeof(buf) );
//    //printf("%s \n", buf);
//    fputs_FILE(buf);
//
//    system("Pause");
//    return EXIT_SUCCESS;
//}





////进阶版,当用户输入 :wq时退出输入

//#include"head.h"
//
//int main() {
//    char buf[4096] = { 0 };
//
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fgets_stdin_fputs_FILE.txt", "w+");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//
//    while (true) {
//        fgets(buf, sizeof(buf) , stdin);
//        //strcmp函数的返回值为0时表示两个参数相等
//        if ( strcmp(buf,":wq\n")==0 ) {            
//        //当输入完成时键入输入的内容时需要按回车
//            printf("%d \n", sizeof(buf));
//            break;
//        }
//        fputs(buf, fp);
//    }
//
//    fclose(fp);
//    system("Pause");
//    return EXIT_SUCCESS;
//}













/*
强化训练:文件版四则运算
    该文件内已有几个四则运算式子,运算好结果后再次写入即可


个人的思路:
    1.拆分字符串    
        (1)sscanf
        (2)strtok
    2.匹配四则运算符
        (1)使用switch case匹配四则运算符
        (2)使用strcmp函数
        (3)找到四则运算符的ASCII,然后使用if判断
    3.将每行的字符串末尾添加\n后,保存到临时变量里面
    4.将临时变量输出并覆盖原先文件。




练习:文件版的四则运算:
    1.封装write_file函数,将四则运算表达式写入
        FILE *fp=fopen(”w“);
        fputs(”1+1\n“);
        。。。。。。
    2.封装read_file函数,将四则运算表达式读出,拆分,运算,写回。
        (1)读出
            FILE *fp =fopen(”r“);
            while(1){
                fgets(buf,sizeof(buf),fp);    //按行读取并存到buf中
            }
        (2)拆分:
            sscanf(buf,”%d%c....                    //获得运算数和运算符
        (3)根据运算符,得到运算结果
            switch(ch){
                case‘+’:
                    return a+b;
            }
        (4)拼接结果到运算式上
            sprintf(temp,“%f%c%f=%f\n”。。。        //包含带有结果的运算式
        (5)将多个带有结果的运算拼接成一个字符串
            strcat()。。。。                    //将带有结果的运算式拼接
        (6)重新打开文件,清空原有四则运算表达式,
            fclose
            fp=fopen(“w
        (7)将拼接好的字符串写入文件中
            fputs

*/


//#include"head.h"
//char buf[4096] = { 0 };
//int memory_file();
//int fopen_strtok();
//float calc(float a, float b, char tt);
//int write_file();
//
//int main() {
//    //memory_file();
//
//    fopen_strtok();
//    write_file();
//
//    return EXIT_SUCCESS;
//}
//
//int memory_file() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fopen_strtok_calc.txt", "w+");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//    fputs("1+1\n2*2\n3-2\n4/2\n10/2\n10*3\n4-2\n10+2", fp);
//    fclose(fp);
//}
//
//int fopen_strtok() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fopen_strtok_calc.txt", "r+");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//
//    char temp[4096] = { 0 };
//    char temp01[4096] = { 0 };
//    float a = 0, b = 0, c = 0;
//    char tt = '0';
//    while (true) {
//        if (fgets(temp, 4096, fp) == NULL) {
//            //perror("fgets ");
//            break;
//        }
//        sscanf_s(temp, "%f%c%f", &a, &tt, 1, &b);
//        //printf("%lf \n", a);
//        //printf("%c \n", tt);
//        //printf("%lf \n", b);
//        c = calc(a, b, tt);
//        sprintf_s(temp01, "%f%c%f=%f\n", a, tt, b, c);
//        //printf("%s \n", temp01);
//        strcat_s(buf, temp01);
//    }
//    fclose(fp);
//    //printf("%s \n", buf);
//    return EXIT_SUCCESS;
//}
//
//float calc(float a, float b, char tt) {
//    switch (tt) {
//    case '+':
//        return a + b;
//    case '-':
//        return a - b;
//    case '*':
//        return a * b;
//    case '/':
//        return a / b;
//    default:
//        break;
//    }
//    return EXIT_SUCCESS;
//}
//
//int write_file() {
//    FILE *fp;
//    fopen_s(&fp, "C:/Users/a/source/repos/ConsoleApplication7/fopen_strtok_calc.txt", "w+");
//    if (fp == NULL) {
//        perror("fopen_s");
//        return -1;
//    }
//    fputs(buf, fp);
//    fclose(fp);
//    
//    return EXIT_SUCCESS;
//}

 

 

 

 

需要使用的请拿去,记得注明出处。

 

good luck

 

posted on 2022-06-05 14:49  AnonymousJDK  阅读(51)  评论(0编辑  收藏  举报

导航