[置顶] 20160203.CCPP体系详解(0013天)

程序片段(01):数组.c+02.数组初始化语法.c
内容概要:数组

///01.数组.c
#include <stdio.h>
#include <stdlib.h>

//01.采用容器结构存储数据的要点:
// 1.必须为每个数据分配独立的存储空间
// 2.必须为每个数据分配独立的标识符(变量名称)
//02.C语言之C99语法的特点:
// 针对于VC编译器:
// 1.VC编译器分配数组的时候必须静态分配
// 静态分配:在编译时期确定数组所占据的内存尺寸(字节数)大小
// 2.数组长度必须为真常量(或常量表达式)
// 明确的数组元素个数
// 针对于GCC编译器:
// 1.GCC编译器分配数组的时候采用动态分配
// 动态分配:在执行时期确定数组所占据的内存尺寸
// 2.数组长度可以为伪常量(或变量)
// 不确定的数组元素个数(程序执行时期知道)
//03.伪常量的声明方式:
// 在原始变量的前面添加一个伪常量标识前缀("const")
//04.关于常量的透彻分析:
// 伪常量:const int num = 1;
// 1.具备内存实体:
// 不允许直接进行修改,但允许间接进行修改
// 2.静态分配:
// 在编译时期确定伪常量的值
// 真常量:#define NUM 1
// 1.不具备内存实体:
// 既不允许直接修改,也不允许间接修改
// 2.预编译决定:
// 在预编译时期就已经决定了将宏名为了常量(整型,实型,字符型,字符串型)
int main01(void)
{
    const int num = 10;//常量表达式{但是该常量表达式的常量值可以经过间接改变,所以是伪常量}-->有内存实体
    #define NUM 1//真常量{一旦确定了真常量的值,就不允许修改真常量的数据}-->无内存实体

    //int a[num];//编译的时候确定大小,静态分配,VC不支持
    int a[NUM];
    //VC必须静态分配,GCC可以动态分配

    system("pause");
}

//05.关于数组使用的要点总结:
// 1.静态数组分配方式:
// (1).int a[5] = {1, 2, 3, 4, 5};//数组元素的类型:int;数组整体的名称:a;数组元素的个数:5;
// 数组元素的具体数据:1, 2, 3, 4, 5
// (2),静态分配:在编译时期就已经确定了数组所占用的内存地址以及内存尺寸(首地址+尺寸)
// 2.分配方式组成分析:
// (1).int:表明数组当中所存储的每个元素的类型
// (2).a:表示数组整体的名称(数组名)
// 数组名的本质是一个常量指针(伪常量)
// (3).{}:代码块儿分配方式,只能用于声明数组的同时进行使用(既可以局部初始化也可以全部初始化)
// 3.sizeof:
// (1).是一个关键字,而不是一个函数
// (2).如果传递的是数组名,那么求取的内存尺寸是数组整体所占用的内存尺寸(区分数组整体和数组元素)
// 4.%p和%d的使用意义:
// (1).所以数据在内存当中的存储实质都一样,都是二进制数据
// (2).格式控制符只是决定了不同的解析方式:
// %d:内存数据按照有符号十进制(signed int)类型进行解析
// %p:内存数据按照指针意义进行解析
// 5.数组元素以及数组元素的地址:
// a[i]:a[i]表示数组元素的名称,直接写数组元素的名称,相当于访问该数组元素本身(数据)
// 好比叫一个人的名字,目的就是为了这个人知道
// &a[i]:&表示根据变量的名称(内存实体)获取该变量的地址
// 变量的名称:其实就是内存实体的别名(区分:(变量:内存实体)-->(变量名称:变量别名))
// 统称:变量(统一)-->具称:变量别名(唯一)
// 说明:中括号"[]"的优先级高于取内存实体地址符"&"的优先级
int main02(void)
{
    //0,1,2,3,4
    int a[5] = { 1,2,3,4,5 };//a:数组名称,a代表该数组的内存首地址

    printf("%d \n", sizeof(a));//sizeof(a):用于获取数组所占用的真实内存尺寸(字节大小)
    printf("%p \n", a);//数组的内存首地址
    for (int i = 0; i < 5; i++)
    {
        printf("%d, %p \n", a[i], &a[i]);//i:索引;&:符号表示获取变量的内存首地址
    }

    system("pause");
}

//06.数组元素本身(内存实体)和数组元素地址(内存实体地址)
// 1.数组元素地址(内存实体地址)
// &a[i],a+i:数组默认从第0个开始进行索引划分(数组元素(内存实体)的标识符:索引)
// 2.数组元素本身(内存实体):
// a[i],*(&a[i]),*(a+i)
int main03(void)
{
    //数组声明语法:double a[10];数组元素的类型 数组整体的名称[数组元素的个数];
    double a[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };

    printf("%d \n", sizeof(a));//10*8=80
    for (int i = 0; i < 10; i++)
    {
        //&a[i], a + i;//代表数组第i个元素的内存实体地址,等价关系a+i(与类型密切相关)//以0作为开头
        //a + (i - 1)*sizeof(double);//以1作为开头
        //*号表示根据内存实体的地址获取内存实体本身(数据内容)
        //a[i], *(&a[i]), *(a + i);//效果等价
        printf("%lf, %lf, %lf, %p, %p \n", a[i], *(&a[i]), *(a + i), &a[i], a + i);//下标,索引
    }

    system("pause");
}
///02.数组初始化语法.c
#include <stdio.h>
#include <stdlib.h>

//01.数组的初始化方式:
// 标准方式:
// int a[5] = {1, 2, 3, 4, 5};
// 数组元素的类型 数组整体的名称[数组元素的指明个数] = {静态初始化的静态数据};
// 简化方式:
// itn a[] = {1, 2, 3, 4, 5};
// 注意事项:
// 1.C/C++当中的静态数组必须进行静态初始化才能进行使用,Java当中的静态数组会进行默认初始化
// 大括号:{}就是表明静态初始化
// 2.数组的声明必须明确两点:数组元素的数据类型+数组元素的元素个数-->才能确定数组整体尺寸(内存字节数)
// 3.赋值特点:
// (1).大括号这种静态初始化方式,只能适用于声明数组的状态下(声明并定义的情况之下)
// (2).统一赋值与指明赋值特点:
// 统一赋值:{0}
// 指明赋值:
// 完全赋值:
// {1, 2, 3, 4, 5}
// 前置局部:
// {1, 2, 3}-->后面默认被编译器初始化为0,只有当前面进行了指明初始化的情况,后面才会进行默认初始化为0的操作
// 4.访问特点:
// 访问数组整体的内部某个元素本身(内存实体本身),不会出错
// 访问数组整体的外部某个元素本身(内存实体本身),可能出错,可能不出错(关键是看系统是否为该内存实体分配了使用权限)
int main04(void)
{
    //int a[10] = { 0 };//C/C++当中的数组必须进行初始化
    //int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//明确数组初始化元素个数,可以省略数组元素个数的声明
    //int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };//数组初始化不允许越界
    //int a[10] = { 1, 2, 3, 4 };//默认没有初始化值的数组元素都将会被默认的初始化为0
    int a[5] = { 0 };//数组必须明确其元素个数

    for (int i = 0; i < 10; i++)
    {//注意不存在长度部分的数据将会是无法预料的值,5之后的数据可能会出现问题
        printf("%d \n", a[i]);
    }

    system("pause");
}

//02.数组名称的操作:
// 1.任何指针进行加法,乘法,除法都没有任何实际意义
// 2.在同一个数组当中的不同内存实体的内存地址进行
// 减法运算具备实际意义,用于获取两个数组元素之间的元素个数差值
// 3.C语言的常规数组不能进行整体操作,元素本身(内存实体)可以进行整体操作
// 4.C语言的特殊素组(字符数组),如果以'\0'结尾,那么就是一个正常的字符串模拟
// 字符串结尾标识符必须是'\0'(字符\0)-->0或者'\0'都一样
// 字符:'\0'-->ASCII:0-->以及关键字NULL
int main05(void)
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int b[5] = { 2, 3, 4, 5, 6 };

    //a = b;//数组名称:标识数组整体的内存空间,数组名称是一个常量指针,不可以直接进行修改
    //a[1];//访问整体数组a当中的第1个元素所对应的内存实体(数据本身)
    //a + b;//C语言当中的普通数组不可以进行批量草最,只能针对于某一个元素进行批量操作
    //a < b;
    char str[5] = { 'c', 'a', 'l', 'c', NULL };   
    printf("%s \n", str);

    system("pause");
}

程序片段(02):01.数组.c+02.数组实战.c
内容概要:数组实战

///01.数组.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//01.数组越界问题分析;
// 1.采用数组名称访问内存实体的时候:
// 如果该内存实体位于数组整体当中的某个部分,那么访问正确
// 如果该内存实体位于数组整体外部的某个部分,那么访问出错
// 因为操作系统并没有为当前程序当中的数组分配该整体数组外部的内存实体的访问权限
// 2.C语言编译器的特点所导致:
// 数组不越界一定不会出错,数组越界可能会出错(编译通过但是运行不一定通过)
int main01(void)
{
    //数组越界不一定出错,但是不越界一定不会发生内存访问冲突
    int a[5] = { 1, 2, 3, 4, 5 };

    for (int i = 0; i < 10; ++i)
    {
        printf("%d \n", a[i]);//存在越界的情况,但是C语言的编译器不一定会进行报错
    }

    //当采用数组方式访问到别处内存地址所对应的内存实体(数据本身)的时候,可能会出现报错的情况:
    // 因为该内存地址在赋值之前就已经具备了一定内存实体(数据本身),不允许紧急性数组操作
    // 因为操作系统并没有为本程序分配该内存地址的使用权限
    a[102389898] = 1;

    system("pause");
}

int main02(void)
{
    int a[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };

    for (int i = 9; i > -1; --i)
    {//逆序输出数组内存实体(数据本身)
        printf("%d \n", a[i]);
    }

    system("pause");
}

int main03(void)
{
    int a[100] = { 0 };
    time_t te = 0;
    //unsigned int seed = (unsigned int)(time(&te));//获取随机数种子
    //srand(seed);//种植随机数种子
    srand((unsigned int)(time(&te)));
    for (int i = 0; i < 100; i++)
    {//循环初始化方式(随机数)
        a[i] = rand() % 300;
        printf("%d \n", a[i]);
    }

    int num = 0;
    scanf("%d", &num);
    int flag = 0;//假定找不到-->标识多数情况
    for (int i = 0; i < 100; ++i)
    if (a[num] == num)
    {
        flag = 1;//标识找到-->只要存在情况
        break;
    }
    if (flag)
        printf("找到! \n");
    else
        printf("找不到! \n");

    system("pause");
}
///02.数组实战.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//01.最简单,最无效率的极值获取方式:
// 打擂算法:极值获取以及极值在数组当中所对应的索引
int main04(void)
{
    time_t te = 0;
    srand((unsigned int)(time(&te)));//获取并终止随机数种子
    int a[20] = { 0 };
    for (int i = 0; i < 20; ++i)
    {
        a[i] = rand() % 300;//通过随机数进行数组的赋值
        printf("%d \n", a[i]);
    }

    int minValue = a[0];
    for (int i = 1; i < 20; ++i)     //打擂算法:获取极小值
        if (minValue > a[i])
            minValue = a[i];

    int maxValue = a[0];
    for (int i = 1; i < 20; i++)//打擂算法:获取极大值
        if (maxValue < a[i])
            maxValue = a[i];

    int minIndex1 = 0;
    int minValue1 = a[0];
    for (int i = 1; i < 20; i++)//打累算法:获取极小值以及极小值在数组当中所对应的索引
        if (minValue1 > a[i])
        {
            minIndex1 = i;
            minValue1 = a[i];
        }
    printf("minIndex1 = %d, minValue1 = %d \n", minIndex1, minValue1);

    system("pause");
}

//02.最简单的排序算法:
// 1.选择排序算法
// 2.时空复杂度分析:
// 时间复杂度:n平方
// 空间复杂度:1
#define EN 20
int a[EN];//C语言全局变量默认被初始化为0
int main05(void)
{
    time_t te = 0;
    srand((unsigned int)(time(&te)));//获取并种植随机数种子
    for (int i = 0; i < 20; ++i)
    {
        a[i] = rand() % 300;//给数组进行进行随机数赋值
        printf("%d \n", a[i]);
    }
    printf("\n");

    int gtIndex = 0;
    for (int i = 0; i < EN - 1; ++i)
    {
        gtIndex = i;
        for (int j = i + 1; j < EN; ++j)
            if (a[gtIndex] < a[j])
                gtIndex = j;
        if (i != gtIndex)
        {
            a[i] = a[i] ^ a[gtIndex];
            a[gtIndex] = a[i] ^ a[gtIndex];
            a[i] = a[i] ^ a[gtIndex];
        }
    }
    for (int i = 0; i < 20; ++i)
    {
        printf("%d \n", a[i]);
    }

    system("pause");
}

程序片段(03):main.c
内容概要:GccArray

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

int main()
{
    int num=10;
    scanf("%d",&num);
    int a[num];
    //GCC支持动态分配数组:因此数组的元素个数指定可以采取变量,伪常量,真常量
    //动态分配,运行的时候

    return 0;
}

程序片段(04):冒泡排序.c
内容概要:冒泡排序法

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

int main01(void)
{
    int intArr[10] = { 3, 5, 18, 9, 23, 5, 2, 1, 0, 2 };
    for (int i = 0; i < 10 - 1; ++i)
    {//冒泡法求最大值:两两临近的数据进行比较
        if (intArr[i] > intArr[i + 1])
        {
            intArr[i] = intArr[i] ^ intArr[i + 1];
            intArr[i + 1] = intArr[i] ^ intArr[i + 1];
            intArr[i] = intArr[i] ^ intArr[i + 1];
        }
    }
    printf("maxValue = %d \n", intArr[9]);

    system("pause");
}

int main02(void)
{
    int intArr[10] = { 3, 5, 18, 9, 23, 5, 2, 1, 0, 2 };
    for (int i = 0; i < 10 - 1; ++i)//外层循环,每完成一次循环,就有一个最值沉底
    {//冒泡法实现排序:重复进行相邻的两个数据比较
        for (int j = 0; j < 10 - 1 - i; ++j)//沉底的次数,决定冒到了那里
        {
            if (intArr[j] > intArr[j + 1])//沉底
            {
                intArr[j] = intArr[j] ^ intArr[j + 1];
                intArr[j + 1] = intArr[j] ^ intArr[j + 1];
                intArr[j] = intArr[j] ^ intArr[j + 1];
            }
        }
    }
    for (int i = 0; i < 10; ++i)
    {
        printf("%d \n", intArr[i]);
    }

    system("pause");
}

程序片段(05):斐波那契.c
内容概要:斐波那契数组法

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

//01.斐波那契数列:
// 1.循环实现
// 2.递归实现
// 3.(循环+栈)实现
//02.数组的使用特点:
// 模拟栈这种数据结构
// 先进后出
// 模拟队列这种数据结构
// 先进先出
//03.如何进行递归加速?
// 递归-->循环+栈:可以实现递归加速
//04.三种实现斐波那契数列方式的速度问题:
// (循环+栈)>循环>递归
int fibonacciLoop(int nItem)
{//循环实现:
    if (1 == nItem || 2 == nItem)
        return 1;
    int temp1 = 1;
    int temp2 = 1;
    int nItemValue = 0;//初始化一个常数,效率更高
    for (int i = 2; i < nItem; ++i)
    {
        nItemValue = temp1 + temp2;//存储推理结果
        temp1 = temp2;//数据往前推进
        temp2 = nItemValue;
    }

    return nItemValue;
}

int fibonacciRecursion(int nItem)
{//递归实现:
    if (1 == nItem || 2 == nItem)
        return 1;
    return fibonacciRecursion(nItem - 1) + fibonacciRecursion(nItem - 2);//关系表达式
}

int fibonacciLoopStack(int nItem)
{//(循环+栈)实现:
    int intArr[64] = { 0 };
    intArr[0] = 1;
    intArr[1] = 1;
    for (int i = 2; i < nItem; ++i)//注意数组存储特点
    {
        intArr[i] = intArr[i - 1] + intArr[i - 2];
    }

    return intArr[nItem - 1];
}

int main01(void)
{
    printf("loopResult = %d \n", fibonacciLoop(40));
    printf("recursionResult = %d \n", fibonacciRecursion(40));
    printf("loopStackResult = %d \n", fibonacciLoopStack(40));

    system("pause");
}

程序片段(06):迷宫1.c
内容概要:迷宫模拟

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

void showIntArr(int intArr[10][10])
{//显示二维数组
    printf("------------------------------ \n");
    for (int i = 0; i < 10; ++i)
    {
        for (int j = 0; j < 10; ++j)
        {
            printf("%3d", intArr[i][j]);
        }
        printf("\n");
    }
    printf("------------------------------ \n");
}

//01.数组数据的存储特点:
// 1.所有数组的数据在内存当中的存储方式都是线性的
// 2.显式的结果不同是由于不同维度的数组对内存当中的数据的解析方式不同
int main01(void)
{
    int intArr[10][10] = {//二维数组的图形化初始化方式:将二维数组当做一维数组进行看待,该一维数组当中的每个元素就是一行的数据信息
        {0, 0, 0, 2, 0, 0, 0, 0, 0, 0},
        {0, 0, 2, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 2, 2, 2, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 2, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 2, 0, 0, 0, 0, 0},
        {0, 2, 2, 0, 0, 0, 0, 0, 0, 0},
        {2, 0, 0, 0, 0, 0, 0, 2, 0, 2},
        {0, 2, 2, 0, 0, 0, 2, 2, 0, 0},
        {2, 0, 0, 2, 0, 2, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 2, 0, 2, 0, 0}
    };
    showIntArr(intArr);

    int px = 0, py = 0;//点坐标(默认:左上角(0,0)点)
    intArr[px][py] = 1;//根据点坐标修改棋盘上对应点坐标的数据实体(二维平面的数据实体修改为0)
    showIntArr(intArr);

    char ch = '\0';
    while (1)
    {
        ch = getchar();
        getchar();//吸收Enter键-->'\n'-->'\r\n':Win解析
        switch (ch)
        {
        case 'w'://按键控制
            if (px - 1 >= 0 && intArr[px][py] != 2)
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px - 1][py];
                intArr[px - 1][py] = intArr[px][py] ^ intArr[px - 1][py];
                intArr[px][py] = intArr[px][py] ^ intArr[px - 1][py];
                --px;
            }
            break;
        case 's':
            if (px + 1 <= 9 && intArr[px + 1][py] != 2)
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px + 1][py];
                intArr[px + 1][py] = intArr[px][py] ^ intArr[px + 1][py];
                intArr[px][py] = intArr[px][py] ^ intArr[px + 1][py];
                ++px;
            }
            break;
        case 'a':
            if (0 <= py - 1 && 2 != intArr[px][py - 1])
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px][py - 1];
                intArr[px][py - 1] = intArr[px][py] ^ intArr[px][py - 1];
                intArr[px][py] = intArr[px][py] ^ intArr[px][py - 1];
                --py;
            }
            break;
        case 'd':
            if (9 >= intArr[px][py + 1] && 2 != intArr[px][py + 1])
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px][py + 1];
                intArr[px][py + 1] = intArr[px][py] ^ intArr[px][py + 1];
                intArr[px][py] = intArr[px][py] ^ intArr[px][py + 1];
                ++py;
            }
            break;
        }
        showIntArr(intArr);
    }

    system("pause");
} 

程序片段(07):二分查找法.c
内容概要:二分查找法以及拉格朗日插值查找

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

//01.二分查找法以及二分查找法的变形:
// 1.前提条件:待查找的数组当中的数据必须有序
// 最好是顺序排列的(从小到大进行排列)
// 2.二分查找以及拉格朗日查找:
// 拉格朗日查找用于二分查找的加速模式
#define N 1024
int binarySearch(int intArr[N], int value)
{//二分查找法
    int minIndex = 0;
    int maxIndex = N - 1;
    int midIndex = 0;
    while (minIndex <= maxIndex)
    {
        midIndex = (minIndex + maxIndex) / 2;
        if (value == intArr[midIndex])
            return midIndex;
        else if (value < intArr[midIndex])
            maxIndex = --midIndex;
        else
            minIndex = ++minIndex;
    }

    return -1;
}

int lagrangeSearch(int intArr[N], int value)
{//拉格朗日查找法
    int minIndex = 0;
    int maxIndex = N - 1;
    //int midIndex = 0;
    int tempIndex = 0;
    while (minIndex <= maxIndex)
    {
        //midIndex = (minIndex + maxIndex) / 2;
        //midIndex = minIndex + (maxIndex - minIndex) / 2;
        tempIndex = minIndex + (value - intArr[minIndex]) / (intArr[maxIndex] - intArr[minIndex]);//二分查找加速
        if (value == intArr[tempIndex])
            return tempIndex;
        else if (value < intArr[tempIndex])
            maxIndex = --tempIndex;
        else
            minIndex = ++tempIndex;
    }

    return -1;
}

int main01(void)
{
    int intArr[1024] = { 0 };
    for (int i = 0; i < 1024; ++i)
        intArr[i] = i;
    int value = 0;
    scanf("%d", &value);
    printf("valueIndex = %d \n", binarySearch(intArr, value));
    printf("valueIndex = %d \n", lagrangeSearch(intArr, value));

    system("pause");
}

程序片段(08):插入排序法.c
内容概要:插入排序法

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

int main01(void)
{//插值法也要求数据必须有序
    int intArr[10] = { 1, 2, 3, 4, 6, 7, 8, 9, 10, 5 };

    int tempIndex = 9;
    int tempValue = intArr[9];
    while (tempIndex > 0 && intArr[tempIndex - 1] > tempValue)//从后往前进行插值
    {   //tempIndex>0:由于要让索引-1,但是索引-1之后必须>=0因此索引必须>=1
        //当此循环退出的时候,退出时所在的索引其实就是刚好需要进行插值的索引位置
        intArr[tempIndex] = intArr[tempIndex - 1];
        --tempIndex;
    }
    intArr[tempIndex] = tempValue;

    for (int i = 0; i < 10; ++i)
        printf("%3d", intArr[i]);

    system("pause");
}

#define EN 10
void insertSort(int intArr[EN])
{
    int tempIndex = 0;
    int tempValue = 0;
    //01.插值排序法说明:
    // int i = 1:
    // 当元素个数为1的时候,不需要插值排序算法
    // 从1开始才能便于进行插值操作intArr[index-1]=intArr[index]
    // i < 10:
    // 从第一个元素开始,到最后一个元素都需要进行插值排序检测
    // 注:忽略掉单个元素的数组,因为单个元素不存在插值排序
    // tempIndex > 0:(可能插值移位的最大范围)
    // 能够进行插值移位的前提
    // intArr[tempIndex - 1] > tempValue:(可能插值移位的最小范围)
    // 只要当前索引的前一个索引所对应的值大于待插入的值
    // 就有必要执行插入操作
    for (int i = 1; i < 10; ++i)
    {
        tempIndex = i;
        tempValue = intArr[i];
        while (tempIndex > 0 && intArr[tempIndex - 1] > tempValue)
        {
            intArr[tempIndex] = intArr[tempIndex - 1];
            --tempIndex;
        }
        intArr[tempIndex] = tempValue;
    }
}

int main02(void)
{
    int intArr[EN] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
    insertSort(intArr);
    for (int i = 0; i < EN; ++i)
    {
        printf("%3d", intArr[i]);
    }

    system("pause");
}

程序片段(09):开房.c
内容概要:开房数据检索-硬盘模式

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

char resourcesPath[256] = "D:\\Resource\\TestData\\DB\\KaiFang.txt";
char targetWritePath[256] = { 0 };

void selectResultWriteToTargetFile(char nameStr[256])
{
    sprintf(targetWritePath, "D:\\Resource\\TestData\\Test\\%s.txt", nameStr);
    FILE *frp = fopen(resourcesPath, "r");//以读取模式打开一个文件(硬盘直接读取模式)
    FILE *fwp = fopen(targetWritePath, "w");//以写入模式打开一个文件(硬盘直接写入模式)
    if (NULL == frp && NULL == fwp)
    {
        printf("建立文件指针失败! \n");
        return;
    }

    while(!feof(frp))//feof();到了文件读取的末尾返回真,没有到文件读取的末尾返回假
    {//只要没有到达文件读取的末尾,就继续进行硬盘文件读取操作
        char readStr[1024] = { 0 };
        fgets(readStr, 1024, frp);//硬盘模式读取一行数据(以换行符作为读取模式结束,并且长度仅限为1024)读取条件限制
        char *tempStr = strstr(readStr, nameStr);
        if (NULL != tempStr)
        {
            puts(readStr);//打印检索到的数据行
            fputs(readStr, fwp);//硬盘模式写入到指定文件
        }
    }
    fclose(fwp);//关闭文件写入流
    fclose(frp);//关闭文件读取流
}

int main01(void)
{
    char nameStr[256] = { 0 };
    scanf("%s", nameStr);
    printf("您要查询人的姓名是:%s \n", nameStr);

    time_t start = 0, end = 0;
    time(&start);
    selectResultWriteToTargetFile(nameStr);
    time(&end);
    printf("查询总计话费了%lf秒 \n", difftime(end, start));
    system(targetWritePath);

    system("pause");
}

程序片段(10):二维数组.c
内容概要:二维数组

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

//01.二维数组:
// 1.二维数组的内存存储原理:
// 所有数组,无论一维数组,二维数组,多维数组,在内存当中的
// 存储实质都是采取的连续存储方式
// 2.二维数组的规律赋值方式:
// 先进行行遍历,在进行列遍历,再逐个进行逐个数组元素的具体赋值操作
// 3.如何求取任何数组的内存尺寸?
// 都是采用sizeof();关键字进行的求取
int main01(void)
{
    int a[5][5];
    //1, 2, 3, 4, 5, 6, 7, 8, 9, 10:总共25个数组元素
    printf("%d \n", sizeof(a));//sizeof(数组名);-->求取数组整体的内存尺寸5*5*4
    printf("%p \n", a);

    int num = 1;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            //a[i][j] = num;
            //++num;
            //printf("%4d", a[i][j]);
            printf("%4d", a[i][j] = num++);//复合语句
        }
    }

    system("pause");
}

//02.二维数组知识详解:
// 1.初始化方式:
// 统一初始化:
// int a[5][4] = {0};-->巧用0
// 前置初始化:
// int a[5][4] = {1}-->特用除0以外的数字
// 注:
// 1.统一初始化方式的实质还是前置初始化方式,由于采用特殊的数字
// 0进行初始化,所以整体被统一的初始化为了0
// 2.所有数组的初始化方式特点:
// 只要数组当中前置元素有数字前置初始化,那么后面的数组元素
// 本身都会被默认的初始化为0
// 2.多维数组的特殊初始化方式:
// 多维数组转化为低维数组进行初始化
// int a[5][4] = {
// {1, 2},
// {1, 2, 3}
// };
// 3.确定数组内存尺寸的两大要素:
// 数组元素个数+数组元素尺寸
// 注:维度的省略情况分析:自动推演
// 一维数组的一维可以省略
// 二维数组的一维不可以省略
// 三维数组的二维不可以省略
int main02(void)
{
    //int a[5][4] = { 1 };//全部初始化为0
    //printf("%p \n", a);
    //int a[5][4] = { 1, 2, 3, 4, 5 };//数组的前面赋值,后面赋值为0,默认是一行一行的进行赋值操作
    //int a[5][4] = { {1, 2, 3, 4}, {1, 2} };//二维数组的初始化方式
    //int a[5][4] = {0};//全部初始化为0
    int a[5][4];//解释:5个一维数组,每个一维数组当中存储有4个数组元素
    int b[2][4] = { {1,2},{3,4} };//第一个名曲有几个一维数组,可以进行忽略
    //行坐标可以进行忽略,但是列坐标不可以进行忽略
    int num = 1;
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            b[i][j] = num++;
        }
    }
    printf("\n\n");
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            printf("%4d", b[i][j]);
        }
    }

    system("pause");
}

//03.二维数组的线性初始化方式:
// 奥数规律方式
// 元素个数+求模(变化慢)+求余(变化快)+被除数是(列数)
int mai03n(void)
{
    int intArrArr[3][4];
    //规律初始化方式:
    // 00 0 01 1 02 2 03 3
    // 10 4 11 5 12 6 13 7
    // 20 8 21 9 22 10 23 11
    for (int i = 0; i < 12; ++i)//i:决定元素个数
    {
        intArrArr[i / 4][i % 4] = i;//行:变化慢;列:变化快
    }
    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            printf("%3d", intArrArr[i][j]);
        }
        printf("\n");
    }

    system("pause");
}

程序片段(11):迷宫初步.c+迷宫进阶.c
内容概要:迷宫AI

///迷宫初步.c
#include <stdio.h>
#include <stdlib.h>

//01.关于维度与数组的联系:
// 零维度:点
// 1.数组元素
// 2.没有方向
// 一维度:线
// 1.一维数组
// 2.向右方向
// 二维度:面
// 1.二维数组
// 2.上下左右
// 三维度:立体
// 1.三维数组
// 2.上下左右前后
// 多维度:慢慢想
// 1.高维数组
// 2.慢慢想
// 注:时间(变化)+空间(三维)
//02.所有数组的内存存储特点:
// 都是采取线性的初始方式,也就是连续存储的方式
// 只是由于计算机对于数组的解析方式的不同,所以产生了不同的维度效果
//03.迷宫矩阵的组成特点分析:
// 1.二维平面的迷宫矩阵由二维整型数组进行模拟
// 2.该二微整型数组的组成元素特点分析:
// 数字0:代表通道
// 数字2:代表墙壁
// 数字1:代表位置
// 3.移动点和结束点模拟移动:
// 移动点:(startPointX, startPointY);
// 结束点:(endPointX, endPointY);
int intArrArrMaze[5][5] = {
    { 0, 0, 2, 2, 2 },
    { 2, 0, 0, 0, 2 },
    { 2, 0, 0, 0, 2 },
    { 2, 0, 0, 0, 2 },
    { 2, 0, 0, 0, 0 },
};
int endPointX = 4, endPointY = 4;//终止点

int visitMaze(int startPointX, int startPointY);

int main(void)
{
    printf("显示迷宫 \n");
    printf("-------------------------------------- \n");
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            printf("%3d", intArrArrMaze[i][j]);
        }
        printf("\n");
    }

    int startPointX = 0, startPointY = 0;//起始点
    if (0 == visitMaze(startPointX, startPointY))
    {
        printf("迷宫没有出口 \n");
    }
    else
    {
        printf("显示路径 \n");
        for (int i = 0; i < 5; ++i)
        {
            for (int j = 0; j < 5; ++j)
            {
                if (2 == intArrArrMaze[i][j])
                    printf("█");
                else if (1 == intArrArrMaze[i][j])
                    printf("◇");
                else
                    printf(" ");
            }
            printf("\n");
        }
    }

    system("pause");
}

//04.该函数的作用功能作用分析:
// 1.函数整体作用:
// 通过递归调用方式判定迷宫是否有出口?
// 如果走到终点,那么就含有出口;如果没能走到出口,那么就没有出口!
// 2.函数局部作用:
// 每走动一次,都需要判定是否到达迷宫终点
// 3.参数说明:
// 形参值:
// 整体意义:起始点
// 局部意义:将要走动的点-->试探点
// 返回值:
// 整体意义:是否能够走出迷宫
// 局部意义:判断是否完成了一条路线
int visitMaze(int startPointX, int startPointY)
{
    int success = 0;//标识迷宫是否完成走出状态
    int movePointX = startPointX;//通过起始点初始化移动点
    int movePointY = startPointY;
    intArrArrMaze[movePointX][movePointY] = 3;//标识该点的起始状态:
    if (endPointX == movePointX && endPointY == movePointY)
        return success = 1;//标识成功的走出状态
    if (1 != success && 5 > movePointY + 1 && 2 > intArrArrMaze[movePointX][movePointY + 1]) visitMaze(movePointX, movePointY + 1);
    if (1 != success && 5 > movePointX + 1 && 2 > intArrArrMaze[movePointX + 1][movePointY]) visitMaze(movePointX + 1, movePointY);
    if (1 != success && -1 < movePointY - 1 && 2 > intArrArrMaze[movePointX][movePointY - 1]) visitMaze(movePointX, movePointY - 1);
    if (1 != success && -1 < movePointY - 1 && 2 >  intArrArrMaze[movePointX - 1][movePointY]) visitMaze(movePointX- 1, movePointY);
    if (1 != success)//标识改点的回溯状态:该点走过,但是没有走成功,因此将该点重新值置为0
        intArrArrMaze[movePointX][movePointY] = 0;

    return success;
}
///迷宫进阶.c
#include <stdio.h>
#include <stdlib.h>

//数据层(Data):存储数据
int intArrArrMazeY[10][10] = {//原始迷宫
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 },
    { 2, 2, 2, 0, 0, 2, 0, 0, 0, 0 },
    { 0, 0, 2, 0, 0, 0, 2, 0, 2, 2 },
    { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 2, 0, 0, 0, 2, 0, 2 },
    { 0, 0, 0, 0, 2, 0, 0, 2, 0, 0 },
    { 0, 0, 0, 0, 0, 2, 0, 2, 2, 0 },
    { 0, 0, 0, 0, 0, 0, 2, 2, 0, 0 }
};
int intArrArrMazeC[10][10] = {//测试迷宫
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 },
    { 2, 2, 2, 0, 0, 2, 0, 0, 0, 0 },
    { 0, 0, 2, 0, 0, 0, 2, 0, 2, 2 },
    { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 2, 0, 0, 0, 2, 0, 2 },
    { 0, 0, 0, 0, 2, 0, 0, 2, 0, 0 },
    { 0, 0, 0, 0, 0, 2, 0, 2, 2, 0 },
    { 0, 0, 0, 0, 0, 0, 2, 2, 0, 0 }
};
int endPointX = 9, endPointY = 9;
int countCiNum = 1;

//视图层(View):显示数据
void showMaze(int intArrArrMaze[10][10])
{
    printf("%d------------------------------ \n", countCiNum++);
    for (int i = 0; i < 10; ++i)
    {
        for (int j = 0; j < 10; ++j)
        {
            printf("%2d", intArrArrMaze[i][j]);
        }
        printf("\n");
    }
}

//控制层(Controller):数据操作
void operateMaze(char direction, int startPointX, int startPointY)
{
    switch (direction)
    {
    case 'w':
        if (-1 < startPointX - 1 && 2 != intArrArrMazeC[startPointX - 1][startPointY])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX - 1][startPointY];
            intArrArrMazeC[startPointX - 1][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX - 1][startPointY];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX - 1][startPointY];
        }
        break;                                                                                              
    case 's':
        if (10 > startPointX + 1 && 2 != intArrArrMazeC[startPointX + 1][startPointY])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX + 1][startPointY];
            intArrArrMazeC[startPointX + 1][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX + 1][startPointY];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX + 1][startPointY];
        }
        break;
    case 'a':
        if (-1 < startPointY - 1 && 2 != intArrArrMazeC[startPointX][startPointY - 1])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY - 1];
            intArrArrMazeC[startPointX][startPointY - 1] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY - 1];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY - 1];
        }
        break;
    case 'd':
        if (10 > startPointY + 1 && 2 != intArrArrMazeC[startPointX][startPointY + 1])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY + 1];
            intArrArrMazeC[startPointX][startPointY + 1] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY + 1];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY + 1];
        }
        break;
    default :
        break;
    }
    showMaze(intArrArrMazeC);
}

//业务层(Service/AI层):人工智能
// 组成特点分析:
// 返回值:int
// 整体意义:迷宫是否能够走通
// 局部意义:没有完成一条通路,就继续往下走
// 不断的进行压栈,压到树状递归的底部
// 如果不行:如果该路不通,就进行回溯释放函数所占用的栈内存(返回值无意义)
// 如果能行:如果该路畅通,就进行回溯释放函数做占用的栈内存(返回值有意义)
// 形参值:
// int intArrArrMaze[10][10]:
// 整体意义:待测试的迷宫数据
// 局部意义:每次迷宫的下一步,所依赖的上一步迷宫数据布局
// int startPointX, int startPointY:
// 整体意义:就是迷宫的起始点
// 局部意义:就是迷宫每次要试探的下一点
int mazeAI(int intArrArrMaze[10][10], int startPointX, int startPointY)
{
    int successFlag = 0;
    int movePointX = startPointX; //测试假定起始点的正确性
    int movePointY = startPointY;
    intArrArrMaze[startPointX][startPointY] = 3;//试探迷宫走步(测试点成功走出)-->假定起点成功
    if (endPointX == movePointX && endPointY == movePointY)//当前待移动的点所在的位置
    {
        printf("小伙子恭喜走出来了! \n");
        return successFlag = 1;
    }
    //右下左上
    // 1 != successFlag:
    // 这条语句表明还没有形成完整的通路,因此急需寻找,最终寻找到的通路
    // 一定是每一个递归函数都返回1的情况
    // 2 > intArrArrMaze[movePointX][movePointY + 1]:
    // 这条语句的作用既可以排除掉墙壁点,也可以排除走过点
    if (1 != successFlag && 10 > movePointY + 1 && 2 > intArrArrMaze[movePointX][movePointY + 1])  mazeAI(intArrArrMaze, movePointX, movePointY + 1);
    if (1 != successFlag && 10 > movePointX + 1 && 2 > intArrArrMaze[movePointX + 1][movePointY])  mazeAI(intArrArrMaze, movePointX + 1, movePointY);
    if (1 != successFlag && -1 < movePointY - 1 && 2 > intArrArrMaze[movePointX][movePointY - 1]) mazeAI(intArrArrMaze, movePointX, movePointY - 1);
    if (1 != successFlag && -1 < movePointX - 1 && 2 > intArrArrMaze[movePointX - 1][movePointY]) mazeAI(intArrArrMaze, movePointX - 1, movePointY);
    if (0 == successFlag)//根据树状递归,递归到树状的根部返回情况决定当前路线是否通路(畅通|不畅通)-->完整路线
        intArrArrMaze[startPointX][startPointY] = 0;//试探迷宫回溯(测试点失败走回)-->假定起点失败

    return successFlag;
}

void AIUnitTest(int intArrArrMaze[10][10], int startPointX, int startPointY)
{
    int movePointX = startPointX;
    int movePointY = startPointY;
    while (endPointX != movePointX || endPointY != movePointY)
    {
        if (10 > movePointY + 1 && 3 == intArrArrMaze[movePointX][movePointY + 1])
        {
            intArrArrMaze[movePointX][movePointY + 1] = 0;
            operateMaze('d', movePointX, movePointY + 1);
        }
        if (10 > movePointX + 1 && 3 == intArrArrMaze[movePointX + 1][movePointY])
        {
            intArrArrMaze[movePointX + 1][movePointY] = 0;
            operateMaze('s', movePointX + 1, movePointY);
        }
        if (-1 < movePointY - 1 && 3 == intArrArrMaze[movePointX][movePointY - 1])
        {
            intArrArrMaze[movePointX][movePointY - 1] = 0;
            operateMaze('a', movePointX, movePointY - 1);
        }
        if (-1 < movePointX - 1 && 3 == intArrArrMaze[movePointX - 1][movePointY])
        {
            intArrArrMaze[movePointX - 1][movePointY] = 0;
            operateMaze('d', movePointX - 1, movePointY);
        }
    }
}

int main02(void)
{
    //showMaze(intArrArrMazeY);
    int successFlag = mazeAI(intArrArrMazeC, 0, 0);
    if (successFlag)
    {
        printf("可以走出! \n");
        intArrArrMazeY[0][0] = 1;
        showMaze(intArrArrMazeY);
    }
    else
    {
        printf("不可以走出! \n");
    }

    system("pause");
}

你可能感兴趣的:(CCPP)