[C/C++基础--笔试突击] 7.指针与引用

概述:

  比较抽象的但又很有用的东西 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++基础--笔试突击] 概述

时间: 2024-12-22 23:14:00

[C/C++基础--笔试突击] 7.指针与引用的相关文章

[C/C++基础--笔试突击] 5.C预处理器、作用域、static、const、内存管理

概述: C预处理器处理程序的源代码,在编译器之前运行,通常以符号#开头. 还会涉及到static.const的知识点...有的和java类同...有的容易混淆T.T. 本章很多以前都没有接触过,在笔试中见过...如果有什么错误,欢迎指正~~ 5.1 C预处理器 C语言的预处理主要有三个方面的内容: 1)宏定义与宏替换: 2)文件包含: 3)条件编译. 考点比较少,讲述一下对应需要注意的地方. 宏替换的本质很简单--文本替换.关于宏定义与宏替换请注意一下几点: 1)宏名一般用大写,宏名和参数的括号

[C/C++基础--笔试突击] 6.函数

概述: 函数是有名字的计算单元,对程序的结构话至关重要. C++中,函数原型就是函数的声明,要加上分号. 这一部分还是比较轻松的~~ 6.1 参数传递 形参:出现在函数定义中,在整个函数体内都可以使用,函数体结束后被收回. 实参:主函数中调用,进入被调函数后,实参不能使用. 形参和实参的功能是数据传送,发生函数调用时,主调函数把实参的值传给被调函数的形参,从而实现主调函数向被调函数的数据传送. 函数调用时,C里面的两种传递: 1)值传递 2)指针传递(严格来说也属于值传递,只不过传递的是地址)

[C/C++基础--笔试突击] 4.运算符及优先级

概述: 表达式,由操作数和运算符组成. 笔试中通常的考点有操作符的优先级.异或等关系运算. 4.1 赋值语句 赋值运算符"=",操作符左边代表着存储单元的地址,称为左值,右边带表着需要的值,称为右值. 注:赋值操作符的左操作数必须是非const的左值. int const& max(int const& a, int const& b) { return a > b ? a : b; } int& fun(int& a) { a += 5;

C++基础之数组、指针与引用

一维数组的声明 ``` 数组类型 数组名 [常量表达式] ``` 常量表达式表示的是数组的个数,即数组的长度,且不能是变量. 一维数组的引用 ``` 数组名 [下标] ``` 一维数组的初始化 1.逐个对元素赋值 ``` char a[3] a[0] = 'a' a[1] = 'b' a[2] = 'c' ``` 2.聚合方式赋值 ``` int a[12] = [1,2,3,4,5,6,7] ``` 二维数组 ``` 数组类型 数组名 [常量表达式1][常量表达式2] ``` 下标运算中的整数

【C++基础】sizeof 数组 指针 空NULL

笔试遇到很多sizeof的小题,博主基础堪忧,怒总结如下,还是要巩固基础啊啊啊! sizeof操作符 对象所占内存空间的大小,单位是字节 关键词:char  数组 指针 结构体 sizeof(NULL) 结果为1 1.基本类型占内存大小   32位机     64位机器 类型 字节数       int 4       char 1       指针 4     8 float 4 浮点型     long 4       double 8 双精度浮点型     2.sizeof(指针)  任意

c++基础知识篇:指针

从面试的反馈来看,这部分可以问的很难. 1.指针与引用的区别 指针是一个变量,用来存放地址的变量.引用是原来变量的存储空间的别名. ? 2.指针作为参数的要点 a.需要进行指针的合法性检验,防止空指针. b.需要修改指针本身指向的地址时,参数需要是该指针的引用. ? 3.c++程序运行空间 数据区(Data Area):全局变量.静态变量.常量存放在数据区. 代码区(Code Area):所有类成员函数和非成员函数 栈区(Stack Area):为运行函数分配的局部变量.函数参数.返回数据.返回

C语言基础学习3:指针

1.地址和指针的概念 一个变量的地址成为该变量的“指针”. 如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”,指针变量的值(即指针变量中存放的值)是地址(即指针). 指针是一个地址,而指针变量是存放地址的变量 2.变量的指针和指向变量的指针变量 2.1指针变量的定义 指针变量的定义:基类型 *指针变量名: int a; int *pointer; pointer = &a; 2.2指针变量的引用 指针变量中只能存放地址,不能将一个整数赋给一个指针变量. “&”和“*

C语言基础学习8:指针数组

一个数组,若其元素均为指针类型数据,称为指针数组,指针数组中的每一个元素都相当于一个指针变量. 一维指针数组的定义形式为: 类型名 *数组名[数组长度]: 例如:int *p[4]; []的优先级比*高,因此p先与[4]结合,形成p[4]形式,这是数组形式,然后再与p前面的"*"结合,"*"表示此数组是指针类型的,每个数组元素都可指向一个整型变量. 为什么要用到指针数组呢? 因为它比较适合于用来指向若干个字符串,使得字符串处理更加灵活. 1 #include <

【C++ 基础 11】 函数指针总结

在家学习的效率真是惨不忍睹.. =========================== 1 指针函数 int* f(int a, int b); 返回一个指向int类型的指针. 2 函数指针 2.1 声明 返回类型 (*函数名)(参数列表); 2.2 示例 int max(int a, int b) { return a > b ? a : b; } int min(int a, int b) { return a < b ? a : b; } int (*f)(int, int); // 声