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个元素,是一个一维数组,也是那个一维数组首元素的首地址

如果 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];

(*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;
}

指针指向字符(串)

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

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

//等价于char* a = "I Love You !";

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

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

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

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

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

char a[] = "China";
char* b = "Chinese";
a[2] = 'r';  //合法,r取代i
b[2] = 'e';  //非法,字符串常量不能改变

猜你喜欢

转载自blog.csdn.net/jiang1126/article/details/125406410