第七章

来源:互联网 发布:chinanet连接软件 编辑:程序博客网 时间:2024/05/16 11:36

**

函数和数组

**
C++将数组名解释为其第一个元素的地址,该规则有些例外:
1、数组声明使用数组名来标记存储位置。
2、对数组名使用sizeof()将得到整个数组的长度。
3、将地址运算符&用于数组名是,将返回整个数组的地址。
在C++中,当且仅当用于函数头或函数原型中时,int* arr和int arr[]的含义才相同
将指针(包括数组名)加1,实际上是加上了一个与指针指向类型的长度相等值,所以对于遍历数组而言,使用指针加法和数组下标时等效。
为将数组类型和元素数量告诉数组处理函数,务必通过两个参数传递:

void fillarray(int arr[], int size);

不要试图使用方括号表示法来传递数组长度!!

void fillArrary(int arr[size]);//错误!错误!错误!

在数组参数的函数中,如果不对数组进行改动的话,需加上const(不加也行,没人管你,但是最好不要作死):

void show_array(const double ar[], int n);//对于不改变数组内容的,加上const!

**

const与指针

**
一般有三种方式:
1、const int* pt;
2、int* const pt;
3、const int* pt;
分别说一下:
1、叫指向const的指针。举个栗子:

int age = 19;int age2 = 20;const int* pt = &age;*pt = 30;//错误!!不能改变指向位置的值!pt = &age2;//这没毛病,可以修改指向位置。此时pt指向了age2。

虽然age不是const类型,但是,pt指针是指向const int类型,也就是说,如果通过指针访问age,那就是const类型的。不能通过pt修改age的值!但是可以改变pt的指向位置。
那牵扯到这个赋值的话,又有四种情况:

//非const赋值非const,没任何毛病int age = 19;int* pt = &age; //非const赋值const,也没问题,就是不能通过pt修改age的值了int age = 19;const int* pt = &age; //const赋值非const,错误!错误!错误!因为这样定义说明能通过pt改变age的值,但是age又为const,这就尴尬了啊!const int age = 19;int* pt = &age;//const赋值const,也没任何毛病,两个都别动了const int age = 19;const int* pt = &age;

2、叫const指针,也就是pt是const类型的,不允许改变它指向的位置!但可以通过它改变指向位置的值,也就是pt不能再指向别的变量,但是pt可以修改age的值

int age = 19;int age2 = 20;int* const pt = &age;*pt = 30;//没毛病,可以改变指向位置的值!此时age值为30。pt = &age2;//错误!!不可以修改指向位置。

另外关于const指针要说的一点是:创建时必须初始化!不许留空。而指向const的指针则没有这个问题。

int a = 1;int* const ptr;//这种只创建,后续再初始化的,错误!!会报错!!ptr = &a; 

3、叫做指向const的const指针,说白点就是不允许改变指向的位置,也不允许改变指向位置的值!

int age = 19;int age2 = 20;const int* const pt = &age;*pt = 30;//错误!!!不可以改变指向位置的值!pt = &age2;//错误!!!不可以修改指向位置!

另外,至于直接通过age来改变值的话,这个过程是跟指针没关系的,只参见age是不是const。
总结一下就是:

const int* pt;// *pt是const的,不允许修改*pt的值,也就是所指变量的值。int* const pt;//  pt是const的,不允许修改 pt的值,也就是所指变量。

**

指针数组,数组指针

**
简单就说一句:

int (*p)[4]; //数组指针,p先跟*结合,说明p是一个指针,指向含有4int元素的数组。int* p[4]; //指针数组,p先跟[]结合,说明p是一个数组,数组包含4个指向int的指针。

数组指针一般见于二维数组,因为二维数组是用数组当元素填充一维数组得到。
指针数组一般见于排序。

**

函数指针

**
函数地址
函数名即为函数地址。add()是个函数,则add就是函数地址。
声明函数指针

int add(int, int);//函数int (*pf)(int, int);//函数指针int* pf(int, int);//注意区分,此pf为函数,参数为int,返回值为int*pf = add;//声明指针后,可以直接将函数名赋值给指针。注意,特征标和返回类型都必须与pf相同。其实特征标与返回类型就定义了pf的类型,类型不同的话,肯定不能赋值。//其实有了auto后非常方便,上两句定义和赋值直接合并成一句就好了:auto pf = add;//auto会自动推断auto pf = &add;//这样也行,完全不影响利用。//调用函数时,函数名和指针名都可以,没区别,以下三种都可以!add(3, 4);pf(3, 4);//这两种都好用,没区别,神奇~(*pf)(3, 4);////其实定义函数指针最重要的用途就是将函数作为参数传入另外一个函数!举个栗子:int operation(int a, int b, int (*pf)(int, int));//具有函数参数函数的原型。也是一个典型的函数指针用法,定义一种运算函数,数据两个,运算规则是现传入的运算函数来规定。//调用的时候:operation(3, 4, add);//传入函数名即可operation(3, 4, pf);//如果上方赋值了,传入pf也好用。

简单说一下函数指针和数组结合起来绕的地方:

double* (*pa[3]) (double, int*);

逐步说:
首先pa跟[3]结合,说明pa是一个包含3个元素的数组
之后pa[3]跟*结合,形成*pa[3],说明pa包含的3个元素为指针
最后这三个指针指向什么呢,指向一种类型的函数,这种函数的类型为:(double, int*) -> double* 类型。
再至于套好几层数组和函数的那种就算了吧。。。

其实在c11中,auto和typedef的引进,已经将上述过程简化并梳理了:

//定义函数指针并赋值:auto pf = add//简化函数类型定义:typedef double* (*p_fun) (double, int*);//定义这种函数类型的指针名称为p_funp_fun pa[3]//具有3个这种类型元素的数组  

尽量将每步进行梳理和定义才是保证可读性的根本,全都攒在一起的花式炫技法其实并没有什么卵用,但是需要知道,确实是可以那么写。

原创粉丝点击