仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 8164|回复: 20
打印 上一主题 下一主题

[C++基础] 来看看:C++指针的概念解读 超具体

[复制链接]
因胸联盟 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-2-7 11:54:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
现在的年轻人,清一色的追求看书看国外教材,当然我也不能低人一个档次,看的都是有名的大师作品,不期自己能够编出惊天地泣鬼神的大作。   指针是一个特别的变量,它外面存储的数值被注释成为内存里的一个地址。要弄清一个指针需求弄清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或叫指针所指向的内存区,还有指针自己所占有的内存区。让咱们分离申明。



    先声明几个指针放着做例子:
    例一:
  1. int *ptr; char *ptr; int **ptr; int (*ptr)[3]; int *(*ptr)[4];
复制代码
 指针的类型

    从语法的角度看,你只需把指针声明语句里的指针名字去失落,剩下的局部就是这个指针的类型。这是指针自己所具有的类型。让咱们看看例一中各个指针的类型:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]
复制代码
  怎样?找出指针的类型的办法是否是很复杂?
 指针所指向的类型

    当你经由过程指针来会见指针所指向的内存区时,指针所指向的类型决意了编译器将把那片内存区里的内容当作甚么来对待。
    从语法上看,你只须把指针声明语句中的指针名字和名字右边的指针声明符*去失落,剩下的就是指针所指向的类型。例如:
  1. int *ptr; //指针所指向的类型是int char *ptr; //指针所指向的的类型是char int **ptr; //指针所指向的的类型是 int * int (*ptr)[3]; //指针所指向的的类型是 int()[3] int *(*ptr)[4]; //指针所指向的的类型是 int *()[4]
复制代码
  在指针的算术运算中,指针所指向的类型有很大的感化。
    指针的类型(即指针自己的类型)和指针所指向的类型是两个概念。当你对C愈来愈熟习时,你会发明,把与指针搅和在一同的“类型”这个概念分红“指针的类型”和“指针所指向的类型”两个概念,是精晓指针的关头点之一。我看了很多书,发明有些写得差的书中,就把指针的这两个概念搅在一同了,所以看起书来前后抵触,越看越懵懂。
 指针的值

    指针的值是指针自己存储的数值,这个值将被编译器看成一个地址,而不是一个普通的数值。在32位法式里,一切类型的指针的值都是一个32位整数,由于32位法式里内存地址全都是32位长。
    指针所指向的内存区就是从指针的值所代表的谁人内存地址入手下手,长度为sizeof(指针所指向的类型)的一片内存区。今后,咱们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;咱们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
    指针所指向的内存区和指针所指向的类型是两个完整分歧的概念。在例一中,指针所指向的类型已有了,但因为指针还未初始化,所以它所指向的内存区是不存在的,或说是有意义的。
    今后,每碰到一个指针,都应当问问:这个指针的类型是甚么?指针指向的类型是甚么?该指针指向了哪里?
 指针自己所占有的内存区

    指针自己占了多大的内存?你只需用函数sizeof(指针的类型)测一下就晓得了。在32位平台里,指针自己占有了4个字节的长度。
    指针自己占有的内存这个概念在判别一个指针表达式是不是是左值时很有效。
 指针的算术运算

    指针可以加上或减去一个整数。指针的这类运算的意义和凡是的数值的加减运算的意义是纷歧样的。例如:
    例二:
  1. char a[20]; int *ptr=a; ... ... ptr++;
复制代码
  在上例中,指针ptr的类型是int*,它指向的类型是int,它被初始化为指向整形变量a。接上去的第3句中,指针ptr被加了1,编译器是如许处置的:它把指针ptr的值加上了sizeof(int),在32位法式中,是被加上了4。因为地址是用字节做单元的,故ptr所指向的地址由本来的变量a的地址向洼地址偏向增添了4个字节。
    因为char类型的长度是一个字节,所以,本来ptr是指向数组a的第0号单位入手下手的四个字节,此时指向了数组a中从第4号单位入手下手的四个字节。
    咱们可以用一个指针和一个轮回来遍历一个数组,看例子:
    例三:
  1. int array[20]; int *ptr=array; ... //此处略去为整型数组赋值的代码。 ... for(i=0;i<20;i++) { (*ptr)++; ptr++; }
复制代码
  这个例子将整型数组中各个单位的值加1。因为每次轮回都将指针ptr加1,所以每次轮回都能会见数组的下一个单位。再看例子:
    例四:
  1. char a[20]; int *ptr = 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个字节。
    总结一下,一个指针ptrold加上一个整数n后,了局是一个新的指针ptrnew,ptrnew的类型和ptrold的类型不异,ptrnew所指向的类型和ptrold所指向的类型也不异。ptrnew的值将比ptrold的值增添了n乘sizeof(ptrold所指向的类型)个字节。就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向洼地址偏向挪动了n乘sizeof(ptrold所指向的类型)个字节。一个指针ptrold减去一个整数n后,了局是一个新的指针ptrnew,ptrnew的类型和ptrold的类型不异,ptrnew所指向的类型和ptrold所指向的类型也不异。ptrnew的值将比ptrold的值削减了n乘sizeof(ptrold所指向的类型)个字节,就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向低地址偏向挪动了n乘sizeof(ptrold所指向的类型)个字节。
 运算符&和*

    这里&是取地址运算符,*是…书上叫做“直接运算符”。&a的运算了局是一个指针,指针的类型是a的类型加个*,指针所指向的类型是a的类型,指针所指向的地址嘛,那就是a的地址。*p的运算了局就八门五花了。总之*p的了局是p所指向的器材,这个器材有这些特色:它的类型是p指向的类型,它所占用的地址是p所指向的地址。
    例五:
  1. 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的了局
    也是个指针,且这两个指针的类型和所指向的类型是一样的,所以?amp;b来给*ptr赋值就是毫无成绩
    的了。 **ptr=34;//*ptr的了局
    是ptr所指向的器材
    ,在这里是一个指针,对这个指针再做一次*运算,了局
    就是一个int类型的变量。
复制代码
 指针表达式

    一个表达式的最初了局假如是一个指针,那末这个表达式就叫指针表达式。上面是一些指针表达式的例子:
    例六:
  1. int a,b; int array[10]; int *pa; pa=&a;//&a是一个指针表达式。 int **ptr=&pa;//&pa也是一个指针表达式。 *ptr=&b;//*ptr和&b都是指针表达式。 pa=array; pa++;//这也是指针表达式。
复制代码
  例七:
  1. char *arr[20]; char **parr=arr;//假如
    把arr看做
    指针的话,arr也是指针表达式 char *str; str=*parr;//*parr是指针表达式 str=*(parr+1);//*(parr+1)是指针表达式 str=*(parr+2);//*(parr+2)是指针表达式
复制代码
  因为指针表达式的了局是一个指针,所以指针表达式也具有指针所具有的四个要素:指针的类型,指针所指向的类型,指针指向的内存区,指针本身占有的内存。
    好了,当一个指针表达式的了局指针已明白地具有了指针本身占有的内存的话,这个指针表达式就是一个左值,不然就不是一个左值。 在例七中,&a不是一个左值,由于它还没有占有明白的内存。*ptr是一个左值,由于*ptr这个指针已占有了内存,其实*ptr就是指针pa,既然pa已在内存中有了本人的地位,那末*ptr固然也有了本人的地位。
 数组和指针的关系

    假如对声明数组的语句不太分明的话,请参阅我前段工夫贴出的文章<<若何了解c和c++的庞杂类型声明>>。 数组的数组名其实可以看做一个指针。看下例:
    例八:
  1. int array[10]={0,1,2,3,4,5,6,7,8,9},value; ... ... value=array[0];//也可写成:value=*array; value=array[3];//也可写成:value=*(array+3); value=array[4];//也可写成:value=*(array+4);
复制代码
  上例中,普通而言数组名array代表数组自己,类型是int [10],但假如把array看作指针的话,它指向数组的第0个单位,类型是int *,所指向的类型是数组单位的类型即int。因而*array等于0就一点也不奇异了。同理,array+3是一个指向数组第3个单位的指针,所以*(array+3)等于3。其它依此类推。
    例九:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]0
复制代码
  上例中,str是一个三单位的数组,该数组的每一个单位都是一个指针,这些指针各指向一个字符串。把指针数组名str看成一个指针的话,它指向数组的第0号单位,它的类型是char**,它指向的类型是char *。
    *str也是一个指针,它的类型是char*,它所指向的类型是char,它指向的地址是字符串”Hello,this is a sample!”的第一个字符的地址,即’H'的地址。 str+1也是一个指针,它指向数组的第1号单位,它的类型是char**,它指向的类型是char *。
    *(str+1)也是一个指针,它的类型是char*,它所指向的类型是char,它指向”Hi,good morning.”的第一个字符’H',等等。
    上面总结一下数组的数组名的成绩。声了然一个数组TYPE array[n],则数组称号array就有了两重寄义:第一,它代表全部数组,它的类型是TYPE [n];第二,它是一个指针,该指针的类型是TYPE*,该指针指向的类型是TYPE,也就是数组单位的类型,该指针指向的内存区就是数组第0号单位,该指针本人占领独自的内存区,注重它和数组第0号单位占有的内存区是分歧的。该指针的值是不克不及修正的,即相似array++的表达式是毛病的。
    在分歧的表达式中数组名array可以饰演分歧的脚色。
    在表达式sizeof(array)中,数组名array代表数组自己,故这时候sizeof函数测出的是全部数组的巨细。
    在表达式*array中,array饰演的是指针,因而这个表达式的了局就是数组第0号单位的值。sizeof(*array)测出的是数组单位的巨细。
    表达式array+n(个中n=0,1,2,….。)中,array饰演的是指针,故array+n的了局是一个指针,它的类型是TYPE*,它指向的类型是TYPE,它指向数组第n号单位。故sizeof(array+n)测出的是指针类型的巨细。
    例十:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]1
复制代码
  上例中ptr是一个指针,它的类型是int (*)[10],他指向的类型是int [10],咱们用全部数组的首地址来初始化它。在语句ptr=&array中,array代表数组自己。
    本节中提到了函数sizeof(),那末我来问一问,sizeof(指针称号)测出的事实是指针本身类型的巨细呢仍是指针所指向的类型的巨细?谜底是前者。例如:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]2
复制代码
  则在32位法式中,有:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]3
复制代码
  实践上,sizeof(对象)测出的都是对象本身的类型的巨细,而不是其余甚么类型的巨细。
 指针和布局类型的关系

    可以声明一个指向布局类型对象的指针。
    例十一:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]4
复制代码
  请问如何经由过程指针ptr来会见ss的三个成员变量?
    谜底:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]5
复制代码
  又请问如何经由过程指针pstr来会见ss的三个成员变量?
    谜底:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]6
复制代码
  呵呵,固然我在我的MSVC++6.0上调式过上述代码,然而要晓得,如许利用pstr来会见布局成员是不正轨的,为了申明为何不正轨,让咱们看看如何经由过程指针来会见数组的各个单位:
    例十二:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]7
复制代码
  经由过程指针pa会见数组array的三个单位的办法是:
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]8
复制代码
  从格局上看却是与经由过程指针会见布局成员的不正轨办法的格局一样。
    一切的C/C++编译器在分列数组的单位时,老是把各个数组单位寄存在一连的存储区里,单位和单位之间没有空地。但在寄存布局对象的各个成员时,在某种编译情况下,能够会需求字对齐或双字对齐或是其余甚么对齐,需求在相邻两个成员之间加若干个“填充字节”,这就招致各个成员之间能够会有若干个字节的空地。
    所以,在例十二中,即便*pstr会见到了却构对象ss的第一个成员变量a,也不克不及包管*(pstr+1)就必定能会见到布局成员b。由于成员a和成员b之间能够会有若干填充字节,说不定*(pstr+1)就正好会见到了这些填充字节呢。这也证实了指针的天真性。如果你的目标就是想看看各个布局成员之间究竟有无填充字节,嘿,这却是个不错的办法。
    经由过程指针会见布局成员的准确办法应当是象例十二中利用指针ptr的办法。
 指针和函数的关系

    可以把一个指针声明成为一个指向函数的指针。
  1. int *ptr; //指针的类型是int * char *ptr; //指针的类型是char * int **ptr; //指针的类型是 int ** int (*ptr)[3]; //指针的类型是 int(*)[3] int *(*ptr)[4]; //指针的类型是 int *(*)[4]9
复制代码
  可以把指针作为函数的形参。在函数挪用语句中,可以用指针表达式来作为实参。
有首歌曲这样唱:说到不如做到,要做就做最好。
爱飞 该用户已被删除
沙发
发表于 2015-2-7 11:55:20 | 只看该作者
其实早在本科一年级就学过C++,当年好像也比较认真的学过,至少成绩上算是认真学过的,只是当年大脑没怎么开化,学的半生不熟的,高级编程自然不用说。
分手快乐 该用户已被删除
板凳
发表于 2015-2-7 11:55:20 | 只看该作者
否极泰来。在你专注一个技术极度郁闷得时候不要放弃,可以暂时放弃,但是请马上回来,因为灵感在等你。黎明前确实是黑暗,但是到了黎明,下面就是很长一段得光明。
小女巫 该用户已被删除
地板
发表于 2015-2-15 09:08:46 | 只看该作者
我当初学习MFC三个月,连门都没有进去,我非常懊恼,看着人家学VB得轻松就做出窗口程序,而自己还是在控制台下苦战,向导生成得代码实在不懂。
乐观 该用户已被删除
5#
发表于 2015-3-4 11:23:42 | 只看该作者
天将降大任与斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,.......理解得人自然会在心中默念,不理解得会笑我土。
若天明 该用户已被删除
6#
发表于 2015-3-11 18:51:29 | 只看该作者
虽然还不明确软件技术包含的具体内容,但从C++语言这门课程开始,已发现程序设计的乐趣,在学习C++语言的过程中也学到了许多计算机应用基础知识,对计算机的机体也有了一个大体的了解。
飘飘悠悠 该用户已被删除
7#
发表于 2015-3-19 07:57:09 | 只看该作者
可以说是C++的核心,相对来说也比较难以理解,因为这些技术很多都是面向于写库的人,初学C++的人很难用得上。
老尸 该用户已被删除
8#
发表于 2015-3-20 22:11:56 | 只看该作者
关于用类来控制C++的内存分配,应该算是C++的一个高级技法。写的好的C++程序,基本看不到delete与new。因为这些内存的分配,销毁都让一特殊的类去管理。
谁可相欹 该用户已被删除
9#
发表于 2015-3-27 12:50:49 | 只看该作者
面向对象思想+CPP语法+算法+实践=学会,初期学习语法较重要,你写的代码编译器都“读”不懂,怎么行?
不帅 该用户已被删除
10#
发表于 2015-3-27 18:09:51 | 只看该作者
我觉得你一开始..应该学好\\\\\\\\\\\\\\\"数学\\\\\\\\\\\\\\\", \\\\\\\\\\\\\\\"数据结构\\\\\\\\\\\\\\\" \\\\\\\\\\\\\\\"算法\\\\\\\\\\\\\\\", \\\\\\\\\\\\\\\"英语\\\\\\\\\\\\\\\"记住.学语言.不仅仅是学语言. 语言仅是一种表达方式而已..
小魔女 该用户已被删除
11#
发表于 2015-3-30 18:44:22 | 只看该作者
大学C++老师开始上课就告诉我们了这个秘诀,而听取得人不多,所以最后很大一批转Java了。对于一个初学者来说,熟悉语法、锻炼手感和培养思维最好得办法就是code.
深爱那片海 该用户已被删除
12#
发表于 2015-4-9 11:21:32 | 只看该作者
通过实际操作,学会 C++语言程序编程的基本步骤、基本方法,开发了自己的逻辑思维能力,培养了分析问题、解决问题的能力。深刻体会到“没有做不到的,
第二个灵魂 该用户已被删除
13#
发表于 2015-4-17 23:11:26 | 只看该作者
特别喜欢用转义运算符。师兄编写的程序也是这样,既用了class类(C++独有),编程风格又尽是C的(printf呀,struct结构体呀,来回的用,搞的我晕头转向)。
简单生活 该用户已被删除
14#
发表于 2015-4-21 06:25:22 | 只看该作者
程序.最主要的是实践.就我所学过的语言来说(差不多十门), C++应该是其中最难的.
灵魂腐蚀 该用户已被删除
15#
发表于 2015-4-21 12:45:17 | 只看该作者
都挺过来。所以你可以试一下,灵感光顾得感觉非常美妙!!!
兰色精灵 该用户已被删除
16#
发表于 2015-4-23 07:21:41 | 只看该作者
关于看书和实践。书本给我们的只能是原理上的介绍,而作为工科学生,以后不是需要你去写本书,或者讲节课,所以实践的过程就很关键,从看程序对原理的理解,到自己写程序的实战都是对编程思维很好的提高。
蒙在股里 该用户已被删除
17#
发表于 2015-4-26 13:10:41 | 只看该作者
实训的项目是高级语言程序设计。说实话,在这么多科目中,这是我学得最糟糕的一科。刚开始,我对这实训没什么信心,不知能否按时完成。
18#
发表于 2015-5-3 02:43:55 | 只看该作者
不耻上问。初学者有时候碍于面子,抑或是怕人家笑话而不敢问问题。没有必要,你问得人以前也是一样过来得。前提找一个技术上大家认为强得,而且容易交流得。
冷月葬花魂 该用户已被删除
19#
发表于 2015-5-4 02:17:08 | 只看该作者
在实际操作过程中犯的一些错误还会有意外的收获,感觉实训很有意思。在具体操作中对这学期所学的C++语言的理论知识得到巩固,达到实训的基本目的,也发现自己的不足之出,在以后的上机中应更加注意。
变相怪杰 该用户已被删除
20#
发表于 2015-6-17 20:48:04 | 只看该作者
此外,在实训中,我还认识到自己的粗心。在编程时,粗心的把一语言写错,导致结果运行不了。在以后的学习中,我要特别注意小节,要认真对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-12-22 14:42

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表