查看“指针”的源代码
←
指针
跳转至:
导航
、
搜索
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于这些用户组的用户使用:
管理员
、
行政员
、users
您可以查看与复制此页面的源代码。
1.在日常生活中指针是[[仪器]]或[[钟表]]上的,可动的,一般狭长的,往往在一段尖的用来指示测量的数据的装置。 2.在信息工程中指针是一个用来指示一个内存地址的[[计算机]][[语言]]的变量或[[中央处理器]]([[CPU]])中[[寄存器]](Register)。指针一般出现在比较近机器语言的语言,如汇编语言或C语言。面向对象的语言如Java一般避免用指针。指针一般指向一个函数或一个变量。在使用一个指针时,一个[[程序]]既可以直接使用这个指针所储存的[[内存]][[地址]],又可以使用这个地址里储存的变量或[[函数]]的值。大家都认为,c语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用上。因此,说指针是c语言的灵魂,一点都不为过。同时,这种说法也让很多人产生误解,似乎只有[[c语言]]的指针才能算指针。[[basic]]不支持指针,在此不论。其实,[[pascal]]语言本身也是支持指针的。从最初的pascal发展至今的object pascal,可以说在指针运用上,丝毫不会逊色于c语言的指针。 指针1、内存分配[[表]] 计算机中的内存都是编址的,就像你家的地址一样。在程序编译或者运行的时候,系统(可以不关心具体是什么,可能是编译器,也可能是操作系统)开辟了一张表。每遇到一次声明语句(包括函数的传入参数的声明)都会开辟一个内存空间,并在表中增加一行纪录。记载着一些对应关系。----------------------------------------------------Declaration | ID Name Address Length----------------------------------------------------Int nP; | 1 nP 2000 2Bchar myChar; | 2 myChar 2002 1Bint *myPointer; | 3 myPointer 2003 2Bchar *myPointer2; | 4 myPointer2 2005 2B---------------------------------------------------- 2、指针就是一个整数。 指针,是一个无符号整数(unsigned int,下简写为int),它是一个以当前系统寻址范围为取值范围的整数。32 位系统下寻址能力(地址[[空间]])是4G-bit(0~232-1)二进制表示长度为32bit,也就是4B。 int 类型也正好如此取值。 例证就是程序1 得到的答案和程序2 的答案一致。(不同机器可能需要调整一下pT 取值。)----------------------------------------------------程序1#include main(){ char *pT; char t='h'; pT= putchar(*pT);}----------------------------------------------------程序2#include main(){ char *pT; char t='h'; pT=(char *)1245048; putchar(*pT);}---------------------------------------------------- 加上(char *)是因为毕竟int 和char *不是一回事,需要强制转换,否则会有个警告。因为char *声明过的类型,一次访问1 个sizeof(char)长度,double *声明过的类型,一次访问1个sizeof(double)长度。 在汇编里int 类型和指针就是一回事了。因为不论是整数还是指针,执行自增的时候,都是其值加一。如果上文声明char *pT;,[[汇编语言]]中pT 自增之后值为1245049,可是C语言中pT++之后pT 值为1245049。如果32 位系统中, s 上文声明int *pT;,汇编语言中pT 自增之后值为1245049,可是[[C 语言]]中pT++之后pT 值为1245052。 为什么[[DOS]]下面的Turbo C,和[[Windows ]]下VC 的int 类型不一样长。因为[[DOS]]是16位的,[[Windows]] 是32 位的,可以预见,在64 位Windows 中编译,上文声明int *pT;,pT++之后pT 值为1245056。 那么,复杂的结构怎么分配空间呢?C 语言的结构体(汇编语言对应为Record 类型)按顺序分配空间。----------------------------------------------------int a[20];----------------------------------------------------typedef struct st{ double val; char c; struct st *next;} pst;----------------------------------------------------pst pT[10];---------------------------------------------------- 在32 位系统下,内存里面做如下分配(单位:H,16 进制);----------------------------------------------------变量 2000 2001 2002 2003 2004 2005 2006 … 204C 204D 204E 204F地址 a[0] a[1] … a[19]----------------------------------------------------变量 2050 2051 … 2057 2058 2059 205A 205B 205C 205D 205E 205F地址 pst.val pst.c pst.next 无效 无效 无效---------------------------------------------------- 这就说明了为什么sizeof(pst)=16 而不是8。编译器把结构体的Size 规定为结构体成员中Size 最大的那个类型的整数倍。 至于pT 的存储,可以依例推得。总长为160,此不赘述。 有个问题,如果执行pT++,答案是什么?是自增16,还是160?别忘了,pT 是常量,不能加减。 所以,我们就可以声明:----------------------------------------------------typedef struct BinTree{ int value; struct BinTree *LeftChild; struct BinTree *RightChild;} BTree;---------------------------------------------------- 用一个整数,代表一棵树的结点。把它赋给某个结点的LeftChild/RightChild 值,就形成了上下级关系。只要无法找到一个路径,使得A-LC/RC-LC/RC...-LC/RC==A,这就构成了一棵[[二叉树]]。反之就成了[[图]]。 3、C 的按值传递 C 中函数调用是按值传递的,传入参数在子函数中只是一个初值相等的副本,无法对传入参数作任何改动。但实际编程中,经常要改动传入参数的值。这一点我们可以用传入参数的地址而不是原参数本身,当对传入参数(地址)取(*)运算时,就可以直接在内存中修改,从而改动原想作为传入参数的参数值。----------------------------------------------------#include void inc(int *val){ (*val)++;}main(){ int a=3; inc(&a); printf("%d" , a);}---------------------------------------------------- 在执行inc(&a);时,系统在内存分配表里增加了一行“inc 中的val”,其地址为新地址,值为&a。操作*val,即是在操作a 了。 4、*和&运算 为了(*p)操作是这样一种运算,返回p 的值作为地址的那个空间的取值。(&p)则是这样一种运算,返回当时声明p 时开辟的地址。显然可以用赋值语句对内存地址赋值。我们假设有这么两段内存地址空间,他们取值如下:(单位:H,16 进制)----------------------------------------------------地址 0000 ... 2000 2001 2002 2003 2004 ... 3000 3001 3002 3003 ...取值 ???? ... 01 30 00 00 30 00 03 20 9A---------------------------------------------------- 假设有这么一段代码:(假设开辟空间时p 被分配给了3001H、3002H 两个位置)----------------------------------------------------int *p;p=2003;*p=3001H---------------------------------------------------- **p 的值为多少? **p=*(*(p))=*(*(2003H))=*(3000H)=0300H。 那么&&p、*(&p)和&(*p)又等于多少? &&p=&(&(p))=&(3001H),此时出错了,3001H 是个常数怎么可能有地址呢? *&p=*(&(p))=*(3001H)=2003H,也就是*&p=p。 &*p=&(*(p))=&(3001H),读者可能以为&*p=p 此时出错了,3001H 是个常数怎么可能有地址呢? 4'、另类的*和& 两个地方要注意: 在程序声明变量的时候的*,只是表明“它是一个整数,这个整数指向某个内存地址,一次访问sizeof(type)长度”。这点不要和(*)操作符混淆; 在C++程序声明变量的时候的&,只是表明“它是一个引用,这个引用声明时不开辟新空间,它在内存分配表加入新的一行,该行内存地址等于和调用时传入的对应参数内存地址”。 这点不要和(*)声明符,(&)操作符混淆。 清华大学软件学院免试研究生面试就有问过这个问题。 5、双重指针(指向指针的指针) 双重指针又是怎么一回事儿呢?综合2 的BTree 定义,和3 的说法。对于一棵树,我们通常用它的根节点地址来表示这棵树。这就使“擒贼先擒王”。找到了树的根,其每个节点都可以找到。 但是有时候我们需要对树进行删除节点,增加节点操作,往往考虑到删除根节点,增加的节点取代原来的根节点作为新根节点的情况。为了修改根节点这个“整数”,我们需要退一步,使用这个“整数”的内存地址,也就是指向这个“整数”的指针。在声明时,我们用2 个*号,声明指向指针的指针。它的意思是“它是一个整数,这个整数指向某个内存地址,一次访问sizeof(int)长度,其值是一个整数,那个整数值指向某个内存地址,一次访问sizeof(BTree)长度。”。详见“数据结构.rar”有关“树”(06 文件夹)的程序代码。 6、指针数组、数组指针和指向函数的指针 指针数组:就是一个整数数组,那个[[数组]]的各个元素都是[[整数]],指向某个[[内存]]地址。 数组指针:数组名本身就是一个指针,指向数组的首地址。注意这是一个常数。 指向函数的指针:从二进制角度考虑,数组名是该数组数据段首地址,函数名就是该代码段的首地址,可以用“int *fun()”。在二进制层面,代码段和数据段什么区别?没什么区别。----------------------------------------------------#include void inc(int *val){ (*val)++;}main(){ void (*fun)(int *); int a=3; fun=inc; (*fun)(&a); printf("%d" , a);} [[Category:技術應用]]
返回至
指针
。
导航菜单
华夏文化百科
访客
个人工具
创建账户
登录
名字空间
页面
讨论
不转换
不转换
简体
繁體
大陆简体
香港繁體
澳門繁體
大马简体
新加坡简体
台灣正體
视图
查看
查看源代码
历史
操作
搜索
华韵导航
子站导航
首页
查字
助手
经典
文集
重要典籍
家训大全
论语集释
周易
资治通鉴
竹书纪年
十三经
金瓶梅小说
古典小说
百科导航
新撰词条
近篡词条
待撰词条
随机页面
使用帮助
工具
链入页面
相关更改
特殊页面
页面信息
旧字形下载
DroidSansFallback(荐)
H-MingLiUC-98(荐)
花园明朝体九万汉字
海峰十三万汉字库
极点海峰9.5词库
更多