zoukankan      html  css  js  c++  java
  • 20160206.CCPP体系具体解释(0016天)

    代码片段(01):.指针.c+02.间接赋值.c
    内容概要:内存

    ///01.指针
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.取地址操作符(&)具体解释:
    //  1.操作对象:变量名(实质:内存实体|数据实体)
    //  2.操作特点:属于寄存器操作(操作结果不是内存实体)
    //      (1).取地址操作(&变量名)是在CPU的寄存器区域所完毕的操作;
    //      (2).地址数据不占用内存,内存地址是在CPU核心构成组件寄存器产生的,
    //          内存地址的数值和内存存储没有实质关系;
    //  3.计算机地址总线:连接CPU与硬件内存的总线
    //      (1).总线数目与CPU位数+操作系统位数有关
    //      (2).地址数值作为一个常量恒久不变
    //      (3).地址作为产量恒值并不会占用内存
    //          内存地址是在CPU的寄存器其中产生的,因此不具备内存实体,也就不会占用内存
    //      (4).总线的个数决定者位数的不同:
    //          32条总线相应于32位操作系统;64条总线相应于64位操作系统
    //02.对指针变量的解释:
    //  P一个指针变量,用于存储普通变量的地址数值,然后通过操作指针变量的方式间接操作普通变量
    //03.对于指针所占用的字节数分析:
    //  Win32平台所编译的程序的指针类型占用4个字节
    //  Win64平台所编译的程序的指针类型占用8个字节
    int main01(void)
    {
        int num = 10;
        int data = 20;
        //P是一个指针变量,能够存储相同类型的不同变量的内存地址,经常使用于做间接訪问变量本身(内存实体)操作
        int * pNum = &num;//0x12312312
        int * pData = &data;
        printf("%d 
    ", sizeof(pNum));//指针变量所占用的内存尺寸为4个字节(Win3平台所编译的程序)
        printf("%p 
    ", pNum);//直接打印指针变量(pNum)的数值,相当于间接打印了普通变量(num)的地址
        printf("%p 
    ", &pNum);//表示获取"指针"变量的地址,类型为int **
    
        system("pause");
    }
    
    //04.指针变量内容具体解释:
    //  1.类型:
    //      既决定了内存实体步长,也决定了内存实体解析方式
    //  2.数值:
    //      就是一个地址数值
    //  3.场景:(携带*号的情况)
    //      赋值号左边:
    //          给内存实体写入数据
    //      赋值号右边:
    //          从内存实体读取数据
    int main02(void)
    {
        int num1 = 1100;
        int num2 = 1200;//变量num都分配了内存,内存实体(数据实体)的数值代表变量的数据
        int * pNum = &num1;//pNum1是int类型的一级指针变量,&num1是一级指针真常量数值(含有类型含义)
        pNum = &num2;//pNum的值是num2这个变量(内存实体|数据实体)的内存地址,该内存地址统一占用4个字节,int * 地址,指针变量的长度统一为4
        //int * 对称于pNum,指针类型既决定了内存实体的訪问字节步长,也决定了内存实体的解析方式,特殊点:浮点型数据的特殊存储形式,既是指数形式存储还涉及到无符号类型(存储实质阶码)
        *pNum = 12;//通过指针变量间接的訪问了普通变量的内存实体//依据指针数值找到内存地址,依据指针类型既决定了存储步长也决定了存储方式
        printf("%p 
    ", &pNum);//&pNum表示获取一级指针变量pNum的内存地址,该地址数值存储于CPU核心组件寄存器区域,全然不会占用内存存储
        printf("%d 
    ", num2);
        printf("num2 = %d 
    ", num2);
    
        system("pause");
    }
    
    //05.野指针:就是没有进行初始化操作的指针变量
    //  VC:编译检測,GCC编译不检測
    //06.解析方式的不同含义:
    //  有无符号:signed/unsigned
    //  存储原理:补码原理/阶码原理
    //07.指针变量所占用的内存尺寸仅仅跟编译平台有关:
    //  Win32平台:4字节-->Win64平台:8字节
    int main03(void)
    {
        //int * p;//没有对象的野指针,定义指针变量的时候必须进行指针变量的初始化操作
        //printf("%p 
    ", p);//打印指针变量其中所存储的内存地址-->编译不通过
    
        //解析方式的不同特点:
        //  signed/unsigned(仅仅针对于10进制的整数)+float指数形式存储(阶码实质存储)
        int num1 = 10;
        int num2 = 20;
        //float * pNum;
        //pNum = &num1;
        //printf("%f", *pNum);//指针变量的类型决定了指针变量对其所存储的地址数值的解析步长(字节尺寸)以及解析方式(补码阶码)
        int * pNum;
        pNum = &num1;
        printf("%d 
    ", *pNum);//对内存地址数值的正确解析步长和正确解析方式
        printf("%d 
    ", sizeof(pNum));//指针变量所占用的字节长度在Win32平台之下统一占用4个字节的内存尺寸,不论什么类型的地址都一样採用int类型的统一字节尺寸存储
        printf("%d 
    ", sizeof(*pNum));//尺寸,方式
    
        system("pause");
    }
    
    //08.指针认识规律:
    //  *pNum<=>num
    int main04(void)
    {
        int num = 20;
        int data = 30;
        int * pNum = &num;//int类型的一级指针变量存储了int类型的普通变量的内存地址
        //&num = 1;//内存地址不同意操作,由于&num这个表达式是在CPU的寄存器其中所进行的操作,然而C语言是不能够直接改动寄存器其中的数据的
        //pNum = &data;
        num = 3;
        printf("%d,%d 
    ", *pNum, num);//*pNum和num是全然等价的
        *pNum = 7;
        printf("%d,%d 
    ", *pNum, num);
    
        system("pause");
    }
    ///02.间接赋值.c
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.函数形參具有副本机制:
    //  1.传值和传指的数据层面意思都一样;
    //      仅仅只是对相同的数值有着不同的解析方式!
    //  1.函数的副本机制总是存在;
    //      不管是传值还是传地!
    void change05(int num)//函数形參具有副本机制
    {
        //函数形參具有副本机制,因此,不管是传值还是传指,都具备这种特性:
        //  传值传递的是副本,传指传递的是地址,因此出现不一样的改动效果
        //  实质:都是副本,仅仅只是对待相同的数值解析方式不同而已
        num = 3;
        printf("change05 = %d 
    ", num);
    }
    
    int main05(void)
    {
        int num = 10;
        change05(num);
        printf("%d 
    ", num);
    
        system("pause");
    }
    
    void change06(int * pNum)
    {
        *pNum = 3;
    }
    
    int main07(void)
    {
        int num = 10;
        change06(&num);//&num-->表达式-->没有内存实体-->位于寄存器-->C语言不具备改动寄存器的权限
        printf("%d 
    ", num);
    
        system("pause");
    }

    程序片段(02):01.Run.c
    内容概要:

    #include <stdio.h>
    #include <stdlib.h>
    
    //01.外挂改动数值原理
    //  1.注入DLL模块儿
    //  2.依据指针进行跨函数訪问内存
    _declspec(dllexport) void go()
    {
        int * p = (int *)0xae0720;
        *p = 77;
    }
    
    //02.遍历内存查找原理:
    //  1.单字节内存遍历
    //  2.待查找尺寸读取
    _declspec(dllexport) void run()
    {
        typedef char * Char;
        for (Char  pStart = 0xae000000,pEnd = 0xae100000; pStart < pEnd; ++pStart)//单字节遍历指定内存范围
        {
            int * p = (int *)p;//指针类型转换,待查找尺寸读取数据进行匹配,以便于相同数值进行内存检索
            if (77 == *p)
            {
                *p = 86;
            }
        }
    }

    程序片段(03):01.void.c+02.空指针.c
    内容概要:Void与空类型指针

    ///01.void.c
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.空类型与空类型指针:
    //  空类型:void
    //  空类型指针:void *
    //02.指针类型:
    //  解析步长+解析方式
    //03.空类型指针变量:
    //  能够存储不论什么类型的指针
    int main01(void)
    {
        //error C2182:"a":非法引用"void"类型 void
        int num = 10;
        double db = 19.3;
        //void num;//不合法-->没有明白数据类型-->编译器既不知道分配多大步长的内存块儿,也不知道依照何种方式进行分配!
        void * vp = &num;//合法->Win平台(32/64)编译器明白指针所应使用的内存字节尺寸-->不须要明白解析方式-->由于仅仅是一个数值意义的地址
        vp = &db;//空类型的指针能够存储不论什么类型变量(普通变量,一级指针变量,二级指针变量,三级指针变量,多级指针变量等等...)的地址,由于编译器决定了地址存储尺寸
        //printf("%d 
    ", *vp);//:error C2100:非法的间接寻址(问题原因一般是採用空类型的指针对该指针所存储的地址进行解析)->既不明白解析尺寸,也不明白解析方式,所以出错
        //空类型的指针既不能够间接取值,也不能够间接赋值(也就是仅仅能存储内存地址,而不能依据内存地址进行间接訪问操作)
        //*vp = 10;
        printf("%f 
    ", *((double *)vp));//将空类型的指针转化为具体指针类型,然后就达到了既明白了指针的解析步长,也明白了解析方式
    
        system("pause");
    }
    ///02.空指针.c
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.结构体变量:
    //  用于组织多种不同类型的变量
    struct MyStruct//包括四根指针,花心的妹子,能够进行动态的扩充
    {//一个由多个一级指针变量所构成的单个普通结构体变量
        int *p1;
        int *p2;
        int *p3;
        int *p4;
    };
    
    //02.空指针(NULL):
    //  实质:(void *)0
    //  作用:标识不论什么指针变量没有存储内存地址
    //  特点:空指针所指向的内存实体不同意訪问,否则出现訪问异常
    int main02(void)
    {
        //标记指针变量是否存储内存地址
        double db = 10.9;
        double 刘海华 = 10.9;
        double * pDb = NULL;//空指针(NULL):标识不论什么指针变量没有存储内存地址
        while (NULL == pDb)
        {
            //炮之
            pDb = &刘海华;
        }
        *pDb = 1;//空指针所指向的内存实体不同意进行操作
    
        system("pause");
    }

    程序片段(04):01.指针的声明.c
    内容概要:指针的声明

    #include <stdio.h>
    #include <stdlib.h>
    
    //01.声明指针变量:
    //  数据类型+指针级数+指针变量
    int main01(void)
    {
        int * p1;
        int * p2;
    
        system("pause");
    }
    
    //02.特殊声明格式:
    //  格式:数据类型 * p, num;
    //  特点:p是指针变量,num是普通变量
    int main02(void)
    {
        int numA, numB, numC;
        double * pNumA, pNumB, pNumC;
        printf("%d 
    ", sizeof(pNumA));//在Win32平台之下,全部类型,所以级数的指针变量都占用4个字节的内存尺寸
        printf("%d 
    ", sizeof(pNumB));
    
        system("pause");
    }
    
    //03.宏定义(宏替换)和别名定义的差别:
    //  宏定义:第二整块儿替换后置
    //  别名定义:最后整块儿替换前置
    #define 整数  int
    typedef int INT;
    int main03(void)
    {
        整数 x = 3;//替换后置
        INT y = 3;//替换前置
        printf("%d, %d 
    ", x, y);
    
        system("pause");
    }
    
    //04.别名定义规律:
    //  变量定义:int * pNum
    //  添关键字:typedef int * pNum;
    //      特点:变量名变为类型别名
    #define 指针 double *
    typedef double * DBP;
    int main04(void)
    {
        指针 p1;
        DBP p2;
        //printf("%p, %p 
    ", p1, p2);
        printf("%d, %d 
    ", sizeof(p1), sizeof(p2));
    
        system("pause");
    }
    
    //05.特别注意:
    //  1.宏定义(宏替换)和别名定义之间的差别
    //  2.预编译与真实别名
    int main05(void)
    {
        指针 p1, p2;//实质:double *p1, p2, p3;//4,8
        p1 = 0x123;
        p2 = 0x123;
        DBP p3, p4;//doube *类型
        p3 = 0x123;
        p4 = 0x123;
        printf("%d, %d 
    ", sizeof(p1), sizeof(p2));
        printf("%d, %d 
    ", sizeof(p3), sizeof(p4));
    
        system("pause");
    }

    程序片段(05):01.银行.c+02.指针数组.c
    内容概要:数据地址映射

    ///01.银行.c
    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.C语言编译器特点:
    //  未初始化的普通变量->编译通过
    //  未初始化的指针变量->编译只是
    //02.数据地址映射使用:
    //  1.不同意改变原始内存实体的情况,实现排序
    //  2.比較数据实体,交换指针变量
    //  注:
    //      1.仅仅有整型数据才干使用位运算
    //      2.升序的反面成立,既须要进行交换
    int main01(void)
    {
        int num1;//内存实体
        int num2;
        scanf("%d%d", &num1, &num2);//从从小到大
        int * p1 = &num1;//映射指针
        int * p2 = &num2;
        if (*p1 > *p2)//升序的反面成立,就须要进行交换
        {
            //p1 = p1 ^p2;//仅仅有整型才干使用位运算
            int * ptemp = p1;
            p1 = p2;
            p2 = ptemp;
        }
        printf("%d, %d 
    ", *p1, *p2);
    
        system("pause");
    }
    
    //03.指针变量声明与const关键字使用:
    //  规律:const在指针变量名称前面,也就是星号("*")的右边
    //      就表明该指针变量本身是一个伪常量,也就是该指针变量
    //      不能直接进行改动,可是能够通过间接方式进行改动
    //  特点:const int * p<=>int const * p
    //      仅仅须要关注const与星号("*")之间的相对位置
    //  用处:限定訪问权限
    //      读取权限和改动权限的综合配对
    //void accessControl(const int * p);
    void accessControl(int const * p)//报表权限:限定訪问权限,间接操作的内存实体仅仅能读取,不能进行改动
    {//const在指针其中所能起到的作用
        p = NULL;//通过指针变量间接訪问的内存实体是个真常量,不同意进行间接改动,可是当前指针变量能够进行改动
        printf("*p = %d 
    ", *p);//不能依据空指针进行内存实体訪问,既不能读取也不能写入(操作系统规定)-->编译不报错,可是执行报错
        //*p = 10;//编译报错
    }
    
    int main02(void)
    {
        int num = 100;
        int * pNum = &num;
        accessControl(pNum);
        printf("num = %d 
    ", num);
    
        system("pause");
    }
    ///02.指针数组.c
    #include <stdio.h>
    #include <stdlib.h>
    
    //int a[8];
    //const int *p[8];
    int a[8] = { 1,8,2,7,3,6,4,5 };//int类型的数组 
    const int * p[8] = { &a[0],&a[1],&a[2],a + 3,a + 4,a + 5,a + 6,a + 7 };//指针数组
    void main()
    {
        printf("原来的数组数据:
    ");
        for (int i = 0; i < 8; i++)
        {
            printf("%d
    ", a[i]);
        }
        printf("原来的指针数组指向数据:
    ");
        for (int i = 0; i < 8; i++)
        {
            printf("%d
    ", *p[i]);
        }
    
        for (int i = 0; i < 8 - 1; i++)//最后一个数据不须要冒泡
        {
            for (int j = 0; j < 8 - 1 - i; j++)//冒泡数与与i形成相应关系
            {
                //指针数组其中存储的是指针,然后通过指针进行数据的获取,通过比較指针所相应的数据,然后进行数据交换
                if (*p[j]>*p[j+1])//这里使用指针数组进行比較数据,用数组指针进行数据获取比較,然后进行数据交换 
                {//指针交换
                    int *ptemp = p[j];
                    p[j] = p[j + 1];
                    p[j + 1] = ptemp;
                }
            }
        }
    
        printf("数组数据:
    ");
        for (int i = 0; i < 8; i++)
        {
            printf("%d
    ", a[i]);
        }
        printf("指针数组指向数据:
    ");
        for (int i = 0; i < 8; i++)
        {
            printf("%d
    ", *p[i]);
        }
    
        system("pause");
    }

    程序片段(06):01.输入指针.c
    内容概要:地址输入

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    
    int main01(void)
    {
        int num = 10;
        int data = 20;
        printf("%p, %p 
    ", &num, &data);
        int * pNum = &pNum;
        //对指针变量进行手动地址输入:
        //  格式:scanf("%p", &pNum);
        //  特点:不须要携带0x前缀,并且必须是大写英文字母
        scanf("%p", pNum);//地址类型数组须要使用%p这种输入格式控制符+指针变量的地址
        *pNum = 20 + 3;//操作系统所使用的地址,胡乱进行訪问的时候easy出现系统问题
        printf("num = %d, data = %d 
    ", num, data);
    
        system("pause");
    }

    程序片段(07):01.Screen.c
    内容概要:屏幕输出图片

    #include <stdio.h>
    #include <stdlib.h>
    #include <Windows.h>
    
    int main(void)
    {
        int i = 0;
        while (1)
        {
            HWND win = GetDesktopWindow();
            HDC winDc = GetWindowDC(win);//获取指定窗体的输出接口
            HDC memDc = CreateCompatibleDC(0);//获取内存存储的操作接口
            HBITMAP bitMap = (HBITMAP)LoadImage(win, TEXT("1.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
            SelectObject(memDc, bitMap);//选定图形图像设备-->设置显示什么
            BitBlt(winDc, 0, 0, i++, i++, memDc, i++, i++, SRCCOPY);
            Sleep(100);//模拟0.1秒
            ++i;
            if (3 == i)//到达3次
            {
                i = 0;//重置0次
            }
        }
    
        system("pause");
    }

    程序片段(08):test.c
    内容概要:Test1

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define EN 1024
    int flag = 0;
    char * filePath = "E:\Resource\TestData\BigDB\Test.txt";
    
    //数组赋值
    int intArr[EN];
    void initArr(int intArr[EN])
    {
        //time_t te;
        //unsigned int seed = (unsigned int)(time(&te));
        //srand(seed);
        srand((unsigned int)(time(NULL)));
        for (int i = 0; i < EN; ++i)
        {
            intArr[i] = rand() % EN + 1;
        }
    }
    
    //数组显示
    void showArr(int intArr[EN])
    {
        for (int i = 0; i < EN; ++i)
        {
            printf("%4d 
    ", intArr[i]);
        }
    }
    
    //冒泡排序
    void bubbleSortArr(int intArr[EN])
    {
        for (int i = 0; i < EN - 1; ++i)
        {
            for (int j = 0; j < EN - 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];
                }
            }
        }
    }
    
    //选择排序
    void selectSortArr(int intArr[EN])
    {
        int minIndex = 0;
        int minNum = 0;
        for (int i = 0; i < EN - 1; ++i)
        {
            minIndex = i;
            minNum = intArr[i];
            for (int j = i + 1; j < EN; ++j)
            {
                if (minNum > intArr[j])
                {
                    minIndex = j;
                    minNum = intArr[j];
                }
            }
            if (i != minIndex)
            {
                intArr[i] = intArr[i] ^ intArr[minIndex];
                intArr[minIndex] = intArr[i] ^ intArr[minIndex];
                intArr[i] = intArr[i] ^ intArr[minIndex];
            }
        }
    }
    
    //插入排序
    void insertSortArr(int intArr[EN])
    {
        int currentIndex = 0;
        int currentValue = 0;
        for (int i = 1; i < EN; ++i)
        {
            currentIndex = i;
            currentValue = intArr[currentIndex];
            while (0 < currentIndex && intArr[currentIndex - 1] > currentValue)
            {
                intArr[currentIndex] = intArr[currentIndex - 1];
                --currentIndex;
            }
            intArr[currentIndex] = currentValue;
        }
    }
    
    //二分查找
    int binarySearch(int intArr[EN], int value)
    {
        int minIndex = 0;
        int midIndex = 0;
        int maxIndex = EN - 1;
        while (minIndex <= maxIndex)
        {
            midIndex = (minIndex + maxIndex) / 2;
            if (value == intArr[midIndex])
            {
                return midIndex;
            }
            else if (value < intArr[midIndex])
            {
                maxIndex = midIndex - 1;
            }
            else
            {
                minIndex = midIndex + 1;
            }
        }
        return -1;
    }
    
    //拉格朗日查找
    int lagrangeSearch(int intArr[EN], int value)
    {
        int minIndex = 0;
        int ratioIndex = 0;
        int maxIndex = EN - 1;
        while (minIndex <= maxIndex)
        {
            //midIndex = minIndex + (maxIndex - minIndex) / 2;
            ratioIndex = minIndex + (maxIndex - minIndex)*(value - intArr[minIndex]) / (intArr[maxIndex] - intArr[minIndex]);
            if (value == intArr[ratioIndex])
            {
                return ratioIndex;
            }
            else if (value < intArr[ratioIndex])
            {
                maxIndex = ratioIndex - 1;
            }
            else
            {
                minIndex = ratioIndex + 1;
            }
        }
        return -1;
    }
    
    int main01(void)
    {
        initArr(intArr);
        showArr(intArr);
    
        insertSortArr(intArr);
        printf("binSearch Index = %d 
    ", binarySearch(intArr, 880));
        printf("lagrangeSearch index = %d 
    ", lagrangeSearch(intArr, 880));
    
        system("pause");
    }
  • 相关阅读:
    php-fpm 进程数的设定
    git如何清除远程 __pycahce__ 文件
    使用docker-compose编写常规的lnmp容器,pdo连接mysql失败。
    composer 巨慢的解决之道
    mysql 单机多实例配置
    golang 在 Mac , Linux , Windows 下交叉编译详解
    mysql 索引优化
    【转】解决深入学习PHP的瓶颈?
    debian 系统搭建rsync+sersync实现实时同步
    docker 搭建debian+nginx+php(含composer的扩展)+mysql+mongo+redis
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8341899.html
Copyright © 2011-2022 走看看