C/C++指针与const、数组、函数

本文介绍了C/C++中const、数组和函数与指针的结合使用,包括常量指针、指针常量、指向常量的常量指针的定义和使用,指针数组与数组指针的区别,以及函数指针和指针函数的概念。文章通过实例详细解释了各种指针类型的定义和操作,并提供了如何区分和使用的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C/C++中指针是灵活多变,可以指指向任意地址,但是地址有可以存储任意对象,因此指针与其它对象的定义结合在一起,功能和作用是不同的,很容易混淆,尤其是const、数组和函数。

 下面分别介绍一下const、数组、函数与指针一起时在如何使用,有点像绕口令。

 

1、const与指针

const用来修饰不变量,const与指针结合在一起,有多种称谓和定义,例如: 常量指针、指针常量(指向常量的指针)、指向常量的常量指针。

中文中,两个或多个次名次在一起的时候,通常最后一个词才是关键词,表示整个词组的意义,而前面都是修饰性的。这样看来看,就比较容易搞清楚各种称谓的意义。

常量指针(const指针),根据上面的分词定主语,表示这是一个指针,是一个常量指针,也就是说,指针是一个常量,给这个指针赋值一个地址之后,不能再改变指针的指向,但是可以修改地址所存的对象(值)。

指针常量(指向常量的指针),表示一个指向常量的指针,也就是说,指针是所指的地址是可以变化的,但是每个可以赋值给这个指针的地址所存的对象是常量。

指向常量的常量指针,这个是非常明确的,指针是常量类型的, 指针所指的地址存储的对象也是常量。

如何定义和使用者三种指针呢,直接来例子吧:

int  a = 1;                                  //定义一个变量;

const int b = 2;                        // 定义一个常量;

const int c = 3;

const int * pa = &b;               // 定义一个指向常量的指针;

pa = &c;                                  //OK, pa是一个指向常量的指针,c和b都是常量,其地址也是常量;

pa = (int*)c;                            //OK, pa是一个指向常量的指针,c和b都是常量;

pa=(int*)100;                        //OK, pa是一个指向常量的指针, (int*)100是一个常量地址

int const * pb = &c;               //OK, pb也是一个指向常量的指针,

int * const pc = &a;              //OK, pc是一个常量指针,

pc=&a + 1;                            //Error,pc是一个常量指针,赋值之后,不能修改指针所指,一辈子只能指向a的地址;

const int* const pd = &b;  //OK, pd是一个指向常量的常量指针, b是常量, b的地址也是常量;

 

我们看到红色字体这四个指针的定义,前面两个(pa,pb)都是指向常量的指针,pc是一个常量指针,pd是一个指向常量的常量指针;

很多人很难区分pa,pb,pc这三种定义,有一个简单办法,那就是以 * 号来分割,const在 * 号左边的是表示修饰指针所指的地址存储的值,而const在*号右边的表示修饰指针本身。

 

2、数组与指针

数组与指针,在大家的印象中,和日常工作中经常使用指针来操作数组, 但是数组和指针还会结合在一起定义使用,因此就出现了指针数组和数组指针。

从概念上区分,是很简单的,还是根据修饰词和关键词来判断。

指针数组:它本身是一个数组,数组里面的元素是指针;

数组指针:它本身是一个指针,是指向数组的指针;

下面看看这两种情况怎么定义和使用:

short (*paa)[20];

short *pbb[20];

如何区分指针数组和数组指针呢,也很简单,"*", "[]", "()"都是运算符, 而运算符有优先级和结合性,而优先级从高到低分别是"()", "[]", "*"。

这样很容易区分上面paa和pbb的意义, paa先与*结合,说明paa是一个指针,然后与[]结合,就paa是一个指向数组的指针;

而pbb没有使用"()", 那么pbb先与[]结合,说明pbb是一个数组,然后再与*结合,说明pbb是一个数组,数组元素是指针。

从使用上来说,指针数组,可以看成是一个一般的数组,其元素的类型变成某某指针。

而数组指针,通常用来访问数组的,一般我们用指针访问访问一维数组, 那么数组指针,根据其数组的维数,通常是访问更高一维的数组,因为指针可以表示一维, 但是也可以访问同维度的数组,但是这个时候,指针取值相当于数组定义时数组的名称。

 

需要注意的是指针数组在进行 +1 和自增操作的时候,地址偏移的长度是数组的维数和类型相关。

 

    short aa[20] = {10, 20, 30, 40, 50, 60};
    short (*paa)[20] = &aa;                             //paa是一个数组指针,指向的是一维数组,paa相当于一个二维数组, 因此paa相当于aa的地址,而*paa相当于数组名称

    cout<<"*paa[1]="<<*paa[1]<<endl;         //注意结合性这里,paa[]先结合,因此这里paa[]表示数组的第一维,也就是paa指针所表示的那一维,但是paa指向的是一个一维数组,因此这里访问是非法的
    cout<<"(*paa)[1]="<<(*paa)[1]<<endl;   //这里*paa表示数组aa,因此(*paa)[1]等同于aa[1];

下面是通过一个指向一维数组的指针来访问二维数组

    short  bb[3][20] = {{1,2,3,4,5,6},{10, 20, 30, 40, 50, 60},{100, 200, 300, 400, 500, 600}};
    paa = bb;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            cout<<paa[i][j]<<",";
        }

        cout<<endl;
    }

 

3、函数与指针

函数和指针的结合在概念上与前面的数组、常量与指针结合类似,存在函数指针和指针函数两个称谓,采用同样的分析方法,我们来看一下他们概念上的区别。

指针函数,本质上是一个函数,只是这个函数的返回值类型一定是某某指针类型,在编码中,经常使用从函数中返回一块内存地址;

函数指针,本质是一个指针,但是这个指针是指向函数的,也许不好理解,我们通常的指针指向的是某个变量的地址,指针本来就是为了给程序员方便的访问地址而出现的,因此指针指向函数也是很自然的事情。

函数指针在较大型的C项目或者用C来实现面向对象编程的时候常用的,也有人说C用函数指针可以实现“多态”,应该说是模仿吧。我们不发散了,下面看看是如何定义使用。

 

指针函数:

int*  func();                                                   //返回值为int* 类型的指针函数;

char* getName(struct Person* p);         //返回值为char*类型的指针函数;

函数指针:

int  (*pFunc1)();                                         //返回值为int类型的函数指针,这里实际上是定义一个类型,函数没有输入参数

char (*pFunc2)(struct Person*p);          //返回值为char类型的函数指针,也是定义一个类型,  struct Person*p 是输入参数;

 

从上面的定义上,很容易区分,关键还是看"*"和名称后面的"()"操作符级别和结合性, 由于"()"操作级别比"*"高,但是前面的"()"可以改变优先级。

 

使用指针函数需要注意两点:

1)指针函数返回的是一个地址,也就是一块内存,要注意不能返回局部变量的地址,也就是栈的地址,否则可能出现不可预料的问题;

2)指针寒暑返回的地址, 如果是全局变量的地址,那么函数就是不可重入的,就是线程不安全的;

 

前面的pFunc1和pFunc2都是定义一个函数指针的类型,在编程中,通常通过typedef 来定义类型,就像定义结构体一样。

例如: typedef int* (*PFUNC)(int a, const char* str );

定义了一个函数指针类型,它可以用来表示一种函数的签名,两个参数,分别是int和const char*类型,返回的值是int*, 注意哦,返回的是int*,那么也说它是一个指针函数了, 不要想那么复杂,下面来看如何用这个类型来定义一个函数指针,例如:

PFUNC pf;

如果你的代码中定义了两个个如下的函数 

 int* testABC(int a, const char* str){...};

int* testDEF(int a, const char* str){...};

那么可以将testABC和testDEF赋值给pf,如下

pf = testABC;               //pf=&testABC 也可以,C语言规定函数名会被转换为指向这个函数的指针

(*pf)(100, "abc");

pf=testDEF;

(*pf)(200, "def");

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值