C++指针(pointer)

C++指针(pointer)

 

在计算机科学中,指针(Pointer),是编程语言中的一类数据类型及其对象或变量,用来表示或存储一个存储器地址,这个地址的值直接指向(points to)存在该地址的对象的值。

 

指针的概念

指针(pointer)是一个特殊的变量,它里面存储的数值被解释为内存里的一个地址。

指针是操作系统内存的重要途径。指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。指针所指向的内存区就是从指针的值所代表的那个内存地址开始的,长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。

指针变量本身所占据的内存区的大小,可用函数sizeof(指针的类型)测得。

 

取地址运算符& :作用于内存中一个可寻址的数据(如变量、对象和数组元素等等),操作的结果是获得该数据的地址。

间接寻址运算符* :作用于一个指针类型的变量,访问该指针所指向的变量。也称为取内容运算符,或间接引用运算符。

 

如果一个变量声明时在前面使用 * 号,表明这是个指针型变量。换句话说,该变量存储一个地址,而 *(此处特指单目运算符*,下同;C++语言中另有双目运算符 * 表示乘) 则是取内容操作符,意思是取这个内存地址里存储的内容。把这两点结合在一起,可将 int *a;看作是 “*a 解得的内容类型为 int”。指针是 C++语言区别于其他同时代高级语言的主要特征之一。

指针不仅可以是变量的地址,还可以是数组、数组元素、函数的地址。通过指针作为形式参数可以在函数的调用过程得到一个以上的返回值(不同于return z这样的仅能得到一个返回值。

 

例:

int *pi;     // 指向整型数据的指针pi

int * api[3];  // 由指向整型数据的指针构成的数组,长度为 3

char ** argv;  // 指向一个字符指针的指针

struct { int member; } stinst,

  * pst = & stinst;  // pst是一个指向一个匿名结构体的指针

储存在指针中的地址所指向的数值在程序中可以由 * 读取。例如,在第一个例子中, *pi 是一个整型数据。这叫做引用一个指针。

 

另一个运算符 &,叫做取地址运算符,它将返回一个变量、数组或函数的存储地址。因此,下面的例子:

 

int i, *pi; /* int and pointer to int */

pi = &i;

i 和 *pi 在程序中可以相互替换使用,直到 pi 被改变成指向另一个变量的地址。

 

当指针指向结构体时,可以使用运算符 -> 代替 *和. 的作用,如 (*p).m 与 p->m 等效。

 

指针的使用一定要特别小心,千万不能越界,否则会出现意想不到的结果。而且一定不要使用未初始化过的指针(野指针)。

 

要想深入理解指针,应从回顾变量的定义开始入手,变量的定义,是向系统申请一块适当大小的内存,来存放对应的数据,比如

int    a = 100;

char   c = 'x'; 

定义变量时,系统为变量分配相应的存储单元,通过变量名可以直接使用该存储单元。

对编程开发初学者而言,充分理解以上变量a、b的内存地址,可以有助于理解指针。

先简要介绍如何查看变量在内存中的地址和内容。

 

先看C语言查看变量在内存中的地址和内容

#include<stdio.h>

 

int main()

{

   int i = 0;

   int *p=&i;

 

    /* %p 十六进制,大写,高位零显示

    %x 十六进制,小写,高位0不显示  */

   printf("变量的地址: %p\n", &i);

   printf("变量的地址: %x\n", &i);

   printf("变量的值为:%d\n",i);

   printf("指针(地址)的值为:%p\n",p);

   printf("指针(地址)的值为:%x\n",p);

  

   return 0;

 }

 

运行之,参见下图:

C++指针(pointer)

 

再看C++语言查看变量在内存中的地址和内容

#include <iostream>

using namespace std;

int main ()

{

   int i = 0;

   int *p=&i;

    

   /* 在c++里面怎么打印变量的地址

   普通变量  int i; cout<<&i;

   指针(地址)的值 int *p=&i;  cout<< p

   数组变量  int a[20]; cout<<(void *)a; */

 

   cout<<"变量的地址:" << &i <<endl;

   cout<<"指针的地址:" << p <<endl;

   cout<<"变量的值为:" << i <<endl;

   int b[20];

   cout<<"数组变量的地址:" << (void *)b<<endl;

  

   return 0;

}

 

运行之,参见下图:

C++指针(pointer)

 

指针变量本身所占据的内存区的大小,可用函数sizeof(指针的类型)测得。操作系统的位数决定了指针变量所占的字节数。一个指针变量不管它是指向任何类型(如整型、还是字符型、双精度型)变量,对于32位系统,指针变量本身只占4个字节,对于64位系统,指针变量本身只占8个字节。

测试指针变量占有内存空间大小的例子:

#include <iostream>

using namespace std;

int main ()

{

    char s = 'a', *p1 =&s;

       cout << "指针的大小" << sizeof(p1) << endl;

       int a = 10, *p2 = &a;

       cout << "指针的大小" << sizeof(p2) << endl;

 

       return 0;

}

运行之,参见下图:

C++指针(pointer)

 

我们已经知道,存储单元的使用可以通过变量名,定义变量时,系统为变量分配相应的存储单元,通过变量名可以直接使用该存储单元。存储单元的使用还可以地址来使用。通过存储单元的地址来使用该存储单元,这就需要用到指针变量。

存贮变量的内存空间的首地址称为该变量的地址。由于指针变量中的值是另一个变量的地址,我们习惯上形象地称为指针变量指向该变量。

 

 

指针变量定义的一般形式为:

类型说明符 *变量名;

其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。例

int *p = &i;

指针变量p的前面有一个星号,这个星号被称为指针变量定义标记,指针变量让我们有另一种渠道来操作内存块:

i = 100;

*p = 100;

以上两行代码,效果是完全一致的。也就是说,*p就是i,此处的星号被称为间接寻址运算符,旨在令p指向的目标i。

 

指针变量的赋值

指针变量同普通变量一样,使用之前不仅要定义说明, 而且必须赋予具体的值。未经赋值的指针变量不能使用, 否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址,决不能赋予任何其它数据,否则将引起错误。在C++语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。C++语言中提供了地址运算符&来表示变量的地址。其一般形式为:

&变量名;如:&i变示变量i的地址,&b表示变量b的地址。 变量本身必须预先说明。

假设有指向整型变量的指针变量p,如要把整型变量i 的地址赋予p可以有以下两种方式:

(1)指针变量初始化的方法

int i;

int *p = &i;

(2)赋值语句的方法

int i;

int *p;

p = &i;

 

再次提醒注意:

1)不允许把一个数赋予指针变量,故下面的赋值是错误的:

int *p;

p = 100;

因为指针变量的赋值只能赋予地址。

2)赋值时指针变量前不能再加“*”说明符,如:

*p = &i; //是错误的

int int I = 10, *p = &i; //指针变量初始化时可以,是正确的

 

指针赋值有三种情况 :

1)取变量地址:使指针指向该变量。

int y=15;

int *ip;

ip=&y

参见下图:

C++指针(pointer)

2)指针相互赋值:使两指针指向同一变量。

(续上)

int *ip1;

ip1=ip;

参见下图:

C++指针(pointer)

3)指针赋NULL:空指针,指针悬空。不同于指针未赋值。

int *ip2 = NULL; // ip2的值是 0

 

下面给出一个使用取地址运算符&和取内容运算符(间接寻址运算符)*的简单例子

#include <iostream>

using namespace std;

int main ()

{

  int i=10,*p=&i;

  cout<<"i= " << i <<endl;

  cout<<"*p= " << *p <<endl;

 

  int a=5,*q;

  q=&a;

  cout<<"a= " << a <<endl;

  cout<<"*q= " << *q <<endl;

   

  return 0;

}

 

运行之,参见下图:

C++指针(pointer)

 

 

取内容运算符(间接寻址运算符)的说明

使用指针变量时,*号表示 操作 指针所指向的内存空间中的值。

假设有:

int i = 10;

*p相当于通过地址(p变量的值)找到一块内存;然后操作内存。

*p放在等号的左边赋值(给内存赋值),如:

int *p = &i;

*p放在等号的右边取值(从内存获取值),如:

int *q = *P;

 

取内容运算符(间接寻址运算符)的使用例子:

#include <iostream>

using namespace std;

int main ()

{

  int i = 10, *p;

  p = &i;  //p指向i的内存地址

  cout<<"*p= " << *p <<endl;

  cout<<"p= " << p <<endl;

  int *q = &i;

  *q= *q+4; //等号的左边*q是赋值——给内存赋值;等号的右边*q是取值——从内存获取值。

  cout<<"*q= " << *q <<endl;

  int j;

  j = *p + 5;

  cout<<"*p= " << *p <<endl;

  cout<<"j= " << j <<endl;

 

  return 0;

}

 

运行之,参见下图:

C++指针(pointer)

 

 

指针使用