• C语言指针的一些易错点


    指针

    指针是一种数据类型,就像 int和 float,int 装整型数据,float 装浮点型数据,指针装地址型数据。

    C语言中的地址包括位置信息(内存编号,或称纯地址)和它所指向的数据的类型信息,或者说它是“带类型的地址”。

    指向是什么意思?简而言之,指针变量装哪块地址,它就指向哪一块空间。指针的类型决定着指针对存储空间的读写方式,所以首先指针与被指对象的类型要对应

    内存操作符“ * ”:一个指针p指向一个变量的地址,“ *p ”,就是这个变量本身。p所指向的空间是什么类型( 如int ),那么 *p 就一次操作多大的内存空间( 4字节 ),或者说指针的读写单位就是多大( 4字节 )。

    32位系统最大支持 4字节 指针,64位系统最大支持 8字节 指针。是指针所占空间大小,是装的地址值的空间大小,不是指针操作的空间大小。

    指针指向多维数组

    指针指向二维数组

    二维数组有三个类型的地址:

    int a[3][4];
    
    &a[0][0] ———— 元素的地址,且等价于a[0](一维数组的名字),数组名字就是首元素的首地址
    &a[0]	 ———— 一维数组的地址,且等价于a,数组名字就是首元素的首地址
    &a		 ———— 二维数组自身的地址
    
    a[i]	 ———— 二维数组的第i-1个元素,是一个一维数组,也是那个一维数组首元素的首地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果 a一维数组,则 a[i] 代表 a 数组下标为i的元素的存储单元。 a[i] 是一个有确定地址的存储单元

    但如果 a二维数组,则a[i]仅为一维数组(名),它只是一个地址,并不代表一个存储单元,也不代表存储单元中的值(如同一维数组名只是一个指针常量一样)。

    • 此时的 a[i] 是一维数组名,它是一维数组中起始元素 a[i][0] 的地址,指向的是 a[i][0] 这个整型数据。
    • a 是二维数组名,它指向的是 a[0] 这个一维数组。

    二者虽然地址相同,但指向的数据类型不同(基类型不同)。

    如果用一个指针变量 p 来指向一个二维数组的一维数组元素,应当这样定义:

        int a[3][4] = {{0},{0},{0}};
        // int (*p)[4] = a; 等价于 int (*p)[4] = a[0];
        int (*p)[4] = a[1];
    
    • 1
    • 2
    • 3

    (*p) 有四个元素,每个元素为整型。也就是 p 所指向的对象是有四个整型元素的数组,即 p 是指向一维数组的指针。此时 p 只能指向一个包含 4 个元素的一维数组,不能指向一维数组中的某一元素。

    这种情况多用于作函数参数,其他场景使用较少。

    指针指向二维数组的数据元素

    计算 a[i][j] 在数组中的相对位置(相对于数组起始位置的位移量/偏移量)的计算公式为:i*c+j,其中 c 为二维数组的列数(二维数组大小为 r×c )

    #include <stdio.h>
    
    int main()
    {
        int a[3][4] = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12}
        };
    
        //int* p = a;           // 左右类型不一致,非法操作,a==&a[0],为int(*)[4]类型
        //int(*p)[4] = a;       // p==a==&a[0],*p==a[0]==&a[0][0],**p==a[0][0]
        //int* p = a[0];        // p==a[0]==&a[0][0],*p==a[0][0]
        //int* p = &a[0][0];    // *p==a[0][0],(i*4+j)为指针偏移量
    
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                //printf("%-3d", *(*(p + i) + j) );  //int(*p)[4] = a;
                //printf("%-3d", *(p + (i*4+j) ) );  //int* p = a[0]; 
                //printf("%-3d", *(p + (i*4+j) ) );  //int* p = &a[0][0]; 
            }
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    指针指向字符(串)

    可以对字符指针变量赋值,但不能对数组名赋值

    char* a;           //定义a为字符指针变量
    a = "I Love You !" //将字符串的第一个元素的地址赋给a
    
    //等价于char* a = "I Love You !";
    
    • 1
    • 2
    • 3
    • 4

    使用字符数组时,只能采取定义数组时初始化逐个对元素赋值的方法,不能用赋值语句对字符数组中全部元素整体赋值

    char str[20];           //开辟20个储存字符数据的空间,并且str=str[0]的地址
    str[0] = 'I';           //对字符数组元素赋值,合法
    str = "I Love You !";   //数组名是地址,是常量,不能被赋值,非法
    str[] = "I Love You !"; //不能用赋值语句对字符数组整体赋值,非法
    
    • 1
    • 2
    • 3
    • 4

    指针变量的值是可以改变的,而字符数组名代表一个固定的值(数组首元素的地址),不能改变。

    char* a = "I Love You !";
    a = a + 3;
    printf("%s", a); // 输出:ove You ! 从a指向的字符开始的字符串
    
    • 1
    • 2
    • 3

    字符数组中的各元素的值是可以改变的(可以对它们再赋值),但字符指针变量指向的字符串常量中的内容是不可以被取代的(不能对它们再赋值)如:

    char a[] = "China";
    char* b = "Chinese";
    a[2] = 'r';  //合法,r取代i
    b[2] = 'e';  //非法,字符串常量不能改变
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    java spring cloud 企业电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展
    c++刷题常用stl用法
    思腾云计算
    RedisAssistant:一款Redis可视化管理工具
    子虔与罗克韦尔自动化合作 进博会签约自动化净零智造联创中心
    【教3妹学算法-每日1题】设计有序流
    Unity AI Sentis 基础教程
    都2022年了,不会实现接口自动化测试的你确定不来看看...
    layui柱状图tooltip获取x轴和y轴数据
    美国海运价格,美国专线直达怎么收费?
  • 原文地址:https://blog.csdn.net/jiang1126/article/details/125406410