前言
指针是C和C++都具有的一种直接操作内存地址的数据类型,它具有在程序运行期间直接操纵内存地址的能力,赋予了开发人员一种直观的操作内存地址的手段。引用是一个与指针相关联的概念,引用是C++引入的新语言特征,是C++常用的一个重要的内容之一。
(本文所有代码都运行过并且能很好地运行)
指针的概念和基本用法
指针的概念
要理解什么是指针首先需要对计算机存储器的内存规划和和如何存取数据进行了解,计算机在存储数据时会将存储器分为一个个小的存储单元,每个单元都会有一个十六进制的编号,这些编号就是每个存储单元的地址。
在c++中存取内存中的数据主要有两种方式,一种是通过变量名,另一种是直接通过地址的形式,第一种就不在赘述,对于第二种,就是通过指针来实现的。
指针是一种特殊的数据类型,其存储的就是内存的地址。指针所存储的地址所在的区域存储着一个值,也就是这个指针所指向的值。
指针所指向值可以是任何基本数据类型,也就是说每种基本类型都有其相应的指针类型。
指针变量的声明
在使用指针变量前,需要先声明指针。指针变量声明的语法格式如下:
数据类型* 指针变量名
1,需要注意的是,空格在“*”号的左边或是右边或是两边都是可以的,但是在数据类型和指针变量名之间至少有一个空格。
2,数据类型可以是C++任何类型和对象
3,指针本身也需要被储存,指针本身的值是unsigned long int类型的,占用四个字节的内存。
实际上,指针确实是一个地址,通常以十六进制表示。指针变量是用来存储这个地址的变量,它是指针的容器。指针变量存储的是内存中某个变量或对象的地址,而不是直接存储这个变量或对象的值。因此,指针变量存储的是指针,而指针本身代表的是内存地址。
下面依次声明了四个不同类型的变量,代码如下:
int* ptr;
double* ptr;
long* ptr;
char* ptr;
当一个指针变量被声明之后,系统就会分配四个字节来存储此指针变量
地址运算符
C++提供了两个内存地址运算符“*”,“&”。“*”称为指针运算符或者间接引用符,它的作用是取得指针所指向变量的内容,“&”是取地址运算符,它的作用是取得变量的地址。
参数说明如下:
1,指针运算符和取地址运算符都是一元运算符(“*”在表示乘法的时候是二元运算符,“&”在表示位运算的时候是二元运算符)。
2,指针运算符只能用于指针变量,不能用于非指针变量。
3,指针运算符既可以用于左值也可以用于右值。
示例:
int a=10;
int* ptr=&a;//指针变量ptr存储着a的地址;
cout<<&a;//输出的是a的地址
cout<<ptr;//输出还是a的地址,因为ptr存储着a的地址
cout<<*ptr;//输出的是指针所指向的值,即是10
值得注意的是,在定义指针时候也用到了“*”,这时候称其为指针定义符。和指针运算符定义完全不同,它的作用仅仅是表示所声明的变量的数据类型是一个指针。
指针的赋值
在声明了指针后,得到的是一个用于存储地址的指针变量。这时候指针变量中的值并没有被设定,也就是说此时指针指向的数据没有被设定。系统会自动生成一个随机数存入指针变量中。这时候无法确定指针到底指向哪个内存单元。如果恰巧指针所指向的内存单元存放着至关重要的数据(如操作系统核心数据等),而且在后面不当地访问指针,可能会导致数据破坏或者系统崩溃。因此在声明变量后,应该赋值后再使用。
对指针的赋值有以下两种方式。
(1)在声明指针变量的同时进行初始化赋值,其语法格式如下。
存储类型数据类型*指针变量名=初始地址;
(2)在声明指针变量后,单独使用赋值语句进行赋值,其语法格式如下。
指针变量名=地址;
参数说明如下。
赋值的时候,使用的地址来源有两种,第一种是某个变量或者对象的地址(利用&取地址运算符可以得到变量或对象的地址);第二种是动态开辟的内存的地址(后面将学习到)。
【示例7-3】用对象地址给指针变量赋值,代码如下。
long *plValue;
long 1Count =100;
plValue =&lCount;//赋变量地址
分析:注意指针变量也是一种变量,也可以对指针进行赋值。
【示例7-4】用指针的地址给指针变量赋值,代码如下。
long 1Count = 100;
long *plTemp = &lCount;
long *plValue = plTemp; //用plTemp给plValue赋值
如果在初始化时无法给定指针的具体地址,一般情况下将其初始化为 0 或者 NULL(针),以避免“野指针”(即不可控的指针)的出现。
【示例7-5】使用指针可能存在的危险举例,代码如下。
long *plValue;
*plValue = 2500;
分析: 本例中没有给 plValue初始化,也就是这个指针指向地址是未知的,此时2500将被存在一个未知的值。这就会造成程序错误。所以一定要在对指针应用(*) 操作符前,给指针初始化一个确定的、适当的地址。
【示例7-6】指针的初始化举例,代码如下。
double *pdValue1 = 0; //声明指针后立即初始化为0
double *pdValue2 = NULL; //声明指针后立即初始化为NULL
分析: 注意不能给地址指针直接赋非0 的整数值。
double *pdValue1 = 0x0000EF04; //这样的操作是错误的
声明了一种数据类型的指针之后,一般情况下这个指针只能指向这种数据类型的变量而不能能指向另一种数据类型的变量。例如,声明了 int类型的指针,只能让指针指向 int 类型的数据而不能指向 long 类型的数据。只有一种特殊类型除外,就是 void类型。可以存储任何类象地址,也就是任何类型的指针都可以赋给 void类型的指针。
指针运算
指针是一种数据类型,他和其他数据类型一样可以参与数据运算,如赋值运算,算数运算和关系运算。
(1)指针的赋值运算
指针的赋值运算是指将一个地址值赋给一个指针变量。这种赋值有以下三种情况.
1,可以将与指针变量同类型的任一变量的地址赋给指针变量。
2,可以将0赋给指针变量,其含义是初始化指针变量,使其值为“空”。实际上告诉系统指针值为0的指针变量不指向任何内存单元。
3,同类型的指针变量之间可以相互赋值。
(2) 指针的算术运算
指针的算术运算是指指针可以和整数进行加减运算。不过指针的加减运算和普通算在规则方面有所区别。
指针变量必须有类型,指针的算术运算和指针类型
ptr++
在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是