[C/C++值班室]指针专题(二),放分引人拍砖。

BluntBlade 2004-07-14 08:54:36
上一篇相关专题:指针,调皮的精灵。
http://community.csdn.net/Expert/topic/3149/3149011.xml?temp=3.557986E-02

指针,让人郁闷的分子(2)

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

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

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

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

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

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

  int a, *pi = &a; 或者 int *pi = NULL;  // 国内的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。而且数组与指针的关系还可以扩展来讲,这是后话,按下不表)

  啊啊,写得有点累了,大家也看得有点累了吧?休息,休息一下:)
...全文
909 76 打赏 收藏 转发到动态 举报
写回复
用AI写文章
76 条回复
切换为时间正序
请发表友善的回复…
发表回复
conquers 2004-07-21
  • 打赏
  • 举报
回复
学习
fengyvn 2004-07-20
  • 打赏
  • 举报
回复
还有.typedef int ARRAY[10];
  ARRAY a;
  ARRAY * pa = & a;
我试过,pa和*pa地址一样,这又是为什么?
fengyvn 2004-07-20
  • 打赏
  • 举报
回复
请楼主再回答一下.
比如说int * p;
编译器是根据*p判断变量为指针还是根据int*来判断?
如果声明成int **p;
编译器又先编译"哪颗星".....HOHO.
antijpn 2004-07-20
  • 打赏
  • 举报
回复
回复人: BluntBlade(无锋之刃·只留程序不留情) ( ) 信誉:105 2004-07-20 11:05:00 得分: 0


回 fengyvn(我菜我自在)

如果声明成int **p;
编译器又先编译"哪颗星".....HOHO.
--------------
应该把
int **p;
解析成
(int *) *p; // 括号是我解析用的,实际上不必写。
即p是一个指针,指向另一个指针(保存另一个指针变量的地址)




错了,不是这么写的,这样写编译不能通过。
需要写成这样int*(*p);
movado0206 2004-07-20
  • 打赏
  • 举报
回复
受益匪浅,up!!!
BluntBlade 2004-07-20
  • 打赏
  • 举报
回复
回 fengyvn(我菜我自在)

如果声明成int **p;
编译器又先编译"哪颗星".....HOHO.
--------------
应该把
int **p;
解析成
(int *) *p; // 括号是我解析用的,实际上不必写。
即p是一个指针,指向另一个指针(保存另一个指针变量的地址)

BluntBlade 2004-07-20
  • 打赏
  • 举报
回复
pi存储的才是a的地址值
*pi是对pi中的地址,即a的地址取内容。
也即*pi 等价于 a。
hikozl 2004-07-20
  • 打赏
  • 举报
回复
回复人: iwom(晴若月)
*pi = &a
这个就不懂了,&取地址,*取内容,这样写什么意思啊?
*pi存储的是a的地址值
BluntBlade 2004-07-20
  • 打赏
  • 举报
回复
(int *) *p; // 括号是我解析用的,实际上不必写。

这只是我解析指针时使用的方法:)

回楼上

1. 比如说int * p;
编译器根据*p判断。

2. typedef int ARRAY[10];
  ARRAY a;
  ARRAY * pa = & a;
&a的类型是int (*)[10];
pa的类型也是int (*)[10];
:)
fengyvn 2004-07-20
  • 打赏
  • 举报
回复
请楼主再回答一下.

1. 比如说int * p;
编译器是根据*p判断p为指针还是根据int*来判断?

2. typedef int ARRAY[10];
  ARRAY a;
  ARRAY * pa = & a;
这里a本来就是数组的地址,用&a来取一个地址值的地址又是什么意思?
toxyboy 2004-07-20
  • 打赏
  • 举报
回复
头好大啊。。快下班了,本打算进来轻松一下的。
liangbowen 2004-07-17
  • 打赏
  • 举报
回复
唉,你们干脆把代码写成只有1和0再让我看吧。。。
rorot 2004-07-17
  • 打赏
  • 举报
回复
看不懂, 写简单点哈
接分
antijpn 2004-07-17
  • 打赏
  • 举报
回复
void*不带有类型信息,不能进行算术运算。其实我觉得,从语义上void*才代表地址,其他类型的指针不仅仅代表了地址,还附带了指向的对象的信息
yndfcd 2004-07-17
  • 打赏
  • 举报
回复
对void*类型的指针可++吗?

晕.
BluntBlade 2004-07-17
  • 打赏
  • 举报
回复
给楼上的:

p=&d; // 类型不兼容,编译器不会放过的

(void*)p++; // void的长度为0,++了的话是在原地踏步……
cpsoft 2004-07-17
  • 打赏
  • 举报
回复
struct A
{
int a;
double b;
char c;
}

void main()
{
A *p;
A d[2];
p=&d;
(void*)p++;
*p=??; //老大告诉我是什么??
}

oldjackyone 2004-07-17
  • 打赏
  • 举报
回复
yjh1982(血精灵) 确实可恶....

把他给砍了....
oldjackyone 2004-07-16
  • 打赏
  • 举报
回复
const 二维数组...

oldjackyone 2004-07-16
  • 打赏
  • 举报
回复
yjh1982(血精灵) 害人精....


你的那么一句子,偶头晕...
加载更多回复(56)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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