复合类型、函数与C++基础——指针与引用

程序中定义的变量会被分配一定的内存单元,当需要存取这个变量的值时,可以通过变量变量的名字访问这块内存。除了直接通过名字访问变量的内存单元外,也可以通过内存地址找到存放数据的单元,间接访问其中的内容。由此引出了指针和引用。

指针

int *ptr;  
char *ptr;  
int **ptr;  
int (*ptr)[3];  
int *(*ptr)[4]; 

每个指针都有相关的类型,如以上代码所示,在定义指针时,应按照:指针类型 *变量名 的格式来定义,应该对指针进行初始化。

指针存放的是它指向对象的地址,如果要获取对象的地址,使用取地址运算符“&”。

int a=100;
int *p=&a;

指针本身也是对象,有两个存储单元与指针有关,一个是指针自己的存储单元,存放着所指对象的地址,另一个是所指对象的存储单元,存放着该对象的值。

如果指针指向一个对象,那么可以通过指针来间接地访问这个对象,此时需要用到解引用运算符“*“;

int x=100'y=20;
int *p=&x;
*p=y;

通过指针的操作,间接地改变了x的值,这就是指针的基本运用。

定义指针时指定的类型实际上是指针指向对象的类型,指针不能指向不同类型的对象。

同时,指针不能保存非地址值,也不能被赋值或者初始化为不同类型的地址值。

int x=100;
int *p=&x;
int *p1=x;      //x不是地址,错误
double y=20;
p=&y;           //y与x的类型不同,编译错误

指针值为0的值称为空指针,即不指向任何对象的指针。目前有三种空指针的表示方法,代码展示如下:

int *p=nullptr;

int *q=0;

#include<cstdlib>
int *w=NULL;
不能写成以下格式:
int d=0;
int *g=d;       //d不是地址,错误

注意:解引用只适用于确实指向某个对象的指针,不能对空指针解引用。

指针比较及算数计算

同类型的指针存放的地址相同,则他们相等,反之则不等。比较的结果是布尔类型。

指针进行算数运算时,是地址值进行增加或减少。这是增加或减少的数目取决于指针的类型。自加自减运算同样适用于指针。指针只有指向数组元素时,其算数运算才有意义。

int a=10;
char b='k';
int *p=&a;
char *q=&b;
p++;            //int占四个字节,在原地址加4
q++;            //char占一个字节,在原地址加1

void*指针

C++提供的通用指针,它持有任何类型的地址值。void指针只能传送地址或者与其他地址值比较,不能操纵void指针指向的对象,也不允许void指针到其他指针的直接赋值。如:

int a=10;
char b='k';
void *pv=&a;
pv=&b;
int *q=pv;         //错误,应该是用强制类型转换

数组与指针

在c++语言中,指针与数组有着紧密的联系。除了使用下标访问数组元素之外,还可以使用指针对数组进行访问。

int a[10];
for(int *p=a;p<a+10;p++)      //a与&a[0]都表示数组第一个元素
    cout<<*p;

c++中以为数组元素在内存中按下标顺序依次存放,啊a[i]在内存中的地址是a+i

多维数组在内存中按行序存储。a[i][j]在内存中的地址是a+(i*n+j).

在指针访问数组时要控制指针的范围指向数组的元素。

为了使用更方便,C++11引入两个库函数begin()和endl(),在头文件<iterator>中定义。

begin(数组名):返回指向数组第一个位置的指针

endl(数组名):返回指向数组最后一个元素的下一个位置的指针

使用如下:

int *p=begin(arr),*q=endl(arr);
while(p!=q&&p>=0)
    ++p;

指针加或减一个整数n,结果仍是指针。新指针指向的元素与原来的指针相比前进或后退了n个位置。指针加或减一个整数,得到的新指针仍需指向同一数组的其他元素。

两个指针相减的结果是它们之间的距离。参与运算的两个指针必须指向同一个数组中的元素。
两个指针如果指向同一个数组的元素,可以利用关系运算符对其进行比较。如果两个指针分别指向不相关的对象,则不能比较。
 

new和delete(动态存储空间的管理)

new:分配特定类型的单个对象,并返回地址值;

          在堆上分配指定类型和大小的数组,并返回数组首地址,但不能对数组进行显示初始化;

          允许程序员将对象创建在已经分配好的内存上。

int *p=new int;
*p=123;
int *q=new int(100);

int *o=new int[100];

#include<iosteam>
#include<new>
using namespace std;
char* a=new char[1000];
int main(){
int *u=new(a)int;
      //在a上创建一个int对象,此时不再重新从堆上分配空间
}

delete

对堆上使用之后空间释放,防止内存泄漏。

形式:delete 指针;

           delete [] 指针;//释放数组

注:delete之后的指针不是空指针,而是空悬指针,指向不确定的单元。

引用

引用分为左值引用和右值引用。这里主要总结一下左值引用。

引用的基本规则:

声明引用的时候必须初始化,且一旦绑定,不可把引用绑定到其他对象;即引用必须初始化不能对引用重定义;

对引用的一切操作,就相当于对原对象的操作。

定义左值引用:类型 &引用变量=初始值;

int a=100;
int &b=a;

int x=100,y=20;
int &w=x;
w=y;       //x=y

引用与指针的区别:

一个指针可以指向同类型的不同对象,引用是一个对象的别名。定义引用时必须有内存地址的对象初始化。初始化之后,一直绑定对象。

指针通过解引用间接访问指向对象,引用作为变量别名直接访问对象;

指针可以不指向对象,引用必须一直绑定对象,不存在“空引用”;

指针之间的相互赋值会改变指向关系,引用之间相互赋值,引用关系本身并不改变。

右值引用简述

        右值引用的基本语法type &&引用名 = 右值表达式;

        右值引用在企业开发人员在代码优化方面会经常用到。

        右值引用的“&&”中间不可以有空格。

猜你喜欢

转载自blog.csdn.net/Lj135328/article/details/88760652