指针可以进行加/减去一个整数。指针这种运行的意义和通常的数值加减意义不一样,它是指加/减去一个单元的长度。
1、指针算术运算终极案之指针变量自加的实质、
- char a[30];
- int *p = (int *)a; // 强制类型转换并不会改变a的类型
- printf("&p = %p , *p = %p, &a = %pn",&p,p,a);
- p++;
- printf("&p = %p , (p++) = %p , &a = %pn",&p,p,a);
- p++;
- printf("&p = %p , (p++) = %p , &a=%pn",&p,p,a);
- // 错误的写法 printf("&p = %p , (p++) = %d , &a=%pn",&p,*p,a);
图1的内存操作结果,可以通过图2的图示解释:
图2、指针相加操作详细图
图2中,p是int*型指针,被赋char a的地址。然后分别执行了两个p++,注意到p所占据的内存空间始终没有变;唯一变的是p所占据的内存空间里面的值,也就是p++是从数组a起始地址往后增加了4个字节的地址长度。
2、指针算术运算终极案例之字符指针与整型指针自加的区别
- char a[20] ="I'm a super man!";
- char *ptr1 = a;
- printf("%sn",a);
- ++ptr1;
- printf("%16sn",ptr1);
- ++ptr1;
- printf("%16snn",ptr1);
-
- printf("%sn",a);
- int *ptr2 = (int *)a;
- ++ptr2;
- printf("%16sn",ptr2);
- ++ptr2;
- printf("%16sn",ptr2);
图3
图4
由上面程序可以看出,对于char *ptr1,int *ptr2,进行p++,都是以字符单元和整型单元为单位进行增加。
3、指针运算之越界问题
- char a[20] ="I'm a super man!";
- printf("%sn",a);
- int *ptr2 = (int *)a;
- ++ptr2;
- printf("%16sn",ptr2);
- ptr2 = ptr2+4;
- printf("%16sn",ptr2);
图5的运行结果,证明了一个整型指针的加减是以sizeof(int)个字节为单元进行的。ptr2+4明显超出了数据a[20]的边界,所以读出的是一堆乱码。注意,这里程序并没有报错,也就证明语法上是允许这样写的。
4、指针运算的典型陷阱
- char a[20] ="I'm a super man!";
- char *p = a;
- char **ptr = &p;
- printf("**ptr = %cn",**ptr);
- ptr++;
- printf("**ptr = %cn",**ptr);
上面这段代码,或许有些人会认为第二个printf输出的是[’],果真是吗?
由图6可知,ptr是一个指向指针的指针变量。它的值是一个32位的地址,ptr++,即就是进行ptr+sizeof(char*)=ptr+4,得到的是一个0x0012ff44的地址。这是一个什么地址?一个非法的地址!这时候执行printf("**ptr = %c\n",**ptr);,肯定会报错,如图7.
图7
所以,一个指针变量加上或减去一个整数n,实质是等于指针变量的值+/- sizeof(type *)*n,即移动sizeof(type *)*n个单元。
另外,两个指针不能进行加法运算,进行加法后,得到的结果指针一个不知所向的地方,没有意义。两个指针可以进行减法操作,但必须类型相同,一般用在数组方面。
参考文献
《让你不再害怕指针》,作者 佚名,向原作者致敬!