谈C/C++指针精髓(3)[转帖]

1.4指针的运算

 

1.4.1赋值运算

指针变量的赋值运算有以下几种形式:

1.4.1.1指针变量初始化赋值如下:

int a;

int *ip=&a;

1.4.1.2把一个变量的地址赋予指向相同数据类型的指针变量。例如:

int a;

int *ip;

ip=&a;             //把整型变量a的地址赋予整型指针变量ip

1.4.1.3把一个指针变量的值赋予指向相同类型变量的另一个指针变量。例如:

int a;

int *pa=&a;

int *pb;

pb=pa;              //a的地址赋予指针变量pb

由于pa,pb均为指向整型变量的指针变量,因此可以相互赋值。

1.4.1.4把数组的首地址赋予指向数组的指针变量。例如:

int a[5],*pa;

pa=a;               //数组名表示数组的首地址,故可赋予指向数组的指针变量pa

也可写为:

pa=&a[0];           //数组第一个元素的地址也是整个数组的首地址也可赋予pa

当然也可采取初始化赋值的方法:

int a[5],*pa=a;

以上是一些基本的数组赋值方法,后面我们会详细讨论指针在数组中的使用。

1.4.1.5把字符串的首地址赋予指向字符类型的指针变量。例如:

char *pc;

pc="c language";

或用初始化赋值的方法写为:

char *pc=" c language ";

这里应说明的是并不是把整个字符串装入指针变量, 而是把存放该字符串的字符数组的首地址装入指针变量。

1.4.1.6把函数的入口地址赋予指向函数的指针变量。例如:

int (*pf)();

pf=f;                //f为函数名

1.4.2加减运算

对于指向数组的指针变量,可以加上或减去一个整数n。设ip是指向数组a的指针变量,则ip+n,ip-n,ip++,++ip,ip--,--ip 运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应该注意,数组指针变量向前或向后移动一个位置和地址加1或减1 在概念上是不同的。因为数组可以有不同的类型, 各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。看如下例子:

char a[20];

int*ip=a;

...

ip++;

在上例中,指针ip的类型是int*,它指向的类型是int,它被初始化为指向整形变量a。接下来的第3句中,指针ip被加了1,编译器是这样处理的:它把指针ip的值加上了sizeof(int),在32位程序中,是被加上了4。由于地址是用字节做单位的,故ip所指向的地址由原来的变量a的地址向高地址方向增加了4个字节。

由于char类型的长度是一个字节,所以,原来ptr是指向数组a的第0号单元开始的四个字节,此时指向了数组a中从第4号单元开始的四个字节。再看如下例子:

char a[20];

int*ip=a;

  ...

ip+=5;

在这个例子中,ip被加上了5,编译器是这样处理的:将指针ip的值加上5sizeof(int),在32位程序中就是加上了54=20。由于地址的单位是字节,故现在的ip所指向的地址比起加5后的ip所指向的地址来说,向高地址方向移动了20个字节。在这个例子中,没加5前的ip指向数组a的第0号单元开始的四个字节,加5后,ptr已经指向了数组a的合法范围之外了。虽然这种情况在应用上会出问题,但在语法上却是可以的。这也体现出了指针的灵活性。

如果上例中,ip是被减去5,那么处理过程大同小异,只不过ip的值是被减去5sizeof(int),新的ip指向的地址将比原来的ip所指向的地址向低地址方向移动了20个字节。

总结一下,一个指针ipold加上一个整数n后,结果是一个新的指针ipnewipnew的类型和ipold的类型相同,ipnew所指向的类型和ipold所指向的类型也相同。ipnew的值将比ipold的值增加了nsizeof(ipold所指向的类型)个字节。就是说,ipnew所指向的内存区将比ipold所指向的内存区向高地址方向移动了nsizeof(ipold所指向的类型)个字节。

一个指针ipold减去一个整数n后,结果是一个新的指针ipnewipnew的类型和ipold的类型相同,ipnew所指向的类型和ipold所指向的类型也相同。ipnew的值将比ipold的值减少了nsizeof(ipold所指向的类型)个字节,就是说,ipnew所指向的内存区将比ipold所指向的内存区向低地址方向移动了nsizeof(ipold所指向的类型)个字节。

1.4.3关系运算

指向同一个数组中的不同元素的两个指针可以进行各种关系运算。例如:

ip1==ip2表示ip1ip2指向同一数组元素

ip1>ip2表示ip1处于高地址位置

ip1<ip2表示ip2处于低地址位置

指针变量还可以与0比较。设ip为指针变量,则ip==0表明ip是空指针,它不指向任何变量;ip!=0表示ip不是空指针。空指针是由对指针变量赋予0值而得到的。例如:

#define NULL 0 

int *ip=NULL;

 对指针变量赋0值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的。否则将造成意外错误。而指针变量赋0值后,则可以使用,只是它不指向具体的变量而已。

1.4.4取地址运算符‘&’和取内容运算符‘*

取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量的地址。

取内容运算符*是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。需要注意的是指针运算符*和指针变量说明中的指针说明符* 不是一回事。在指针变量说明中,‘*’是类型说明符,表示其后的变量是指针类型。而表达式中出现的‘*’则是一个运算符用以表示指针变量所指的变量。如下例子:

int a=12;

int b;

int *p;

int **ptr;

p=&a;   //&a的结果是一个指针,类型是int*,指向的类型是int,指向的地址是a

//地址。

*p=24;   //*p的结果,在这里它的类型是int,它所占用的地址是p所指向的地址。

ptr=&p; //&p的结果是个指针,该指针的类型是p的类型加个*,在这里是int **。该

//指针所指向的类型是p的类型,这里是int*。该指针所指向的地址就是指针

//p自己的地址。

*ptr=&b;//*ptr是个指针,&b的结果也是个指针,且这两个指针的类型和所指向的类型//是一样的,所以用&b来给*ptr赋值就是毫无问题的了。

**ptr=34;//*ptr的结果是ptr所指向的东西,在这里是一个指针,对这个指针再做一次*

//运算,结果就是一个int类型的变量。

1.4.5关于括号组合

在解释组合说明符时, 标识符右边的方括号和圆括号优先于标识符左边的“*”号,而方括号和圆括号以相同的优先级从左到右结合。但可以用圆括号改变约定的结合顺序。

阅读组合说明符的规则是“从里向外”。从标识符开始,先看它右边有无方括号或园括号,如有则先作出解释,再看左边有无*号。 如果在任何时候遇到了闭括号,则在继续之前必须用相同的规则处理括号内的内容。

1.5指针表达式

    一个表达式的最后结果如果是一个指针,那么这个表达式就叫指针表式。所以指针表达式也具有指针所具有的四个要素:指针的类型,指针所指向的类型,指针指向的内存区,指针自身占据的内存。(预知后事如何,且听下回分解!!!)

 
 

作者简介:

马伟,现任大方软件开发工程师,在C家族(CC++C# 呵呵,因为都有个C,所以我习惯称为C家族)方面有一定的见解,希望和广大技术朋友共同交流。

E-MAILmadengwei-88163@163.com QQ:328941810 MSN:madengwei@hotmail.com

网站和个人主页:www.itspzo.com|

最后版权声明一下:本文章归本作者所有,任何个人和公司不得随意把本文章的部分或者全部用于商业目的,如有转载或者其他目的请联系作者。呵呵!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值