指针 指针 到底有什么好处?

zsd1101897 2005-07-21 08:05:37
小弟是新手~刚学c不算久~
就很不明白指针有什么好处~
或者应该说感觉上模模糊糊感觉到指针有一定的用处~
但是具体真有很多好处吗?
弄不明白~想要大虾们给指点一下~
感谢万分~
或者说说你们在以前刚学完指针后的感觉~
我学c用的是潭浩强写的那本《c程序设计》
感觉还行,因为潭浩强写的这本书不象有的计算机著作,喜欢动不动搬些让新手看的头晕的东西,比较通俗~
...全文
1048 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
333sunshine 2005-07-21
  • 打赏
  • 举报
回复
楼上讲得太多了。一两眼看不明白。 我来讲个简单的。

指针就是一个内存字节块。 字节块里面的内容是一个地址。
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
二、指针的类型

指针的类型,呃,这是最值得留意的对手。

  其实并没有所谓的“指针类型”,而只有指针所指对象的类型。换言之,指针只是保存对象地址的一个容器而已,强加于其上的对象类型只是一种编译期信息,用于提示编译器该从此地址取出多少个字节来交差罢了。所以不能把指针所指对象的类型和指针本身的类型切开来看,而是从一开始就应该把它们当成一回事。可以说,类型系统中有多少种类型,就应该有多少种指针(同样地,就可以有多少种引用,多少种数组,多少种……:)。噢噢,话归正题,下面一一为大家讲解各种指针类型,顺便提醒一下在使用针指的过程中容易出错的地方。

  (PS:刚才废人说《TCPL》把指针看作是别的类型的“派生类型”,很值得玩味。)

  1、最简单的指针:指向单一对象的指针(为什么我是说“对象”而非“变量”呢?因为对象才是类型系统要处理的东东,变量只是对象的实现手法)。示例如下:

  int *pi; // 声明+定义一个指向int类型对象的指针

  以上语句在只是简单地“声明+定义”了一个指针,在符号表中引入了指针的名字,同时保存了编译期类型信息。但是这样的写法有可能会被报警,因为C编译器大多会针对未进行初始化的指针扔出一个警告(警告粗心大意的程序员,直接定义的局部变量未经初始化时的值是随机的,而对一个拥有随机地址的指针进行对象引用……Bombing!)。所以我们最好这样写:

  int a, *pi = &a;

或者

 int *pi = 0;  // 国内的C相关考试最喜欢在这里出考题

  记得一点,定义一个指针就要对它初始化,没错的。而引用所指对象也很简单,*pi就是了。概念上可以把*pi当做a来用,但要注意运算符的优先级(比如*p++和*(p++)还有*++p……头疼了吧?:)。

  2、比较复杂的指针:指向复合对象的指针。复合对象可能是数据的聚合(比如数组,结构体,枚举),也可能是类型的聚合(比如联合体),换言之,复合对象是“用户定义类型”,千变万化类型各异。但不管它们怎么变,总会有对应的指针指向它们的实例对象(书上说指针是其它类型的派生类型,越想越有道理)。示例一:

  struct HUMAN {
    char name[24];
    int age;
  }h;
  struct HUMAN *ph = &h;

  要通过指针引用结构体的成员,可以使用->操作符,比如ph->name[0]或者ph->age。同样地,*ph在概念上与h等价,可以这样使用*ph.age(有时候加上一对括号比较安全,(*ph).age)。

  示例二:
  union MSG_ENTRY {
    int (*Button_Click)(POINT *pp);
    void (*Idle)(void);
  }me;
  union MSG_ENTRY * pm = & me;

  要通过指针引用联合体的成员,同样可以使用->操作符,比如pm->Button_Click或者pm->Idle。而*pm也与me等价。但提请注意,pm->Button_Click与pm->Idle两者的地址实际上是一样的。这是联合体与结构体的基本差异所在。

  示例三:
  typedef int ARRAY[10];
  ARRAY a;
  ARRAY * pa = &a;

  在这里,pa所指对象(即a对象)的类型可能会令人迷惑。但仔细观察分析后就可以知道,a的类型是一个拥有10个整型元素的数组,而pa就是指向此对象的指针。也就是说,pa的类型应该是int (*)[10]。请大家注意(*)和[10],前者是将指针限定为“指向数组”,后者则限定了“该数组的大小”。如有以下代码:
  int b[5];
  pa = &b; // 编译器应当报警,因为int (*)[5]类型无法与int (*)[10]兼容

  嘿嘿……看明白了?也就是说,数组大小也成为限定饰修的一部分。

  还有几个非常容易混淆的类型是:
  int *p[10];
  int (*pp)[10];
  int *(*ppp)[10];

  其中,p是一个数组,拥有10个int *类型的元素。而pp是一个指针,指向int [10]类型的数组对象。ppp也是一个指针,指向int *[10]类型的数组对象。所以可以这样写:
  ppp = &p; // ok
  却不能这样写:
  pp = &p; // 两者的类型无法兼容

  (PS:有关数组与指针的关系,可以参考我写的另外一篇小专题,URL为http://community.csdn.net/Expert/topic/3142/3142075.xml?temp=.2214624。而且数组与指针的关系还可以扩展来讲,这是后话,按下不表)

  啊啊,写得有点累了,大家也看得有点累了吧?休息,休息一下:)

三、指针的类型二

可以想象一下,当使用了类型来限定某一块内存区域之后,这个区域不就可以被视为一个数据的容器了么?而地址,就是访问这个容器中的数据的指向标。函数呢?函数体在语义层面上界定了语句的范围,而在内存层面上,则限定了语句对应的机器码的保存区域。可以想见,函数名就是这个区域的入口。

这样,函数名不就是相当于一个地址么?

嘿嘿,所以这世间就多了一种指针的类型:函数指针。用于保存函数的入口地址并提供间接调用函数的方法。如下:

int foo(void) { return 10; } // 一个函数
int (*p)(void) = &foo; // 一个承载int (void)类函数地址的指针,指针类型为int (*)(void)

看上去挺简单吧?其实就是声明并定义一个int (*)(void)类型的指针变量,然后让它保存了foo函数的地址。当我们写下

int a = (*p)();

的时候,p所指向的函数就会被调用,然后a就得到一个值:10。
其实我们不用写下“&”运算符来取函数的地址。事实上,与数组名类似,函数名本身就是一个地址常量。于是直接写下

p = foo;

也是成立的。同理可证:

int b = p();

也是可行的。当然这有赖于编译器本身的实现,是不是能正确地识别程序员的意图。

“唔,”我听到有同学窃窃私语的声音,“挺简单的嘛……”真的简单么?嘿嘿,挽起你的袖子来,准备来一场头脑风暴吧!看下面这两个东东:

int (*p)(int (*)(void)); // 1:啥指针?
int (*(*pp)(int (*)(void)))(void); // 2:又是啥指针?

第一个指针也许还比较好理解:p是一个指针,指向只有一个形参(参数类型为int (*)(void),指向一个函数),而返回值为int类型的函数。不过,即便是这样的一个指针,也许就已经能让初学者挠破头皮(当然,自称天才者除外)。

第二个指针就更不用说了。可能还会有人问:这是不是指针呀?答案是肯定的。问题在于,它的类型是什么?嘿嘿,花点脑力来研究一下吧。先露点诀窍:从小括号入手。

……

好啦,看明白了么?答案要揭晓啦:pp是一个指向函数的指针,被指向的函数(假设为A)有一个指针形参,该形参又是一个指向函数(假设为B,类型是int (*)(void))的指针,而被指向函数的返回值类型也是一个指向函数(假设为C,类型也是int (*)(void))的指针……怎么样,有没有看傻?:)

嘿嘿,暴风雨前总平静……“今天就是这样,下回再说。”

欢迎大家来我们的站点指正EvilOctal.Yeah.Net:)
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
[原创]指针 魔界的精灵 第一部


文章作者:无锋之刃[EST顾问团]
信息来源:邪恶八进制 中国(www.EvilOctal.com)

一、指针的概念

  我们应该这样理解程序代码:一种可以被机器解释执行的数据。那么,我们就可以用统一的观点来看待程序与数据,并将之与指针关联起来。

  运行时数据总是要存储在内存中的,以备CPU的不时之需。为了能够有效地访问数据,计算机系统势必要对内部存储单元进行编号--就像门牌号一样。有了明确的编号,总线控制器就得以快速而准确地定位并访问内存,顺利地将数据提取出来。在这里,“内存编号”起到了一种指示地址的作用。可以这样说,任何存在于内存中的东西(啊,啊,都是些逻辑上的0、1代码串)都拥有地址,以便于对其进行访问。

  注意唷,“内存编号”这样的东东只存在于逻辑空间内,在物理空间中则是用电路线来映射编号的:)。

  事实上,这种“内存编号”,或者简称“地址”,本身也是一种数据--毕竟它的数据类型可以视为unsigned integer,当然能保存在内存中(废人语:这是丫指针的本质)。但是,这种数据有点特殊:它被用于指示别的数据的地址,所以保存它的内存单元对应的变量类型也比较特殊:指针类型。顾名思义,指针就是一种“其值具有指向性”的变量。看起来颇简单吧?但,越是简单的东西麻烦就越是多,比如……

  指针具有两个属性,一个是它的值(就是地址),一个是它的类型(数据类型)。花开两枝,各表一头,咱们先来说说“地址”的“值”。地址值是有大小范围的,其上下限是[0,2^n),即从“0”到“2的n次幂减1”,其中n是机器地址线的数量。通常这个n值不会与CPU的字长一致,但实际使用地址值时n都会取CPU字长为基准(这个问题另外撰文指出原因)。在不同的硬件平台上,指针变量占用的内存单元数量与其地址值的范围大小成正比,也即指针变量占用n个内存位(bit)。

  在数学中“零”是一个很特殊的值,而值为零的地址也是一个特殊的地址。它于用指示地址为零的内存单元--废话--但是操作系统一般会把拥有零地址的内存区域划为安全区,且只用作捕获越界指针使用。因此将一个指针初始化为零地址是非常安全,而且是非常必要的(在C的某些编译器中一定要对指针进行初始化才能使用)。一般而言,我们不必在意地址的确切值是多少,也不用在意这个地址的种类是什么(实地址,虚地址,物理地址,逻辑地址……),把一切都扔给编译器去完成好了,毕竟人脑不是编译器:)。

  指针的另一个属性是数据类型。实际上这个类型是指针指向的变量的数据类型,而不是指针自身的类型。因为指针的类型是所谓的“用户定义类型”而不是“编译器内建类型”。这个类型有两个作用:1)指示编译器在进行解引用的时候应该从内存中获取几个字节(就是数据类型对应的内存单元占用数,单位是字节Byte),2)以及指示编译器在进行指针类型转换时如何进行类型检查与类型匹配。

  通常来说同一个地址值可以搭配不同的数据类型(只要逻辑上说得通),这样通过指针就可以获取位于同一块内存区域中的不同类型的数据(换言之,是把同一块内存中的0、1代码串解释成不同类型的数据),这就是1)中所说的指针的作用。举个例子:

  int a = 0xFF00;

char *p = (char *)&a; // 强制类型转换,确保类型匹配(第二点作用的体现,以通过类型检查)

cout << *p << endl; // 指示编译器只获取一个字节数值(第一点作用的体现,以取出正确的数据)

  运行结果是0,即只取出了低十六进制位一个字节的数值。

  以上是关于指针专题的前导性知识,希望大家踊跃拍砖。

zsd1101897 2005-07-21
  • 打赏
  • 举报
回复
谢谢 ~~~~~
可以有个问题:打不开(是暂时还是网页现在已没存在)
打开网页后显示
Service Temporarily Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
--------------------------------------------------------------------------------

Apache/1.3.31 Server at www.jothan.com Port 80

刷新几次都这样.............
pcboyxhy 2005-07-21
  • 打赏
  • 举报
回复
学完指针后
感觉太方便了
哈哈
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
《说C》

http://www.eviloctal.com/forum/read.php?tid=8259&fpage=3
http://www.eviloctal.com/forum/read.php?tid=8341&fpage=4
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
http://www.eviloctal.com/forum/read.php?tid=5272&fpage=5

拙作一篇。
zsd1101897 2005-07-21
  • 打赏
  • 举报
回复
好 谢谢~加你qq还是?
我qq是627830~~
email是zsd1101897@163.com
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
我写的《说C》你看不?
zsd1101897 2005-07-21
  • 打赏
  • 举报
回复
BluntBlade(无锋之刃·呢条友好普通) :
介绍一两本有关c的比较通俗又写的比较好的书,行不?
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
看多了就知道哪儿误导人了。
zsd1101897 2005-07-21
  • 打赏
  • 举报
回复

回复人: WingForce(初六,履霜,坚冰至。) ( ) 信誉:99 2005-07-21 20:08:00 得分: 0


但是谭浩强那本书会误导人


误导人?此话怎讲?
WingForce 2005-07-21
  • 打赏
  • 举报
回复
但是谭浩强那本书会误导人
BluntBlade 2005-07-21
  • 打赏
  • 举报
回复
用多了就知道了。

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧