• 九、指针


    指针
    Byte字节作为内存最小单元
    int占用4个字节
    1.内存地址和指针
    变量存放在内存当中 ------>找到变量在内存当中的位置 就可以操作这个变量
    数组元素的首地址--->地址

    在形参中传参主要的是传递的地址

    指针存放地址的类型 指针通过地址 去访问 去修改变量的值

    1.函数传参 2.使用堆内存
    2.指针定义和使用方式
    指针就是地址
    指针变量用来存放地址

     1 int *q = (int *)malloc(sizeof(int)* 100);//申请堆内存 第一个(int*)是强转 第二个(int)是申请int大小的空间
     2     
     3     if (q == NULL)
     4     {
     5         printf("申请失败");
     6         getchar();
     7         return 0;
     8     }
     9     //q指向了这块空间的首地址
    10     *q = 12;//===q[0]
    11     *(q + 1) = 13;//===q[1]
    12     q[2] = 14;//===(*q+2)
    13     q[3] = 15;
    14     for (size_t i = 0; i < 4; i++)
    15     {
    16         printf("%d
    ", q[i]);
    17     }
    18     q = (int*)realloc(q, sizeof(int)* 200);//把之前的100个int扩充到200个int
    19     printf("重新分配后
    ");
    20     for (size_t i = 0; i < 4; i++)
    21     {
    22         printf("%d
    ", q[i]);
    23     }
    24     printf("q的值%p
    ", q);
    25     free(q);//释放内存

    int类型 double类型


    如果只有一个地址 没法判断这个地方是什么类型的数据

    指正是有类型的!!!

    一个地址里面存放是int类型的值 int* 表示存放int类型的地址
    一个地址存放的时候double类型的值

    一级指针 地址存放基本数据类型

    int float double char
    %p输出地址
    * 运算符 解引用

    如果变量x的地址 存放在指针p 里面 p指向这个变量

    int*类型的指针 指向int类型的变量

    int y;
    int*p;//定义一个指向int类型变量的指针
    p=&y;//将y的地址 赋值给指针p
    *p=2;//将y存放的内容赋值2 y就为2
    printf("%p=%d",&y,y); &y输出y存放的地址


    形参不能改变实参
    需要在其他函数中 修改实参的值 通过传递地址的方式修改


    类型* 指针变量名

    int* p;//int* 表示指针类型 p表示变量名
    一维数组 也可以用一级指针

    数组名 vs 指针

    数组名 表示数组的首地址 数组名不可以修改(视为常亮)
    指针可以修改

    sizeof求大小 数组名 得到的数组的大小
    如果得到指针大小

    1 void fun(int arr[][5])//形参实际上是指针   int*arr  
    2 {
    3     int a=sizeof(arr[0]);//求的是形参的大小--->指针的大小
    4     int b = sizeof(arr);
    5     int c = sizeof(arr[0][0]);
    6     printf("arr[0]的大小为:%d
    ", a);//数组定义的第一个元素的大小
    7     printf("arr的大小为:%d
    ", b);//数组指针arr的大小 为4
    8     printf("arr[0][0]的大小为:%d
    ", c);
    9 }

    int arr[10]

    错误用法 arr++
    数组名[下标]

    数组名和指针 都可以用* []


    指针 申请堆内存

    程序运行的时候 代码数据 加载内存当中

    内存四区
    代码区 存放代码二进制
    全局静态常量区(全局静态 常量区)
    全局函数外定义的变量 作用域是整个程序
    静态 static 修饰变量 用static修饰的变量存放在全局静态区

    1 void fun2()//全局静态常量区
    2 {
    3     static int x = 0;//静态变量x 每次调用的时候运算结束 值都会改变
    4     ++x;
    5     printf("x=%d
    ", x);
    6 }

    常量区 存放一些数字常量或者字符常量

    没法取到地址


    栈区 局部变量(函数 循环里面定义变量) 形参
    都会存放在栈区
    栈区 小的空间 内存操作系统控制
    4M
    堆区 1G 需要申请释放 需要用到函数专门申请内存
    申请内存需要用到指针

    申请内存 malloc 用于申请内存
    释放内存 free

    realloc 内存重分配 在原有内存的基础上 加/减 内存

    传参

    int 有int*  一级指针  保留int的地址

    int*p ---> p也是变量 p也有地址 如果得到p的地址 定义二级指针来接受p的地址
    int** pp=&p; 二级指针

    *pp --->得到的是pp指向的内容 也就是p

    printf("%d ",x)

    一维数组 传参 用一级指针
    二维数组 传参 数组指针

    int dArr[3][4]---->int (*pd)[4] 数组指针

     1 void fun3(int(*pd)[4])//指针数组相当于int dArr[][4]
     2 {
     3     for (size_t i = 0; i < 12; i++)
     4     {
     5         printf("%d	",(*pd)[i]);//二维数组传入参数 利用指针可以用一级指针的方式进行保存
     6     }
     7     printf("
    ");
     8     for (size_t i = 0; i < 3; i++)
     9     {
    10         for (size_t j = 0; j < 4; j++)
    11         {
    12             printf("%d	",pd[i][j]);//二维数组进行二维数组下标的方式进行输出
    13         }
    14     }
    15 }
     1 void test()//数组指针vs指针数组
     2 {
     3     int(*pd)[10];//指针数组  数组的行号不定 列号为10 相当于pd[][10]
     4     int* dArr[10];//数组指针需要申请堆内存
     5     for (size_t i = 0; i < 10; i++)
     6     {
     7         dArr[i] = (int*)malloc(sizeof(int)* 4);//申请四个内存的空间 10行4列 相当于dArr[10][4]
     8     }
     9     for (size_t i = 0; i < 10; i++)
    10     {
    11         for (size_t j = 0; j < 4; j++)
    12         {
    13             dArr[i][j] = j;
    14             printf("%d	", dArr[i][j]);
    15             if (j == 3)
    16                 printf("
    ");
    17         }
    18     }
    19 
    20     for (size_t i = 0; i < 10; i++)//一个一个释放内存
    21     {
    22         free(dArr[i]);
    23     }
    24 }

    [] 解引用
    p[i]===*(p+i)


    基本数据 int x --->实参 写整数或者整形变量
    变量地址 修改变量的值 int*px 实参 变量地址
    数组名 操作一维数组 int *px /int arr[] 实参一维数组的数组名


    const 常属性 不可变 定义的还是变量
    通过语法限定 x的值不可以修改 必须先定义后赋值
    常量指针
    const int* p;//int const *p const限定了p不能修改他指向的内容
    指针常量
    int* const q;

     1 void test1()//const的妙用
     2 {
     3     int arr[10] = {0,1,2,3,4,5,6,7,8,9};
     4     const int* p;//const限定了这个p不能修改他指定的内容 即*p=0是错误的 
     5     p = &arr[0];//但是可以修改指针指向的地址  让p指向第一个元素
     6     p++;//也可以进行后移一位进行指向下一个地址
     7     //const在前*在后 是代表的常量指针
     8     printf("p的地址是:%p
    ", p);
     9     printf("p的值是:%d
    ",*p);//此时的p相当于p[1]===arr[1]
    10     
    11     
    12     //const在*后面   指针常量
    13     int* const q = &arr[0];//const 后面的q q在定义之后不能赋值
    14     //q = &arr[0];//q的值不可修改 只能修改*q的值
    15     *q = 0;//指针q可以去修改指向的内容
    16     //使用指针传参 提高了效率 修改形参值
    17 
    18 }

    指针传参 提高效率 修改形参的值

    函数指针 返回值为指针的函数 malloc作用申请内存 返回值是一个指针
    函数指针 指向函数的指针
    函数调用的过程 函数名--->函数 传递形参 计算 得到返回值 回到主函数

    1 void *(*pfun)(size_t _Size);
    2 pfun=malloc;
    3 //pfun指向函数的地址---->利用pfun来调用这个函数
    4 int *p=(int*)pfun(100*sizeof(int));

    指针地址效果简介

     1 #include<stdio.h>
     2 int main()
     3 {
     4     int x=3;
     5     int* p=&x;
     6     int y=5;
     7     *p=y;
     8     printf("p的值:%d
    ",*p);
     9     printf("p的地址:%d
    ",p);
    10     printf("x的地址:%d
    ",&x);
    11     printf("x的值:%d
    ",x);
    12     printf("y的地址:%d
    ",&y);
    13     printf("y的值:%d
    ",y);
    14     getchar();
    15     return 0;
    16 }

    指针效果整体代码

    #include<stdio.h>
    #include<stdlib.h>//malloc
    void fun(int arr[][5])//形参实际上是指针   int*arr  
    {
        int a=sizeof(arr[0]);//求的是形参的大小--->指针的大小
        int b = sizeof(arr);
        int c = sizeof(arr[0][0]);
        printf("arr[0]的大小为:%d
    ", a);//数组定义的第一个元素的大小
        printf("arr的大小为:%d
    ", b);//数组指针arr的大小 为4
        printf("arr[0][0]的大小为:%d
    ", c);
    }
    void fun2()//全局静态常量区
    {
        static int x = 0;//静态变量x 每次调用的时候运算结束 值都会改变
        ++x;
        printf("x=%d
    ", x);
    }
    void fun3(int(*pd)[4])//指针数组相当于int dArr[][4]
    {
        for (size_t i = 0; i < 12; i++)
        {
            printf("%d	",(*pd)[i]);//二维数组传入参数 利用指针可以用一级指针的方式进行保存
        }
        printf("
    ");
        for (size_t i = 0; i < 3; i++)
        {
            for (size_t j = 0; j < 4; j++)
            {
                printf("%d	",pd[i][j]);//二维数组进行二维数组下标的方式进行输出
            }
        }
    }
    
    void test()//数组指针vs指针数组
    {
        int(*pd)[10];//指针数组  数组的行号不定 列号为10 相当于pd[][10]
        int* dArr[10];//数组指针需要申请堆内存
        for (size_t i = 0; i < 10; i++)
        {
            dArr[i] = (int*)malloc(sizeof(int)* 4);//申请四个内存的空间 10行4列 相当于dArr[10][4]
        }
        for (size_t i = 0; i < 10; i++)
        {
            for (size_t j = 0; j < 4; j++)
            {
                dArr[i][j] = j;
                printf("%d	", dArr[i][j]);
                if (j == 3)
                    printf("
    ");
            }
        }
    
        for (size_t i = 0; i < 10; i++)//一个一个释放内存
        {
            free(dArr[i]);
        }
    }
    void test1()//const的妙用
    {
        int arr[10] = {0,1,2,3,4,5,6,7,8,9};
        const int* p;//const限定了这个p不能修改他指定的内容 即*p=0是错误的 
        p = &arr[0];//但是可以修改指针指向的地址  让p指向第一个元素
        p++;//也可以进行后移一位进行指向下一个地址
        //const在前*在后 是代表的常量指针
        printf("p的地址是:%p
    ", p);
        printf("p的值是:%d
    ",*p);//此时的p相当于p[1]===arr[1]
        
        
        //const在*后面   指针常量
        int* const q = &arr[0];//const 后面的q q在定义之后不能赋值
        //q = &arr[0];//q的值不可修改 只能修改*q的值
        *q = 0;//指针q可以去修改指向的内容
        //使用指针传参 提高了效率 修改形参值
    
    }
    void test2()
    {
        void *(*pfun)(size_t _Size);
        pfun = malloc;
        //pfun指向函数的地址---->利用pfun来调用这个函数
        int *p = (int*)pfun(100 * sizeof(int));
    }
    
    int main()
    {
        int arr[4][5];
        fun(arr);
        fun2();
        fun2();
        fun2();
        int dArr[3][4] = {1,2,3,4,5,6,7,8,10,9,11,12};
        fun3(dArr);
        printf("
    ");
        int *q = (int *)malloc(sizeof(int)* 100);//申请堆内存 第一个(int*)是强转 第二个(int)是申请int大小的空间
        
        if (q == NULL)
        {
            printf("申请失败");
            getchar();
            return 0;
        }
        //q指向了这块空间的首地址
        *q = 12;//===q[0]
        *(q + 1) = 13;//===q[1]
        q[2] = 14;//===(*q+2)
        q[3] = 15;
        for (size_t i = 0; i < 4; i++)
        {
            printf("%d
    ", q[i]);
        }
        q = (int*)realloc(q, sizeof(int)* 200);//把之前的100个int扩充到200个int
        printf("重新分配后
    ");
        for (size_t i = 0; i < 4; i++)
        {
            printf("%d
    ", q[i]);
        }
        printf("q的值%p
    ", q);
        free(q);//释放内存
        printf("q的值%p
    ", q);
        //内存释放后  q指向的空间就不要访问
        //q依然指向这个空间 释放之后再用就会出现问题
    
        int x=2;
        int *p = &x;//一级指针存放x的地址
        int **pp = &p;
    
        printf("x=%d
    ",x);
        printf("p=%d
    ", p);//x的地址====&x
        printf("pp=%d
    ", pp);//p的地址===&p
    
        printf("x的地址%d
    ", &x);
        printf("p的地址%d
    ", &p);
    
        printf("%d
    ", *pp);//x存放的地址===&x
        printf("%d
    ", **pp);//x的值===x
        printf("%d
    ", *p);//x的值===x
    
        test();
        test1(); 
        test2();
        getchar();
        getchar();
    
        return 0;
    }

  • 相关阅读:
    HTML5 ViewPort 资料收集
    [ASP.NET 技术点滴] Jquery 前端验证
    [转帖]Asp.NET 弹出页面
    [转]ASP.NET 页生命周期概述
    C#时间转整型(时间戳),模仿php strtotime函数的部分功能
    [转]使用微软的官方类库CHSPinYinConv获得汉字拼音
    [转]ASP.NET数据库连接字符串总结
    gradle 生成 pom,引用mybatis-plus源代码到自己的工程中
    困扰的问题终于解决了-docker时区不正确的问题修改记
    mybatis plus3.1.0 热加载mapper
  • 原文地址:https://www.cnblogs.com/liugangjiayou/p/11771808.html
Copyright © 2020-2023  润新知