水滴石穿C语言之指针步进辨析

2016-02-19 13:43 17 1 收藏

今天图老师小编要跟大家分享水滴石穿C语言之指针步进辨析,精心挑选的过程简单易学,喜欢的朋友一起来学习吧!

【 tulaoshi.com - 编程语言 】

基本解释
  
  通过上一篇的分析,我们已经很清楚地知道:指针不是一个简单的类型,它是一个本身和所指向物相复合的类型。指针的算术运算(如步进)与指针所指向物的类型密切相关。
  
  问题:指针步进 & 步进单位
  
  下面的代码中打印出的结果是几?
  
  int arContext[5] ={0,1,2,3,4}, i, *pAr;
  pAr = arContext;
  printf ("%d", *(pAr + 3 * sizeof (int)));
  答案与分析:
  
  这段代码没有正确答案,因为这段代码是错的,printf将打出无法猜测的内存区的值,其中的原因如下:
  
  在C语言中,指针总是按照它所指向的对象的大小步进。在上面的例子中,pAr是指向整数类型变量的指针,一个整数是4个字节(默认CPU字长是32位),pAr + 1就指向下一个整数,也就是指针后移4个字节,而不是说将地址只移动一个字节。
  
  因为C语言编译器知道每个指针的类型,因此对指针的运算是会自动把所指类型的Size考虑进去的。
  
  pAr + 3 * sizeof (int) = pAr + 3 * 4 = pAr + 12 ,因此pAr指向了数组的第13个整数元素。而数组本身才5个元素,pAr早已经超出了界限,所指向的地方当然就是无人可知道的东西了,具体指向什么东西,各种不同的编译器互不相同。总之,肯定不能打印出我们想要的值就是了。
  
  指针不是一个简单的类型,它是一个和指针所指物的类型相复合的类型。因此,它的算术运算与指针所指物的类型密切相关,在C++语言中也是同样。
  
  再比如下面的例子:
  
  int a[8];
  int* p = a;
  int* q = p + 3;
  p++;
  指针的加减并不是指针本身的二进制表示加减,要记住,指针是一个元素的地址,它每加一次,就指向下一个元素。所以:
  
  int* q = p + 3;
  q指向从p开始的第三个整数。
  
  p++;
  
  p指向下一个整数。 问题:指针步进 & 步进单位转换
  
  我有一个char *类型的指针,恰好指向了一个int类型的值,我想让这个指针跳过int指向下一个char,下面的代码可以达到这个目的吗?
  
  ((int *)p)++;
  答案与分析:
  
  可以。
  
  首先我们要清楚C语言中左值和右值的概念,C语言中左值是指可以放在“=”左侧,即可以被赋值,右值是可以放在“=”的右边,即可以赋给其它变量的值。++是单目操作符,它将一个变量的值加1然后再赋给这个变量,因此它需要的操作数应该既可以放在“=”号的左边,也可以放在“=”的右边。原则上讲,类型强制转换的结果是右值而不是左值。所以,(int *)p的结果在这个表达式中是++的右值,而++的左值依旧是p,而不是(int *)p。
  
  这个问题的核心正是告诉我们类型强制转换的结果是右值而不是左值。
  
  另外,我们可以使用一个简单的办法达到相同的目的:
  
  p += sizeof(int);
  p是char *类型的指针,它的步进长度是1,加上一个整数所占的长度,就是跳过了一个整数所占的空间。
  
  所以,有时候,ULONG *p; 想要增加8个字节,可以作如下强制转换:
  
  (ULONG *)((UCHAR *)p+8
  问题:指针步进 & void 指针
  
  为什么我对void *类型的指针进行运算,编译器会报告如下错误?
  
  error C2036: 'void *' : unknown size
  答案与分析:
  
  在C语言中,所有的指针远算,例如+、—、*、/,都是将它所指向的对象的尺寸考虑进取的。例如‘char*’ 类型的指针加1,就是地址向后移动一个字节;而‘int*’类型指针加1,就是移动4个字节。但是,对于‘void*’型的指针呢?‘void *’指针在C标准中被规定可以强制转换成任何类型的指针而不会丢失数据,它的大小具体的编译器各不相同,也就是说,编译器也不知道void到底有多大,因此,无法对‘void*’类型的指针进行算术运算。

来源:http://www.tulaoshi.com/n/20160219/1605069.html

延伸阅读
什么是空指针常量(null pointer constant)? [6.3.2.3-3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 这里告诉我们:0、0L、'\0'、3 - 3、0 * 17 (它们都是“integer constant expression”)以及 (void*)0 (tyc: 我觉得(void*)0应该算是一个空...
就指向指针的指针,很早以前在说指针的时候说过,但后来发现很多人还是比较难以理解,这一次我们再次仔细说一说指向指针的指针! 先看下面的代码,注意看代码中的注解! //程序作者:管宁 //站点:www.cndev-lab.com //所有稿件均有版权,如要转载,请务必著名出处和作者 #include iostream #include string usingnamespacestd; voidprint_char(...
第一个: ------------------------------------------------------ 代码如下: #include stdio.h #include string.h void tell_me(int f(const char *, const char *)); int main(void) {    tell_me(strcmp);    tell_me(main);    return 0; } void tell_me(int f(const char *, const char *)) {  &n...
  就指向指针的指针,很早以前在说指针的时候说过,但后来发现很多人还是比较难以理解,这一次我们再次仔细说一说指向指针的指针。 先看下面的代码,注重看代码中的注解: !-- frame contents -- !-- /frame contents -- #include iostream  #include string  using ...
在学习c/c+过程中,指针是一个比较让人头痛的问题,稍微不注重将会是程序编译无法通过,甚至造成死机。在程序设计过程中,指针也往往是产生隐含bug的原因。下面就来谈谈指针的应用以及需要注重的一些问题,里面也许就有你平时没有注重到的问题,希望能帮助各位读者理解好指针。 !-- frame contents -- !-- /frame contents -- ...

经验教程

457

收藏

45
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部