深入理解C语言指针的奥秘(转自 哈工大·纯C论坛)
c语言吧
全部回复
仅看楼主
level 9
assiss 楼主
正规院校的毕竟不一样啊.不过这篇文章中有很多技巧性的不适合初学者学习.大家看看,了解一下就可以了.别跟着乱学啊.要是出错了,把你系统搞崩溃了,资料都没有了,找我哭,我是没办法的.=======================深入理解C语言指针的奥秘副标题:作者:未知 文章来源:不详 点击数:19 更新时间:2004-11-8指针的概念   指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。 要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的 类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区。让我们分别说明。   先声明几个指针放着做例子:   例一:   (1)int*ptr;   (2)char*ptr;   (3)int**ptr;   (4)int(*ptr)[3];   (5)int*(*ptr)[4];   如果看不懂后几个例子的话,请参阅我前段时间贴出的文章<<如何理解c和c ++的复杂类型声明>>。   指针的类型  从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:   (1)int*ptr;//指针的类型是int*   (2)char*ptr;//指针的类型是char*   (3)int**ptr;//指针的类型是int**   (4)int(*ptr)[3];//指针的类型是int(*)[3]   (5)int*(*ptr)[4];//指针的类型是int*(*)[4]   怎么样?找出指针的类型的方法是不是很简单?   指针所指向的类型  当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。   从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:   (1)int*ptr;//指针所指向的类型是int   (2)char*ptr;//指针所指向的的类型是char   (3)int**ptr;//指针所指向的的类型是int*   (4)int(*ptr)[3];//指针所指向的的类型是int()[3]   (5)int*(*ptr)[4];//指针所指向的的类型是int*()[4]   在指针的算术运算中,指针所指向的类型有很大的作用。   指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。我看了不少书,发现有些写得差的书中,就把指针的这两个概念搅在一起了,所以看起书来前后矛盾,越看越糊涂。   指针的值,或者叫指针所指向的内存区或地址  指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。 指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为si zeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。   指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。   以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?   指针本身所占据的内存区  指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。   指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
2004年11月08日 11点11分 1
level 9
assiss 楼主
在表达式*array中,array扮演的是指针,因此这个表达式的结果就是数组第0号单元的值。sizeof(*array)测出的是数组单元的大小。   表达式array+n(其中n=0,1,2,....。)中,array扮演的是指针,故array+n的结果是一个指针,它的类型是TYPE*,它指向的类型是TYPE,它指向数组第n号单元。故sizeof(array+n)测出的是指针类型的大小。   例十: intarray[10]; int(*ptr)[10]; ptr=&array;   上例中ptr是一个指针,它的类型是int(*)[10],他指向的类型是int[10] ,我们用整个数组的首地址来初始化它。在语句ptr=&array中,array代表数组本身。   本节中提到了函数sizeof(),那么我来问一问,sizeof(指针名称)测出的究竟是指针自身类型的大小呢还是指针所指向的类型的大小?答案是前者。例如: int(*ptr)[10];   则在32位程序中,有: sizeof(int(*)[10])==4 sizeof(int[10])==40 sizeof(ptr)==4   实际上,sizeof(对象)测出的都是对象自身的类型的大小,而不是别的什么类型的大小。  指针和结构类型的关系   可以声明一个指向结构类型对象的指针。   例十一: structMyStruct {  inta;  intb;  intc; } MyStructss={20,30,40};//声明了结构对象ss,并把ss的三个成员初始化为20,30和40。 MyStruct*ptr=&ss;//声明了一个指向结构对象ss的指针。它的类型是MyStruct*,它指向的类型是MyStruct。 int*pstr=(int*)&ss;//声明了一个指向结构对象ss的指针。但是它的类型和它指向的类型和ptr是不同的。   请问怎样通过指针ptr来访问ss的三个成员变量? 答案: ptr->a; ptr->b; ptr->c;   又请问怎样通过指针pstr来访问ss的三个成员变量?   答案: *pstr;//访问了ss的成员a。 *(pstr+1);//访问了ss的成员b。 *(pstr+2)//访问了ss的成员c。   虽然我在我的MSVC++6.0上调式过上述代码,但是要知道,这样使用pstr来访问结构成员是不正规的,为了说明为什么不正规,让我们看看怎样通过指针来访问数组的各个单元:   例十二: intarray[3]={35,56,37}; int*pa=array;   通过指针pa访问数组array的三个单元的方法是: *pa;//访问了第0号单元 *(pa+1);//访问了第1号单元 *(pa+2);//访问了第2号单元   从格式上看倒是与通过指针访问结构成员的不正规方法的格式一样。   所有的C/C++编译器在排列数组的单元时,总是把各个数组单元存放在连续的存储区里,单元和单元之间没有空隙。但在存放结构对象的各个成员时,在某种编译环境下,可能会需要字对齐或双字对齐或者是别的什么对齐,需要在相邻两个成员之间加若干个"填充字节",这就导致各个成员之间可能会有若干个字节的空隙。   所以,在例十二中,即使*pstr访问到了结构对象ss的第一个成员变量a,也不能保证*(pstr+1)就一定能访问到结构成员b。因为成员a和成员b之间可能会有若干填充字节,说不定*(pstr+1)就正好访问到了这些填充字节呢。这也证明了指针的灵活性。要是你的目的就是想看看各个结构成员之间到底有没有填充字节,嘿,这倒是个不错的方法。   通过指针访问结构成员的正确方法应该是象例十二中使用指针ptr的方法。指针和函数的关系   可以把一个指针声明成为一个指向函数的指针。 intfun1(char*,int); int(*pfun1)(char*,int); pfun1=fun1; .... .... inta=(*pfun1)("abcdefg",7);//通过函数指针调用函数。   可以把指针作为函数的形参。在函数调用语句中,可以用指针表达式来作为实参。   例十三: intfun(char*); inta; charstr[]="abcdefghijklmn"; a=fun(str); ... ... 
2004年11月08日 11点11分 4
level 0
真的很好——好学者小晖
2004年11月08日 14点11分 6
level 0
很好呀,看完后,对指针的理解好象又深了!!!
2005年04月08日 01点04分 7
level 0
高啊,可惜我没这么好的条件
2005年04月08日 09点04分 8
level 0
谁能给我解释这个题? 对于下述说明,不能使变量p->b的值增1的表达式是()struct str{int a;int *b;}*p;A.++p->b B.*++((p++)->b) C.*p->b++ D.((p++)->b)++ 答案:C请各位帮忙指点一下
2005年04月21日 08点04分 9
level 0
非常好,易于理解
2005年05月22日 03点05分 10
level 0
对于下述说明,不能使变量p->b的值增1的表达式是()struct str{int a; int *b; 定义了成员为:int *型;}*p; A.++p->b B.*++((p++)->b) C.*p->b++ D.((p++)->b)++ 答案:C 分析过程:A:明显 B:(p++)->b明显指向了b,然后P自加,我们不管b,然后进行了*++操作,因为b是指针,所以这是有道理的,也就是说变成*++b 明显这是使b先指向,然后在自加,既满足了条件了C:先指向b,然后指向,在自加 d:也是明显的此题目让我想起了:(*P->b)++ 与 *P->b++ 的区别。
2005年06月17日 02点06分 11
level 0
文章的作者是一个叫girlrong的网友,以前好像是广州什么什么社区的版主,很多网友都喜欢她。
2005年08月13日 01点08分 12
level 0
工件加工问题现有14件工件等待在一台机床上加工。某些工件必须安排在另一些工件完工之后才能开始,第j号工件的先期必须完工的工件由下表给出:工件序号j 1 2 3 4 5 6 7前期工件号 3 ,4 5,7,8 5,9 —— 10 ,11 3 ,8 ,9 4工件序号j 8 9 10 11 12 13 14前期工件号 3,5,7 4 —— 4,7 6,7,14 5 ,12 1,2 ,6若第j号工件紧接着第i号工件完工后开工,机床需要花费的准备时间Tij为: Tij= i+j (i
j) 试设计一个满足条件的加工顺序,使机床花费的总时间最少
2005年08月13日 05点08分 13
level 0
例十八不能编译通过vc++6
2005年11月28日 13点11分 14
level 0
声明了一个数组TYPE array[n],则数组名称array就有了两重含义:第一,它代表整个数组,它的类型是TYPE[n];第二 ,它是一个指针,该指针的类型是TYPE*,该指针指向的类型是TYPE,也就是数组单元的类型,该指针指向的内存区就是数组第0号单元,该指针自己占有单独的内存区,注意它和数组第0号单元占据的内存区是不同的。该指针的值是不能修改的,即类似array++的表达式是错误的。 “该指针自己占有单独的内存区,注意它和数组第0号单元占据的内存区是不同的。” 这个说法是错误的,数组名对应着(不是指向)第0号单元占据的内存区,它不是一个指针,没有自己的内存区,但是可以当成指针来用
2005年12月23日 02点12分 15
level 0
书上讲的更好!
2006年03月06日 12点03分 16
level 0
好多好多 都晕了 哈哈
2006年03月07日 03点03分 17
level 0
??//\
2006年04月16日 03点04分 18
level 0
就他妈会抄袭别人地!~你要牛的话就用指针搞几种彩票算法出来!~
2006年11月17日 04点11分 19
level 0
就算抄袭 也要有这份心..  你没这份心  都在这说别人   别人为我们初学者 提供就是好事.你他妈的 也提供啊操  老子最看不得你这人 老子QQ 82602935加我 老子D死你 
2006年12月21日 14点12分 20
level 1
好深奥啊
2006年12月31日 13点12分 23
level 0
我只能说!“垃圾”!楼主所说的问题我在第一次学习指针的时候就OK了!不知道为什么????大家怎么不那出来点真正的问题出来呢???
2007年01月01日 01点01分 24
1 2 3 尾页