• 指针闲谈


     

    曾经看过一篇文章,讲述的是基础的重要性,我摘录一段“什么是基础呢?就是要把我们大学所学的离散数学,算法与数据结构,操作系统,计算机体系结构,编译原理等课程学好,对计算机的体系,CPU本身,操作系统内核,系统平台,面向对象编程,程序的性能等要有深层次的掌握。初学者可能体会不到这些基础的重要性,学习jsp,donet,mfc,vb的朋友甚至会对这些嗤之以鼻,但是一开始没学好基础就去学jsp或donet会产生很坏的影响,而且陷入其中不能自拔”

     

    其实大学中学到的东西都可以认为是基础,实战的东西是很难学到,除非是天天泡在实验室,或者做些项目等,或者参与实习,去年写过一篇博文,里面就写到了实习是一个很重要的环节,实习能学的很多,做项目也能学到很多,但是我还是建议不要花费太多的时间在这个上面,毕竟那个时候还是学生,学生么,以学习为主,待往后毕业,步入社会,很难有那样的学习环境和学习气氛,就跟我现在的状态类似,很怀念以前读书的时候,还经常妄想能进入校园去读读书。

      我不是一个能写出掷地有声的博文,也不算一个高产的博文,但是今天也想在这里畅所欲言,一吐心中之快。师傅引进门,学艺在个人,上大学的人都不是笨人,都是天资极高的人,在饱读书籍是多年之后,大家都知道这个道理,也都明白很多,所谓的师傅除了我们的老师之外,还有那一道道的升学考试,是他们让我们一步步进入另外一个门,其实大学中没有真正的师傅,十多年的读死书生活已经让我们明白了很多,只要自己去下功夫,去努力,自己完全可以胜任自己的老师,但是也不能将老师说的一无是处,毕竟很多的时候需要老师的点拨,古人也说过,三人行,必有我师,在大学,任何人都可以成为老师,关键看自己能否去认识,其实道理都懂,关键缺少有心人,我就是一个没有心的人。

     

     今天又一次看到了指针和数组的关系的内容,说实话,以前上C语言课程的时候只是知道自己的老师是个女的,其余的就不知道了,因为C语言课我一般都是坐在最后,不做其他,就是为了睡觉,C语言的课程是上午的第一节,所以很难起来,又怕老师点名,所以就去抢最后一排睡觉,真是应了那句“大学过的像猪一样的生活”,惭愧呀,惭愧。

     今天看到指针和数组,只是知道数组的数组名表示的是一个地址,那么一维和二维的数组名到底有什么不同?然后就突发奇想,决定自己好好去探索下,做一回有心人,将结果记录下来,所谓纸上得来终觉浅,绝知此事要躬行,借助手中之便顺手写了两个数组,对于数组其实计算机在内存中开辟了一段连续的空间,并将这段地址空间的首地址作为数组名,那么整个数组所占的大小等于数组中每一个基本元素大小乘以数组的个数。

     

    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	printf("%s\n","打印一维数组指针");
    	int a[5]={1,2,3,4,5};
    
    	printf("%p\n",a);
    	printf("%p\n",&a[0]);
    	printf("%p\n",&a);
    	printf("%p\n",&a+1);
    	printf("%p\n",a+1);
    	printf("%p\n",a+2);
    
    	printf("%s\n","打印二维数组指针");
    
    
    	int b[2][3]={{1,2},{3,4}};
    
    
    	printf("%p\n",b);
    	printf("%p\n",b[0]);
    	printf("%p\n",&b[0]);
    	printf("%p\n",&b[0][0]);
    
    	printf("%p\n",*(b+1));
    	printf("%p\n",b[1]);
    
    	printf("%s\n","打印偏移");
    	printf("%p\n",b+1);
    	printf("%p\n",b+2);
    	printf("%p\n",b[1]+1);
    	printf("%p\n",b[2]);
    	
    
    	getchar();
    	return 0;
    }
    

                                                                                                                                             

    因为内容是自己一个个添加的,所以三附截图会有不同,但是结

    果已经很明显了,对于一维数数组,数组名的地址a和a[0]以及&a的地址是一样的,而且还可以看出对于数组可以通过加法运算,但是这个加表示的是地址的偏移量:

     

     

    但是这些意义不同&a表示的是一个指向含有5个int数据的一维数组的地址,因为一个int表示4个字节,所以可以看到&a与&a+1相差4*5=20个字节,但是对于a一个含有5个int 数据第一个元素的地址,也就是&a[0]相等,但是意义不同。在VS的即时窗口里面可以清楚的看到a+1,a,&a+1的不同: 

     对于二维数组有点复杂,但是可以将二维数组看成一维数组的组合。上面给的例子b可以认为是b[0],b[1]两个一维数组的组合,既可以写成b[b[0],b[1]],一维数组一样b[0],b[1]分别表示一维数组的第一个地址,这也可以在调试的时候看出:

    而b也是一个数组,那么b也就表示一个地址或者指针,b相当于&b[0]或者&b[0][0],所以在二维数组中有四个地址是相等的,但是意义也是不同的,那么b就相当于一位数组地址的指针&a,所以b也是一个指向一个含有三个int元素的地址,我们可以称之为指向一个行地址,那么b+1表示第二行的首地址也就是b[1],因为每一行有三个int 数据,所以b+1和b相差3*4=12个字节。

    对于二维数组的,常常可以使用二个“*”操作,上面我们已经看到了b表示一个地址,一维数组的情况,那么*b表示b[0],而b[0]也是一个地址,*b[0]表示b[0][0],从而可以得出**b=b[0][0],对于*(b+1)也和 *(b+0)是同样的道理,*(b+1)=b[1]。 我们再来看*b[1], 因为*b[1]=*(b[1]+0)=*(&b[1][0])=b[1][0], 可以看出,这就是 二维数组中第二行第一个元素的地址 。*(*(b+1)+1)因为*(*(b+1)+1)=*(*(&b[1])+1)=*(b[1]+1)=*(&b[1][0]+1)=*(&b[1][1])=b[1][1],语言描术就是 ,b+1使地址偏移到了二维数组中第二行所包含的一维数组的地址(或第二行的行地址 ),然后再对这个行地址求指针(或求值)运算,因此就得到第二行第一个元素的地址 , 然后再对这个地址偏移一个单位, 就得到第二行第二个元素的地址, 再对这个地址进行指针运算 ,就得到了这个元素的值,即 b[1][1],其他的内容可以以止类推 。

    int _tmain(int argc, _TCHAR* argv[])
    {
    
        printf("%s\n","打印一维数组指针");
        int a[5]={1,2,3,4,5};
    
        printf("%p\n",a);
        printf("%p\n",&a[0]);
        printf("%p\n",&a);
        printf("%p\n",&a+1);
        printf("%p\n",a+1);
        printf("%p\n",a+2);
    
        printf("%s\n","打印二维数组指针");
    
    
        int b[2][3]={{1,2},{3,4}};
    
    
        printf("%p\n",b);
        printf("%p\n",b[0]);
        printf("%p\n",&b[0]);
        printf("%p\n",&b[0][0]);
    
        printf("%p\n",*(b+1));
        printf("%p\n",b[1]);
    
        printf("%s\n","打印偏移");
        printf("%p\n",b+1);
        printf("%p\n",b+2);
        printf("%p\n",b[1]+1);
        printf("%p\n",b[2]);
        
        printf("%s\n","二维数组");
        printf("%d\n",**b);
        printf("%d\n",b[0][0]);
        printf("%p\n",*(b+1));
        printf("%p\n",b[1]);
    
        getchar();
        return 0;
    }

     

     

    和a+1,&a+1  类似,我们也可以看出b,b+1,b[0]+1的区别:

     

     以上不算什么真知灼见,只是希望在解决问题的时候,可以多用下这些探索的方法。

  • 相关阅读:
    追踪CPU跑满
    巧用Systemtap注入延迟模拟IO设备抖动
    用户态函数跟踪 (无调试符号)
    C#(同步调用、异步调用、异步回调)
    如何安装Python环境以及为Visual Studio 2012安装Python插件
    [转] FTP主动模式和被动模式的区别
    ORA-12154: TNS: 无法解析指定的连接标识符
    C# Enum,Int,String的互相转换 枚举转换
    2.Maven之(二)Maven生命周期
    1.Maven之(一)Maven是什么
  • 原文地址:https://www.cnblogs.com/zuiyirenjian/p/3114374.html
Copyright © 2020-2023  润新知