刘宇,对指针的看法理解(有借鉴)

地址指针的基本概念
(理解)
在计算机中,所有的数据都是存放在
存储器中的。一般把存储器中的一个
字节称为一个内存单元,不同的数据
类型所占用的内存单元数不等,如整
型量占2个单元,字符量占1个单元等,
在前面已有详细的介绍。为了正确地
访问这些内存单元,必须为每个内存
单元编上号。根据一个内存单元的编
号即可准确地找到该内存单元。内存
单元的编号也叫做地址。既然根据内
存单元的编号或地址就可以找到所频
的内存单元,所以通常也把这个地址75
称为指针。
内存单元的指针和内存单元的内容记
两个不同的概念。可以用一个通俗的
例子来说明它们之间的关系。我们
银行去存取款时,银行工作人员将根
据我们的帐号去找我们的存款单,找
针,这种变量称为指针变量。因此,
一个指针变量的值就是某个内存单元
的地址或称为某内存单元的指针。
在这里插入图片描述

图中,设有字符变量C,其内容
为“K”(ASC码为十进制数75),C占用
了011A号单元(地址用十六进数表示)
设有指针变量P,内容为011A,这种情
况我们称为P指向变量C,或说P是指向
变量C的指针。
严格地说,一个指针是一个地址,评论
一个常量。而一个指针变量却可以被
赋予不同的指针值,是变量。但常毮记
指针变量简称为指针。为了避免混
淆,我们中约定:“指针”是指地例题
址,是常量,“指针变量”是指取值
为地址的变量。定义指针的目的是录
了通过指针去访问内存单元。
既然指针变量的值是一个地址,那么
这个地址不仅可以是变量的地址,也
可以是其它数据结构的地址。在一个
指针变量中存放一个数组或一个函数
的首地址有何意义呢?因为数组或函
数都是连续存放的。通过访问指针变
量取得了数组或函数的首地址,也就
找到了该数组或函数。这样一来,凡
是出现数组,函数的地方都可以用一
个指针变量来表示,只要该指针变量
中赋予数组或函数的首地址即可。这
样做,将会使程序的概念十分清楚,
程序本身也精练,高效。
因为在C语言中,一种数据类型或数据结
构往往都占有一组连续的内存单元。
用“地址”这个概念并不能很好地描
述一种数据类型或数据结构,而“指
针”虽然实际上也是一个地址,但
它却是一个数据结构的首地址,它
是“指向”一个数据结构的,因而概
念更为清楚,表示更为明确。这也是
引入“指针”概念的一个重要原因。

指针的算术运算
运算符&和*
这里&是取地址运算符,是间接运算符。&a 的运算结果是一个指针,指针的类型是a 的类型加个,指针所指向的类型是a 的类型,指针所指向的地址嘛,那就是a 的地址。p 的运算结果就五花八门了。总之p 的结果是p 所指向的东西,这个东西有这些特点:它的类型是p 指向的类型,它所占用的地址是p所指向的地址。例六:int a=12; int b; int *p; int *ptr;p=&a; //&a 的结果是一个指针,类型是int,指向的类型是//int,指向的地址是a 的地址。*p=24; //*p 的结果,在这里它的类型是int,它所占用的地址是//p 所指向的地址,显然,p 就是变量a。ptr=&p; //&p 的结果是个指针,该指针的类型是p 的类型加个,//在这里是int *。该指针所指向的类型是p 的类型,这//里是int。该指针所指向的地址就是指针p 自己的地址。*ptr=&b; //ptr 是个指针,&b 的结果也是个指针,且这两个指针//的类型和所指向的类型是一样的,所以用&b 来给ptr 赋//值就是毫无问题的了。**ptr=34; //ptr 的结果是ptr 所指向的东西,在这里是一个指针,//对这个指针再做一次运算,结果是一个int 类型的变量指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的,以单元为单位。例如:
例:
char a[20];
int *ptr=(int )a; //强制类型转换并不会改变a 的类型
ptr++;
在上例中,指针ptr 的类型是int
,它指向的类型是int,它被初始化为指向整型变量a。接下来的第3句中,指针ptr被加了1,编译器是这样处理的:它把指针ptr 的值加上了sizeof(int),在32 位程序中,是被加上了4,因为在32 位程序中,int 占4 个字节。由于地址是用字节做单位的,故ptr 所指向的地址由原来的变量a 的地址向高地址方向增加了4 个字节。由于char 类型的长度是一个字节,所以,原来ptr 是指向数组a 的第0 号单元开始的四个字节,此时指向了数组a 中从第4 号单元开始的四个字节。我们可以用一个指针和一个循环来遍历一个数组,看例子:
例:
int array[20]={0};
int *ptr=array;
for(i=0;i<20;i++)
{
(*ptr)++;
ptr++;
}
这个例子将整型数组中各个单元的值加1。由于每次循环都将指针ptr加1 个单元,所以每次循环都能访问数组的下一个单元。

再看例子:
例:
char a[20]=“You_are_a_girl”;
int *ptr=(int *)a;
ptr+=5;
在这个例子中,ptr 被加上了5,编译器是这样处理的:将指针ptr 的值加上5 乘sizeof(int),在32 位程序中就是加上了5 乘4=20。由于地址的单位是字节,故现在的ptr 所指向的地址比起加5 后的ptr 所指向的地址来说,向高地址方向移动了20 个字节。
在这个例子中,没加5 前的ptr 指向数组a 的第0 号单元开始的四个字节,加5 后,ptr 已经指向了数组a 的合法范围之外了。虽然这种情况在应用上会出问题,但在语法上却是可以的。这也体现出了指针的灵活性。如果上例中,ptr 是被减去5,那么处理过程大同小异,只不过ptr 的值是被减去5 乘sizeof(int),新的ptr 指向的地址将比原来的ptr 所指向的地址向低地址方向移动了20 个字节。
下面请允许我再举一个例子:(一个误区)

例:
#include<stdio.h>
int main()
{
char a[20]=" You_are_a_girl";
char *p=a;
char **ptr=&p;
//printf(“p=%d\n”,p);
//printf(“ptr=%d\n”,ptr);
//printf("*ptr=%d\n",*ptr);
printf("**ptr=%c\n",**ptr);
ptr++;
//printf(“ptr=%d\n”,ptr);
//printf("*ptr=%d\n",*ptr);
printf("**ptr=%c\n",**ptr);
}
误区一、输出答案为Y 和o
误解:ptr 是一个char 的二级指针,当执行ptr++;时,会使指针加一个sizeof(char),所以输出如上结果,这个可能只是少部分人的结果.
误区二、输出答案为Y 和a误解:ptr 指向的是一个char *类型,当执行ptr++;时,会使指针加一个sizeof(char *)(有可能会有人认为这个值为1,那就会得到误区一的答案,这个值应该是4,参考前面内容), 即&p+4; 那进行一次取值运算不就指向数组中的第五个元素了吗?那输出的结果不就是数组中第五个元素了吗?答案是否定的.
正解: ptr 的类型是char *,指向的类型是一个char 类型,该指向的地址就是p的地址(&p),当执行ptr++;时,会使指针加一个sizeof(char),即&p+4;那(&p+4)指向哪呢,这个你去问上帝吧,或者他会告诉你在哪?所以最后的输出会是一个随机的值,或许是一个非法操作.
总结一下:
一个指针ptrold 加(减)一个整数n 后,结果是一个新的指针ptrnew,ptrnew 的类型和ptrold 的类型相同,ptrnew 所指向的类型和ptrold所指向的类型也相同。ptrnew 的值将比ptrold 的值增加(减少)了n 乘sizeof(ptrold 所指向的类型)个字节。就是说,ptrnew 所指向的内存区将比ptrold 所指向的内存区向高(低)地址方向移动了n 乘sizeof(ptrold 所指向的类型)个字节。指针和指针进行加减:两个指针不能进行加法运算,这是非法操作,因为进行加法后,得到的结果指向一个不知所向的地方,而且毫无意义。两个指针可以进行减法操作,但必须类型相同,一般用在数组方面,不多说了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值