• 20160211.CCPP体系详解(0021天)


    程序片段(01):01.指针数组.c+02.动态数组.c
    内容概要:指针数组

    ///01.指针数组.c
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.指针数组作为函数的形参:
    //  会退化为一个二级指针!
    //02.如何确定一个数组作为函数形参将会退化为什么样儿的指针?
    //  关键在于形参数组当中的元素是什么类型!就是什么类型的指针
    void show01(char * str[5])//char *str[5]
    {
        for (int i = 0; i < 5; ++i)
        {
            printf("%s 
    ", str[i]);//char **str
        }
    }
    
    //03.等价关系:
    //  二级指针和指针数组的数组名所对应的解析方式都一样!
    void show02(char ** str)
    {//指针数组作为函数的形参进行传参的时候,指针数组的数组名将会退化为一个二级指针!
        for (int i = 0; i < 5; ++i)
        {
            printf("%s 
    ", str[i]);
        }
    }
    
    //04.函数形参的拦截机制:
    //  如果是数组,就没有副本机制,不是副本,就有拦截介质
    //注:解除数组的副本机制依赖于数组名的退化机制!
    //05.如何确定一个变量的数据类型?
    //  在定义变量的基础情况之下,挖掉变量名,就是变量的数据类型
    //注:字符指针数组开发过程当中比较常用!
    int main01(void)
    {
        int * arr[10];//-->int * [10]-->一级指针数组类型!
        //一级指针数组的数组名arr在作为函数形参的时候,该一级指针的数组名会自动退化以为一个二级指针
        char * str[5] = { "calc", "notepad", "tasklist", "mspaint", "pause" };
        //char * [N]:字符指针类型的一级指针数组在开发过程当中经常使用!
        char **pp = str;//变量指针=常量指针(地址意义的数组赋值动作!)-->指针变量结果-->指针变量遍历!
        printf("%p 
    ", str);//二级指针常量的数值
        //show01(str); <= = > show02(str);
    
        system("pause");
    }
    ///02.动态数组.c
    #include <stdio.h>
    #include <stdlib.h>
    
    //01.如何确定动态数组的数组名称?
    //  1.开辟内存的时候所采用的指针变量名称就是动态数组名称!
    //  2.通过指针变量名称的访问方式就如同标准数组的访问方式!
    //  注:严格区分变量指针和常量指针之间的差别!
    int main02(void)
    {
        //动态分配一个一维数组
        int * const arr = malloc(30 * sizeof(int));
        for (int i = 0; i < 30; ++i)
        {
            printf("%d 
    ", arr[i] = i);//arr[i]<=>*(arr+i)
        }
    
        system("pause");
    }
    
    //02.动态数组的分配要点:
    //  1.动态内存开辟函数!
    //  2.解析动态内存的指针类型!
    //  注:所有数组都看做为一维数组!,指向该数组首元素的指针
    //      指针可以使用:变量指针和常量指针(模拟栈内存数组!)
    //  注:动态数组的尺寸在程序运行过程当中决定!
    //      每个当前维度的数组都必须要求明确其维度-1的特点
    int main03(void)
    {
        //动态分配一个二维数组
        //int test = 5;
        int(*p)[5] = malloc(30 * sizeof(int));
        for (int i = 0, num = 0; i < 30; ++i, ++num)
        {
            printf("%3d", p[i / 5][i % 5] = num);//0->1->2->3...
            if (0 == (i + 1) % 5)
                putchar('
    ');
        }
    
        system("pause");
    }
    
    //03.两种区别的数组:
    //  二维数组:数组当中的每个相邻数组元素的内存地址必须连续
    //      (连续!+对齐!)
    //  分块数组:针对于同一个数组当中的每个数组元素的内存地址必须连续
    //      但是内部就整体而言的数组元素之间是可以不连续的
    //      (不连续+不对齐!)
    //  注:动态内存开辟函数的返回值类型为("void *")类型,只是负责返回一个有效
    //      地址,但是没有具备解析意义+堆内存动态开辟函数前面的赋值号只是用于
    //      返回一个明确的地址而已!-->指针类型决定对动态内存的实际解析意义!
    int main04(void)
    {
        //使用malloc函数在堆内存当中开辟一个指针数组!
        int **pp = malloc(5 * sizeof(int *));//20个堆内存字节
        int num = 0;
        for (int i = 0; i < 5; ++i)
        {
            pp[i] = (int *)malloc((5 + i)*sizeof(int));
            for (int j = 0; j < 5 + i; ++j)
            {
                pp[i][j] = num++;//赋值
            }
        }
        for (int i = 0; i < 5; ++i)
        {
            for (int j = 0; j < 5 + i; ++j)
            {
                printf("%3d", pp[i][j]);
            }
            printf("
    ");
        }
    
        system("pause");
    }
    
    
    //04.常见数据结构的特点:
    //  数组:查找效率高+增加|删除效率低
    //  链表:增加|删除效率高+查找效率低
    //  分块:查找效率和数组一样+增加|删除效率比数组高(略低于链表,不过可以忽略!)
    //      可以不用连续,可以不用对齐!
    //05.如何分配一个N-1级指针数组?
    //  需要一个N级的指针!
    // N级指针,存储N-1级指针数组的地址
    // N级指针分配一个数组,用于存放N-1级指针数组的首个元素的地址(区分变量指针|常量指针)
    // 数据等同于0级指针

    程序片段(02):01.Array.c
    内容概要:数组的三种形态

    #include <stdio.h>
    #include <stdlib.h>
    
    //01.C语言版本标准:
    //  第一版:C89
    //  第二版:C99
    //02.(VC2013以上+GCC4.7以上)支持C99语法
    //  VC2013+GCC4.7
    //03.C99新语法分配数组模式!
    //  1.位于栈内存的静态数组
    //  2.可以进行指明初始化!
    //      指明初始化的最大索引可以推导数组总元素个数
    //  3.指明初始化方式的特点:可以明确长度!
    //      纯大括号初始化:只能同时指明数组长度,并且给数组最后一个元素初始化赋值
    //          其余数组元素统统采用默认初始化方式!
    //      非纯大括号初始化:可以同时指明数组长度,并且给多个数组元素初始化赋值
    //          其余数组元素统统采用默认初始化方式!
    int main01(void)
    {
        int arr[] = { [10] = 10 };//默认不操作的数组元素被赋值为0,[10]-->arr[10]=0->11个元素
        for (int i = 0; i < 11; ++i)
        {
            printf("%d 
    ", arr[i]);
        }
    
        system("pause");
    }
    
    int main02(void)
    {
        int n = 4;
        int * pC99 = (int[]) { [2] = 1, [4] = 10 };//静态数组
        //默认不指明初始化的数组元素所对应的值为0
        for (int i = 0; i < 5; ++i)
        {
            printf("%d 
    ", pC99[i]);
        }
    
        system("pause");
    }
    
    //04.静态数组与动态数组:
    //  静态数组:
    //      1.存储于栈内存
    //      2.编译时期决定数组元素个数
    //      3.(自动开辟+自动回收)
    //  动态数组:
    //      1.存储于堆内存
    //      2.运行时期决定数组元素个数
    //      3.(手动开辟+手动释放)
    //  注:严格区分(分配+释放)以及(开辟+回收)的区别
    //      分配+释放:权限
    //      开辟+回收:内存
    void run()
    {
        //int arr[5] = { 1, 2, 3, 4, 5 };
        int * p = malloc(10 * sizeof(int));
        for (int i = 0; i < 10; ++i)
        {
            p[i] = i;//p[i]-->*(p+i)
        }
        free(p);
        //基于C99语法的静态数组:处于栈内存当中,自动开辟回收,用于解决心脏起搏器问题!
        //int * pC99 = (int []){ [4] = 10 };
        //printf("%p 
    ", pc99);
        printf("
    ");
    }
    
    int main03(void)
    {
        run();
        printf("
    
    
    ");//加速内存的回收动作!+防止Release模式!优化操作
        run();
        printf("
    
    
    ");
    
        system("pause");
    }
    
    //05.指针变量可以指向任何内存地址:
    //  无论是栈内存,堆内存,全局区,代码区
    int main04(void)
    {
        int num = 30;
        //int * pC99 = (int[30]) { 0 };
        //pC99 = (int[10]) {0};//pC99是int*类型
        //pc99 = 1;
        int * pC99 = (int [30]) { [2] = 1, [4] = 10 };//静态数组
        for (int i = 0; i < 30; ++i)
        {
            printf("%d 
    ", pC99[i]);
        }
    
        system("pause");
    }
    
    //06.区分静态分配和动态分配区别:
    //  int num=30;//静态分配:必须在编译时期,决定静态数组的元素个数
    //  int a[num];//栈上的静态分配-->可变长度的数组只有在GCC编译器当中实现,VC编译器当中不能进行实现
    //  注:VC不支持位于栈内存的静态数组+GCC支持位于栈内存的静态数组!

    程序片段(03):01.内存.c
    内容概要:四大分配堆内存的函数

    #include <stdio.h>
    #include <stdlib.h>
    
    //01.内存四大分配函数:
    //  malloc<->calloc:
    //      malloc:内存不清零(参数:内存字节数)
    //      calloc:内存清零(参数1:数组元素个数+参数2:单个元素尺寸)
    //  realloc<->_recalloc:
    //      realloc:内存不清零(参数1:内存首地址,总内存字节数)
    //          1.如果原始内存地址足够拓展,就在原始内存地址进行拓展
    //          2.如果原始内存地址不够拓展,就在新地址内存进行拓展:
    //              拷贝原始内存地址所对应的有效数据+回收原始内存地址数据
    //          3.拓展之后的内存如果没有数据进行覆盖,就不回执行内存清零操作!
    //      _recalloc:内存清零(参数1:内存首地址+参数2:数组元素个数+参数3:单个元素尺寸)
    //          1.如果原始内存地址足够拓展,就在原始内存地址进行拓展
    //          2.如果原始内存地址不够拓展,就在新地址内存进行拓展
    //              拷贝原始内存地址所对应的有效数据+回收原始内存地址数据
    //          3.拓展之后的内存如果没有进行手动初始化,系统将会执行自动初始化操作!
    int main01(void)
    {
        //int * p = (int *)malloc(100);//malloc不会初始化参数,参数是整体所占用的内存尺寸(字节数)!
        int * p = calloc(25, sizeof(int));//calloc存在初始化参数,参数解释:第一个参数是元素个数,第二个参数是元素内存尺寸
        printf("%p 
    ", p);
        //for (int i = 0; i < 25; ++i)
        //{
        //  p[i] = i;
        //}
    
        system("pause");
    }
    
    int main02(void)
    {
        int * p = malloc(10 * sizeof(int));//指针能够操作这片儿堆内存!
        //int * p_p = malloc(100);
        for (int i = 0; i < 10; ++i)
        {
            printf("%d 
    ", p[i] = i);
        }
        printf("p = %p 
    ", p);
    
        int * px = realloc(p, 200);//拓展内存,内存不清零
        //返回值是内存首地址,说明拓展成功,后续地址拓展,拓展不成功,重新开辟内存
        //原来的内存就被回收了
        printf("px = %p 
    ", px);
        for (int i = 0; i < 50; ++i)
        {
            px[i] = i;
            printf("%d 
    ", px[i]);
        }
        //p[120387] = 10;
    
        system("pause");
    }
    
    int main03(void)
    {
        int * p = calloc(25, sizeof(int));//会初始化为0,参数:数组元素个数+内存字节大小
        //scanf("123");
        printf("%p 
    ", p);
        for (int i = 0; i < 25; ++i)
        {
            p[i] = i;
        }
        p = _recalloc(p , 50, sizeof(int));//内存清零操作
        for (int i = 25; i < 50; ++i)
        {
            p[i] = i;
        }
        system("pause");
    }

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

    #include <stdio.h>
    #include <stdlib.h>
    
    //01.VC不支持栈内存动态数组,GCC支持栈内存动态数组!
    int main()
    {
        int num=30;
        int a[num];//栈上的动态分配
         //int *pc99 = (int[30]){0};
    
        //printf("Hello world!
    ");
        return 0;
    }
    
  • 相关阅读:
    数据分析的5层解读,报表仍是有效的落地实践!
    rex 传文件改变用户属主
    rex 通过--parameter1=dbcdefg传参
    rex 给shell 脚本传参
    rex run 传参
    rex ssh公钥认证
    eclipse maven工程中src/main/resources目录下创建的文件夹是包图标的解决方法
    数据分析的三层需求
    com.mysql.jdbc.MysqlDataTruncation: Data truncation: Truncated incorrect DOUBLE value
    java.sql.SQLException: Can not issue data manipulation statements with executeQuery()
  • 原文地址:https://www.cnblogs.com/new0801/p/6176817.html
Copyright © 2020-2023  润新知