0
点赞
收藏
分享

微信扫一扫

C++指针、引用

1、取地址运算符、间接寻址运算符:

  • & 取地址运算符,返回变量的内存地址(指针)。
  • * 是间接寻址运算符(解引用),是 & 运算符的补充,返回变量所指定地址的变量的值。
#include <iostrem>

using namespace std;

main() {
int var;
int *p;
int val;

var = 3000;

p = &var;

val = *p;

cout<<var<<endl;
cout<<p<<endl;
cout<<val<<endl;
}

输出:3000、0xbff64494、3000

2、指针:

指针是一个包含了另一个变量地址的变量,变量可以是任意的数据类型,包括对象、结构、函数或者指针。必须在使用指针存储其他变量地址之前,对其进行声明。

2.1)指针变量定义:

1)type *var-name; 定义一个指定类型的指针变量。(注:这里的*和上面的间接寻址运算符不一样)

int *p;//一个整型指针
float *f;//一个浮点型指针
char *ch;//一个字符型指针

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

2)使用指针:

  • 使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。
  • 访问指定地址的变量的值,是使用*(解指针运算符)获取指向的类型变量。

2.2)对象指针

对象指针就是指向一个对象类型的指针,和其他类型的指针变量一样。

1)对象指针的定义:

类名 *对象指针名;

2)对象指针的使用:

和一般指针一样,使用解引用运算符(*)找到指针的内容——是一个对象,接下来可以用对象的点运算符(.)访问对象内部的属性和方法。

不过上述过程比较麻烦,C++中提供了一个->运算符,对象指针可以通过该运算符来访问对象的属性和方法。

#include <iostream>

using namespace std;
class Point {
public:
Point(int a,int b):x(a),y(b){}
int getX() {
return x;
}
int getY() {
return y;
}
private:
int x,y;
};

main() {
Point p(1,2);
cout<<"x:"<<p.getX()<<",y:"<<p.getY()<<endl;

Point *pp = &p;//定义对象指针,用p的地址初始化
cout<<"x:"<<pp->getX()<<",y:"<<pp->getY()<<endl;
cout<<"x:"<<(*pp).getX()<<",y:"<<(*pp).getY()<<endl;
}

3)this指针:

指向当前对象自己的指针。我们先来想一个问题:假设我们构造出很多个对象,当使用某个对象.方法来调用该对象的方法时,系统是如何知道该把哪个对象的属性、方法返回回来?

答案就是:

  • this指针隐含于类的每个非静态成员函数中;
  • 当通过对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针;例如:return x; 相当于 return this.x;

2.3)函数指针

函数指针就是指向一个函数的指针(实际上代码中的函数也是有地址的),指向函数的首地址。

1)函数指针的定义:

数据类型 (*函数指针名)(参数表);

2)为什么使用函数指针?

我们都知道,函数都是通过函数名来访问的,函数指针的典型用途——实现函数回调。

  • 通过函数指针调用函数:将函数的指针作为参数传递给一个函数,使得在处理类似事件的时候可以灵活的使用不同方法;
  • 调用者不关系谁是被调用者;

3)函数指针使用:

  • 先定义一个函数A,某个参数是函数指针类型;
  • 定义具体函数B,在main方法中调用函数A时,把函数B的地址传递进去(通过取地址运算符);
#include <iostream>

using namespace std;

int compute(int x,int y,int(*fun)(int,int)){
return fun(x,y);
}

int max(int x,int y) {
return (x>y)?x:y;
}

int sum(int x,int y) {
return x+y;
}

main() {
int z = compute(10,3,&max);
cout<<"max:"<<z<<endl;

z = compute(10,3,&sum);
cout<<"sum:"<<z<<endl;
}

3、引用:

引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样(反之也一样)。使用&作为引用的时候,必须在定义时候就进行初始化,若不进行初始化则会编译报错。

1)引用变量的定义:

通过&定义了一个引用变量,类型名 &别名 = var;

#include <iostream>

using namespace std;

main() {
int n;//default 0
int &rn = n;

cout<<"n:"<<n<<",rn:"<<rn<<endl;

n=10;
cout<<"n:"<<n<<",rn:"<<rn<<endl;

rn--;
cout<<"n:"<<n<<",rn:"<<rn<<endl;
}

输出:

n:0,rn:0

n:10,rn:10

n:9,rn:9

2)引用和指针的区别:

  • 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
  • 不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
  • 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
  • 引用没有const,指针有const,const的指针不可变;
  • “sizeof 引用”得到的是所指向的变量(对象)大小,而“sizeof 指针”得到的是指针本身的大小;
  • 指针和引用的自增(++)运算意义不一样;
  • 引用是类型安全的,而指针不是 (引用比指针多了类型检查)

为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。

4、指针的引用:

指针是一种类型,所以可以有指针的引用,但是没有引用的指针。

1)指针的引用定义:

类型 *&变量 = 指针;

  • 因为是引用,所以声明时需要赋值
  • 指针的引用比较特殊,本质上就是一个指针的别名,所以使用上和指针一样。
main() {
int i=5;
int *p = &i;
int *&pr = p;//指针的引用,与p指向同一个变量i

cout<<"i:"<<*p<<" "<<*pr<<endl;

i = 10;
cout<<"i:"<<*p<<" "<<*pr<<endl;

cout<<"address:"<<p<<" "<<pr<<endl;//指针的引用其它就是指针p的一个别名和p有相同的地址
pr = NULL;//该引用比较特殊,本质也是个指针,所以可以赋null
cout<<"address:"<<p<<" "<<pr<<endl;
}

输出:

i:5 5

i:10 10

address:0x7fff1810cd5c 0x7fff1810cd5c

address:0 0

2)函数传参:

5、指针的指针:

1)指针的指针定义:

类型 **变量名

指向指针的指针是一种多级间接寻址的形式。通常,一个指针包含一个变量的地址,当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。

所以,需要使用两层解引用才能获取到指针的指针指向的内容。

main() {

int a = 2;
int *ptr = &a;
int **pptr = &ptr;

cout<<"a:"<<a<<",ptr:"<<*ptr<<",pptr:"<<**pptr<<endl;
a =10;
cout<<"a:"<<a<<",ptr:"<<*ptr<<",pptr:"<<**pptr<<endl;
}

输出:

a:2,ptr:2,pptr:2

a:10,ptr:10,pptr:10

2)函数传参:

6、总结:

&有两种用法:

  • 取地址运算符,赋值给指针变量;
  • 引用变量、参数;

*有两种用法:

  • 间接寻址运算符(解引用);
  • 定义指针变量;

:在googleC++规范中,声明指针变量或参数时, 星号与类型或变量名紧挨都可以。如:

//空格前置
char *c;
const string &str;

//空格后置
char* c;
const string& str;

 

 

 


举报

相关推荐

0 条评论