前言
今天发现自己对C++了解得还不够深刻,毅然决定重新补充C++指针的知识。一直在论坛里听别人说没有几个人真正的会用指针,我居然怀疑了一下自己,好吧。恶补呗,顺便写篇博客祭奠一下,这篇文章适合非小白看,我只是把容易错的点补充了。
1.数据在内存中是如何存储的
在编译时就会系统就会给变量分配内存空间,这里有个概念必须理清,就是内存单元地址跟内存单元内容,在编译期间,变量实际上已变成内存单元地址(就0xYYYYY)之类的,然后系统根据地址找到内存单元内容,如定义了变量INT I=100;i的内存单元内容就是100。
2.指针和指针变量的概念
上述查找I的内容是直接寻值,还有一种是间接寻值,即有一种特殊变量是用来存放某个变量的内存单元地址。该特殊变量的值称之为指针(其实某个变量的地址就是指针)。
3.定义指针变量及其概念
int *pointer_01;
上述所定义的指针变量是指向整型数据的指针变量。也就是说,指针变量pointer_1只能指向整型的变量,一般定义指针的形式:基类型 *指针变量名。
请各位注意,*并不是该指针变量的变量名,在变量名前加*只是为了说明该变量是指针变量。
我的电脑输出结果为:007FF824---007FF824---100
int* pointer_01;
int a=100;
pointer_01=&a;
cout<<&a<<"---"<<*pointer_01<<"---"<<pointer_01<<"---"<<&pointer_01;
\\&是取地址的符号
\\我的电脑输出结果为:0097F874---100---0097F874---0097F880
每个人运行的结果前两个值都会相同,说明了pointer变量的内存单元内容是a的地址,pointer是变量,所以有自己的内存单元地址,用*引用pointer变量的内存单元内容即可找到真正的值。到这,我回想了一下,我之前确实误解了指针的真正含义,如果不经常用真的很容易把概念混淆。
4.指针作为函数参数
例如:函数Do(int *point_01),定义了变量:int *point_01,i我们调用是传得是地址即point_01,&a等,千万不用传*point_01,因为人家需要的是地址,加*号就指向了a的内容即100了。
5.指针与数组
指向一维数组的指针
数组因为内存中是顺序存放的,当指针指向数组某一个位置时,通过加减移动指 针就可以访问数组中的元素,数组名字默认是数组首位的地址。
例如: int a[5];int *point_01=a;point_01+1==a[1];指向二维数组的指针
用单个指针引用二维数组考虑数组在内存中的存放情况即可。
#include <iostream>
using namespace std;
int main( )
{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int *p; //p是基类型为整型的指针变量
for(p=a[0];p<a[0]+12;p++)
cout<<*p<<endl;
cout<<endl;
system("pause");
return 0;
}
当用指针数组引用二维数组要注意的是,指针数组的增值是以一维数组为单位,想要任意访问二维数组中任一元素,应该这么写:定义了point_01[n], 用*(*(point_01+i)+j)访问i行j列。
解析:*point_01+i指向了a[i],在二维数组中显示一维的就是该维的地址,然后用地址+1再用*引用得出值。
6.字符串与指针
字符指针不同与整形指针,字符指针可以初始化。输出也不一样,具有一定的特殊性,待我慢慢说道。我们先理清一下概念:
1. 输出指针的内容(即所指向空间的地址)cout<<p<<endl
2. 输出指针所指的内容(即指针内容所描述地址空间中的内容):cout<<*p<<endl
指针对于字符的处理却有些特殊,和前面的非字符的指针输出处理要分开理解。
首先举个例:
char a='T';
char *p=&a;
cout<<p<<endl;
cout<<*p<<endl;
第一行会输出T####, #代表乱码,并不是地址。
第二行会输出T。
当时我遇到这种情况和各位一样的懵,p不是存放着地址吗,为什么会T####?很明显已经指向内容了啊,原来是cout的原因,cout操作字符指针的话,它遇到字符地址,就会直接去寻找这个地址所指向的内容,并把它的空间里的机器数按照字符的规则转化成字符输出,直到遇到“\0”这个操作符才停止。所以我们直接输出p的时候,它先输出‘T’然后再继续读取后面的内存空间直到遇到“\0”,显示结果是“T+乱码”。在这里再强化一个概念,地址即指针,牢记。
7.指针数组和指向指针的指针
指针数组:一般的定义形式为类型名*数组名[数组长度];在这个数组里每位元素都是指针。
但是我们要区别清楚:
int *p[4]------这是指针数组。
int (*p)[4]---------这是数组指针。
这俩位仁兄长得实在太像,平时我特别容易混淆,但它俩却大不相同。果然,C++都是坑,慢慢填吧。
指针数组是一个只存放定义类型的指针的数组。
数组指针是一个指针,只能指向定义类型的数组。
8.指向指针的指针
我的天,看到这个标题我脑子飞速饶了几圈,妈呀,指针都够烦了,还要☞中☞,要是真想在项目中玩起来,估计得有些修行。
在理解前面指针数组的基础上,我们再来看指向指针的指针。不说废话,先上到菜。
#include <iostream>
using namespace std;
int main( )
{ char **p; //定义指向字符指针数据的指针变量p
char *name[]={″BASIC″,″FORTRAN″,″C++″,″Pascal″,″COBOL″};
p=name+2; //见图6.23中p的指向
cout<<*p<<endl; //输出name[2]指向的字符串
cout<<**p<<endl; //输出name[2]指向的字符串中的第一个字符
}
//输出结果为:
//C++
//C
解析:字符指针数组是一个指针数组,里面的元素name[i]都是指针==地址,数组名name代表该指针数组首元素的地址。name+i是name[i]的地址,所以p=name+2是合法的。指针-指针==地址-地址,这种方法就多级间接访问,下面配个图方便理解。
9.指针总结
希望大家认真复习指针,看见下图中的每一个定义要能迅速想起对应的概念
10.引用
顺便说说引用的意思跟引用和指针的区别。
引用的概念:
int a; //定义a是整型变量
int &b=a; //声明b是a的引用
引用只是一个变量的别名
引用和指针的相同点:
(1)都是指针的概念
只不过指针的内容是某块内存的地址,引用是某块内存的别名。
不同点:
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
引用“从一而终” ^_^
4. 引用没有 const,指针有 const,const 的指针不可变;
5. 引用不能为空,指针可以为空;
6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。
7. 指针和引用的自增(++)运算意义不一样;