&&&&&&&上一讲鸡啄米介绍了指针的基本概念和地址运算,今天为大家带来指针赋值和指针运算的内容。
&&&&&&&一.指针的赋值
&&&&&& 当我们声明了一个指针之后,这个指针变量中没有存储任何确定的地址值,而是一个随机整数。也就是它指向的地址是不确定的,有可能它指向了系统的重要数据,这时候我们如果修改了它指向地址的值可能会引起想象不到的系统问题。所以指针声明以后要先赋值才可以引用。
&&&&& &跟鸡啄米前面讲的其他类型的变量一样,给指针变量赋值也有两种方式:
&&&&&& 1.在声明指针时对其进行初始化,也就是赋一个初值,初始化形式为:数据类型 *指针名=初始地址值;。
&&&& & 2.在声明指针后,单独给它赋值,赋值的语法形式为:指针名=地址;。
&&&&&& 如果我们像方式1中使用变量地址为指针初始化,或者像方式2中将变量地址赋给指针,此变量必须在此之前声明过,并且这个变量的类型要和指针类型一样。可以将一个已经赋值的指针赋值给另一个指针,让多个指针指向相同的变量。
&&&&&& 鸡啄米给大家一个用两种方式为指针赋值的例子:
&&&& & int a[5];&&&&&&& &// 声明一个整型数组
&&&& & int *p1=a;&&&& // 声明指针p1,并用数组首地址a来初始化p1
&&& && int *p2;&&&&&&& &// 声明指针p2
&&&& & p2=a;&&&&&&&&&& // 将数组首地址a赋值给指针p2
&&&&& &鸡啄米说过,数组名就是数组的首地址,所以它可以用来给指针赋值。
&&&&&&&另外,鸡啄米要强调的是,赋给指针变量的值必须是地址常量(比如数组名)或地址变量,但一定不能是非0整数。给指针赋值为0时表示该指针是一个空指针,它不指向任何地址,比如,int *p=0;。为什么会把指针声明为空指针呢?大家想想,我们在声明一个指针时没有给它赋值,这时它是一个随机的值,在给它赋确定的地址值之前如果我们使用了它,就可能会访问到重要的内存地址并破坏此地址的数据,造成严重后果,所以我们在软件开发中一般先将指针设为空指针。
&&&&&&&给大家一个指针的声明、赋值和使用的例子:
&&&&&& #include<iostream>
&&&&&& using namespace std;
&&&&&& int main()
&&&&&& {
&&&&&&&&&&&&&&& int *p; //声明int型指针p
&&&&&&&&&&&&&&& int i; //声明int型数i
&&&&&&&&&&&&&&& p=&i; //取i的地址赋给p
&&&&&&&&&&&&&&& i=6; //int型数赋初值
&&&&&&&&&&&&&&& cout<<"output int i="<<i<<endl;//输出int型数的值
&&&&&&&&&&&&&&& cout<<"output int pointer i="<<*p<<endl;//输出int型指针所指地址的内容
&&&&&&&&&&&&&&& return 0;
&&&&&& }
&&&&& 程序运行结果是:
&&&&& output int i=6
&&&&& output int pointer i=6
&&&&&&上面的程序首先声明了int型指针p,又声明了int型变量i,然后取i的地址赋给指针p,再给i赋值6,因为i等于6,所以第一个cout语句输出output int i=6。*p表示p指向的变量的值,因为p存储的是i的地址,所以p指向i,*p的值也是6,第二个cout语句输出output int pointer i=6。
&&&&&& 鸡啄米再给大家强调几点:
&&&&&&&1.我们可以声明指向常量的指针,这时候指针本身的值可以改变,也就是指针可以指向其他对象,但是我们不能通过指针改变它指向的值。例如:
&&&&& &const char *name="tom"; //指向常量的指针
&&&&&& char s[]="lili";
&&&&& &name=s;&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&//正确,name本身的值可以改变
&&&&& &*name=’a’;&&&&&&&&&&&&&&&&&&&&&&&&&& //编译时指出错误,不能通过name修改指向的对象
&&&&& &2.我们还可以声明指针常量,这时候指针本身的值不能改变,例如:
&&&&& &int a=1;
&&&&&&&int b=2;
&&&& & int *const p=&a;&&& // 声明指针常量p
&&&&& &p=&b;&&&&&&&&&&&&&& // 错误,不能改变指针常量p的值
&&&&&&&3.我们进行指针赋值时可以将某个指针的值赋给相同类型的另一个指针。但是有一种特殊类型的指针,可以用任意类型对象的地址为之赋值,这就是void类型指针。我们在使用void类型的指针访问数据时需要进行强制类型转换。鸡啄米给大家一个void指针的例子:
&&&&&& &void *p;
&&&&&& &int *p1;
&&&&&& &int a;
&&&&&& &void main()
&&&&&& &{
&&&&&&&&&&&&&&&& &p=&a;&&&&&&&& // void类型的指针p指向整型变量a
&&&&&&&&&&&&&&&&& p1=(int*)p;&& // 用强制类型转换的方式将void指针p的指针赋给int型指针p1
&&&&& & }
&&&&&&&二.指针运算
&&&&&& 鸡啄米前面说过,指针也是一种数据类型,也可以参与一些运算。指针能够进行的运算有赋值运算、算术运算和关系运算。赋值运算鸡啄米上面刚讲过了。下面介绍算术运算和关系运算。
&&&&&&&指针可以和整数进行加减运算,但是跟一般的加减运算不同,指针的加减运算跟指针的类型密切相关,例如,char型指针p和整数3,p+3表示p所指地址后面第3个字符的地址,p-3就表示p所指地址前面第3个字符的地址。给大家一个更直接的例子,有整型数组int a[5],p指向数组首地址a,则a+3表示首地址后第3个整数的地址,即a[3]。
&&&&& &“指针++”和“指针--”表示指针所指地址的下一个或前一个数据的地址。
&&&&&&&指针的算术运算一般都是在操作数组的时候进行,因为只有声明数组才可以得到连续的内存空间。如果我们对一个单独的变量地址进行加或减的算术运算,然后改变新地址的值,则可能会破坏该地址的数据,所以在对指针进行算术运算时要明确运算的结果是程序中分配可用的地址。
&&&&&& 指针的关系运算说的是相同类型的指针之间的关系运算。不同类型的指针之间的关系运算没有任何意义,指针和非0整数的关系运算也没有任何意义,但是指针可以和0进行关系运算,后面鸡啄米会讲。两个相同类型的指针相等,表示这两个指针指向同一个地址。
&&&&&& 今天讲的仍然是很重要的内容,鸡啄米希望大家掌握好,关键是理解,这些以后在软件开发中会经常用到。有什么问题可以在鸡啄米博客留言讨论。
&