概述:
比较抽象的但又很有用的东西 0.0
void*指针:可以保存任何类型对象的地址。
指向指针的指针
函数指针
7.1 指针
一个有效的指针必然是一下三种状态之一:
1)保存一个特定对象的地址;
2)指向某个对象后面的另一个对象
3)0值。
若指针保存0值,表明它不指向任何对象。未初始化的指针是无效的,直到给该指针赋值后,才可使用。
注:*p++和(*p)++不等价,单目运算符*的优先级比++高,故*p++先完成取值操作,然后对指针地址执行++操作,而(*p)++是首先执行屈指操作,然后对该值进行++操作。
C语言允许用typedef说明一种新类型名,来代替已有类型名。
在typedef中使用指针会带来意外的结果。下面给出一个很多人容易理解错误的题:
typedef string *pstring; const pstring cstr;
上面的cstr是什么类型?简单的回答是const pstring类型的指针。进一步问:const pstring指针所表示的真实类型是什么?很多人都会认为真正的类型为:
const string *cstr;
即cstr是一个指针,指向string类型的const对象,但这是错误的。
错误的原因在于将typedef当作宏定义替换试的文本拓展了。声明const pstring时,const修饰的是pstring类型,这是一个指针。因此,该声明语句应该是把cstr定义为指向string类型对象的const指针,这个定义等价于:
string *const cstr;
7.1.1 void*指针
void*表明该指针与以地址值相关,当不清楚存储在此地址上的对象的类型。void*指针只支持几种有限的操作:
1)与另一个指针进行比较;
2)向函数传递void*指针或从函数返回void*指针;
3)给另一个void*指针赋值。
不允许使用void*指针操纵它所指向的对象。
需要注意的是,当函数返回void*类型时表示返回一个特殊的指针类型,而不是像函数返回类型为void那样表示无返回值。
7.1.2 指向指针的指针
字面理解就好^.^ 如下面的例子:
int i = 1024; int *p = &ival; int **pp = *p;
表示如图:
再看下面的例子(32位系统):
int main() { double* (*a)[3][6]; // a为指针 类型为 double*(*)[3][6]; cout<<sizeof(a)<<endl; // 4 :a为指针 cout<<sizeof(*a)<<endl; // 72 : *a为一个3行6列的数组 元素类型为double* 3*6*4 cout<<sizeof(**a)<<endl ; // 24 : **a为数组首元素*a[0],6*4 = 24 cout<<sizeof(***a)<<endl ; //4 : ***a是上面的一个元素double* cout<<sizeof(****a)<<endl ; // 8 : ****a为double return 0; }
7.1.3 函数指针
函数指针是指指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的函数类型,函数类型由其返回类型以形参表确定,而与函数名无关:
bool (*pf)(const string &, const string &);
这个语句将pf声明为指向函数的指针,它所指向的函数带有两个const string &类型的形参和bool类型的返回值。
函数指针只能通过同类型的函数或函数指针或0值常亮表达式进行初始化或赋值。
函数指针的使用
指向函数的指针可用于调用它所指向的函数。直接通过指针调用函数,若有:
typedef bool (*cmpFcn)(const string &, const string &); bool lengthCompare(const string &, const string &);
则:
cmpFcn pf = lengthCompare; lengthCompare("hi", "bye"); // 语句1
语句1为直接调用lengthCompare函数;
pf("hi", "bye"); // 语句2
语句2为利用函数指针调用lengthCompare函数,未使用*;
(*pf)("hi", "bye"); // 语句3
语句3为利用函数指针调用lengthCompare函数,使用*。
注:如果指向函数的指针没有初始化,或者具有0值,则该指针不能在函数调用中使用。只有当指针已经初始化,或被赋值为指向某个函数,才能用来调用函数。
函数指针形参
函数的形参可以是指向函数的指针。这种形参可以用以下两种形式编写:
void useBigger(const string &, const string &, bool(const string &, const string&));
等价于:
void useBigger(const string &, const string &, bool(*)(const string &, const string &));
返回指向函数的指针
函数可以返回指向函数的指针,但是,正确写出这种返回类型相当不容易 T.T :
int (*ff(int))(int*, int);
阅读函数指针声明的最佳方式是从声明的名字开始由里向外理解。
首先观察:
ff(int)
将ff声明为一个函数,带有一个int形参。该函数返回:
int(*)(int*, int);
它是一个指向函数的指针,所指向的函数返回int型,并带有两个分别是int*型和int型的形参。
使用typedef可使该定义更简明易懂,上面的声明等价于:
typedef int (*PF)(int *, int); PF ff(int);
注:允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。
具有函数类型的形参所对应的实参将被自动转换为指向对应函数类型的指针,但是,当返回的是函数时,同样的转换操作则无法实现:
typedef int func(int 8, int); // func是一个函数,而不是一个函数指针 void f1(func); // 正确,f1的形参是一个函数,func自动装换为函数指针 func f2(int); // 错误,func无法被自动转化 func *f3(int); // 正确,f3返回一个函数指针。
7.2 引用
引用就是对象的另一个名字。
所谓引用,其实就是一个特殊的变量,这个变量的内容绑定在这个引用对象的地址上,而使用这个变量时,系统就会自动根据这个地址去找到它绑定的变量,然后对这个变量进行操作。
所以本质上,引用其实还是指针,只不过这个指针是不能修改的,任何对它的操作都会发生在这个指针所指的地方。
需要注意的是,不能定义引用类型的引用,但可以定义任何其他类型的引用。
引用和指针的区别:
1)引用不能为空,当引用被创建时,它必须被初始化。而指针可以为空,可以在任何时候被初始化。
2)一旦一个引用被初始化为指向一个对象,它就不能被改变为对另一个对象的引用。指针则可以在任何时候指向另一个对象。
3)不能有NULL引用,必须确保引用是和一块合法的存储单元关联。
4)"sizeof(引用)"得到的是所指向的变量(对象)的大小,而"sizeof(指针)"得到的是指针本身的大小。
5)给引用赋值修改的是该引用所关联的对象的值,而并不是是引用与另一个对象关联。
6)引用使用时不需要解引用,而指针需要解引用,引用和指针的自增(++)操作运算意义不一样。
7)如果返回动态分配的对象或内存,必须使用指针,引用可能引起内存泄漏。
8)当使用&运算符取一个引用的地址时,其值为所引用变量的地址;而对指针使用&运算,取的是指针变量的地址。
最后一点,引用可以作为类的数据成员,但是必须用到初始化列表初始化,同时必须定义构造函数。
这一部分的内容也很少很集中,多做做题才能理解其中的精髓,希望大家都能有所收获~~ 0.0
返回目录 -> [C/C++基础--笔试突击] 概述