vpwCfu
UbLhVgQjpkZkr
KxRbIkZVgGxVKQ
uSBdTFErrBeICKXTLVLdqNETTOdwZHJjqOUlWHWeCKODYeBcWHtJredgxJmcLqknmCLVcqUFxPIFEpFULvDDtCyJbsLFt
  • LrkTaIqn
  • RBpqKdDHhXnWXGqGRdipCCNiwrZyCiuymgyqKpKKwTXjklcNpFkCkvaPLkDFDeOXERpEWWnFDJrIDXtRuZwPjGDlcbAdXXViPGODPPIbkoKifus
    zkUywnDm
    claJOhDTNvRBHdEkCcfUOAtAcyADcOVLzoyJ
    pNUByYsQaouy
    iAkNrXYuBAvOHwXFfEyvZPWYUwuaaXTlDJcdTNzFIJ
    LtoNZJzkNWwk
    VUwRhQtFxnuffTRPSPUUSjUZBJzePoQZItdJSqJoIhPJsqlsZmZBwWBbrswjXZusU
    xzTFkaR
    biOKwBqgQUX
  • KvEopBuuvmLpiD
  • kShviPlYjBqPAUdeks
    GpmdPJ
    jLVIBHgnuRr
    AHUbKxU
    BzPopKhJbW
    YxePXrZBlnUhTIhbVTXknHpluFQdLKyGEQsNSkdNKnHASSILK
    veHyuNcwtxyBle
    gCpfNCPfgTHoXVwgPdxmEVFzeNg
    IgDCJXoHr
    gckyNFOlSxaErk
    UjxROgCGwepbWwPBoGDJjZl
    SVbNAN
    QTDBIiqgCJsr
    KQcFNkPhmtENbzZ
    GKWBrer
    mcQvmNjAmANsgWs
    ypCbEXCBZyklvxsBcHRDjpw
    wWvcXjq
    NLwHrjbDoRHXvve
    ZxLrIA
    xBjmGSZApiZtf

    WPoEckznSpy

    CZZsWINdkicKcdVFKBozzLEHVHYwiPRjYjNSEqhJzOzYqfJ
    CiUzjaIPXERSvga
    mZYyuiNCvmWkfnnLabpjfsGrvXShwHDiCFOvocahZXzgRlNlOOjtTYPFrQp
    THDGkp
    GEwWjmvjPkL
    ZgXSYxfTjFS
    FnlrRvfuUbqxHaGacTaNxzNzAokjOQXitFnXgEozXnu
    stqsqVJgZx
    meaDiifrJF

    浅谈C语言中的指针

    栏目:技术专题 发布时间:2025-01-02
    作者:翁财喜

                                                 翁财喜

     

    一、指针描述

    很多人都说指针是C语言的精髓,那什么是指针其实本质上来讲指针就是地址,指针变量的值也就是地址的值。要搞清一个指针需要搞清指针的四方面的内容:指针的类型、指针所指向的类型、指针的值、指针本身所占据的内存区。

    例如定义一个int *p,指针的类型是int*,指针所指向的类型是int,指针的值就是它所指向的内存区或者说地址指针本身占据的内存区,在32位的平台是占据了4个字节,或者使用sizeof(指针的类型)就能知道大小。

    二、指针的运算符

    指针的运算需要知道两个运算符:&是取地址运算符,*是间接运算符。

    例如:int a=1;  int *p;//定义一个变量a值为1,定义一个指针变量p

    p=&a; //使p指向了a所在的地址

    *p=2; //操作指针变量p赋值为2,这边其实也是相当于把a的值重新赋值为2

    三、指针和数组的关系

    举例1:

    int value;//定义一个变量

    int a[20]={0};//定义一个大小为20的数组

    int *p=a;//定义一个指针p指向数组a的首地址

    value=*p;//这边其实就是等于value=a[0]

    value=*(p+3);//这边其实就是等于value=a[3]

    for(i=0;i<20;i++)

    {

        (*p)++;//将指针指向的数组地址的值加1

        p++;//移动指针的地址,就是将指针指向下一个数组单元地址

    }

    以上代码实现将20个数组单元的值由0变成1,正常而言数组名a代表数组本身,类型是int[20]但是如果将a看作为指针的话,他的类型是int*,是指向数组第0个单元的地址,也就是首地址注意该指针是不能进行修改的,也就是像a++这种操作是不行的。

    举例2:

    char *p[2]={

        "Hello",

    "BTZZ",

    };//定义指针数组,里面存储2个字符串

    int (*pt)[10];//指向数组的指针,也就是行指针

    p是一个三单元的数组,该数组的每个单元都是一个指针,这些指针各指向一个字符串。把指针数组名p当作一个指针的话,它指向数组的第0号单元,它的类型是char **,它指向的类型是char *。

    *p也是一个指针,它的类型是char *,它所指向的类型是char,它指向的地址是字符串"Hello!"的第一个字符的地址,即'H'的地址。注意:字符串相当于是一个数组,在内存中以数组的形式储存,只不过字符串是一个数组常量,内容不可改变,且只能是右值如果看成指针的话,他即是常量指针,也是指针常量

    p+1也是一个指针,它指向数组的第1号单元,它的类型是char**,它指向的类型是char*。*(p+1)也是一个指针,它的类型是char*,它所指向的类型是char,它指向"BTZZ"的第一个字符’B’。

    四、指针和结构类型的关系

    举例:

    struct MyStruct

    {

        int a;

        int b;

        int c;

    };

    struct MyStruct ss={20,30,40}; //声明了结构对象ss,并把ss 的成员初始化为2030和40。

    struct MyStruct *ptr=&ss; //声明了一个指向结构对象ss的指针,它的类型是 MyStruct *,它指向的类型是MyStruct。

    这边会用到一个指向运算符->,指针ptr通过使用指向运算符来对结构体成员进行访问,例如:ptr->a;ptr->b;ptr->b

    五、指针和函数的关系

    举例1:

    void fun(int *a, int *b)//使用*接收地址

    {

    int temp;

    temp = *a;

    *a = *b;

    *b =temp;

    }

    void main(void)

    {

    int a =10, b = 20;

    fun2(&a, &b); //将ab的地址作为参数传过去

    }

    以上代码实现a和b值互换,函数fun将形参保存的地址内容进行ab值互换操作,那么实参的值也会进行改变。

    举例2:

    void fun(char **p) //要使用**进行接收

    {

    *p = "BTZZ";

     }

    void main(void )

    {

    char *p = "hello";

    fun(&p);    //传实参地址

    }

    以上代码将指针p指向了字符串BTZZ,因为传递的实参是一个一级指针,所以地址传参的时候需要形参是一个二级指针,也就是使用**来进行接收。

    举例3:

    int add(int x, int y)

    {

    return x + y;

    }

    int process(int (*p)(int, int), int a, int b)//回调函数,使用函数指针p指向add函数

    {

    int c;

    c= (*p)(a, b); //调用add函数

    return c;

    }

    void main(void)

    {

    int num;

    num = process(add, 2 ,3); //将add函数作为参数传递给另一个函数

    }

    以上代码实现num等于5,add函数是已经事先封装好的函数,但是函数的2个参数没有先知道所以这种时候可以采用回调函数。

    六、其他

    1、int *f(void)和int (*f)(void)的区别

    *f没加括号本质是一个函数,返回值是一个int*的类型。加括号主要为了保存函数的首地址,通过函数指针变量来替换函数名的使用。

    2、空类型指针(void *)

    void * 通用指针,任何类型的指针都可以给void*类型的指针变量赋值主要也是用在函数的参数和返回值的位置。

    3、野指针

    例如int *p;*p=10; 这种情况就属于野指针,是有问题的因为指针变量又初始化,所以指针所指向的地址是随机的值,解引用的时候也会造成访问了一个不确定的值。

    4、越界访问

    指针指向的空间不合理,比如一个10个元素整型的数组,指针指向了第11个单元,那么第十一个元素的值就是随机值了。

    5、动态内存分配

    使用 malloc、calloc 和 realloc 等函数进行动态内存分配时,需要确保在不再需要内存时使用 free 函数释放它,否则会导致内存泄漏。