char (*(*x[3])())[5] 怎么解释 谢谢

manutdsodagreen 2010-06-10 05:27:46
char (*(*x[3])())[5] 怎么解释 谢谢
...全文
1447 26 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
sunboyqq23 2010-06-12
  • 打赏
  • 举报
回复
呵呵回复内容太短了!日 回复太快,请先休息一下!
barryhappy 2010-06-12
  • 打赏
  • 举报
回复
mark
brysjlulu 2010-06-12
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 forestdb 的回复:]
引用 22 楼 mymtom 的回复:
引用 10 楼 zhao4zhong1 的回复:

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得……
[/Quote]
他不是什么方法论,你来久了就知道,他就这一句回复到处贴。。
mymtom 2010-06-11
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 zhao4zhong1 的回复:]

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
[/Quote]
ForestDB 2010-06-11
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 mymtom 的回复:]
引用 10 楼 zhao4zhong1 的回复:

VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
[/Quote]
人家也只不过是种方法论。
--!!

char (*(*x[3])())[5];
x是个数组,有3个元素,每个元素是个函数指针,
此函数指针指向的函数不带参数,返回一指针,
该指针指向有5个char元素的数组。
everbeing 2010-06-10
  • 打赏
  • 举报
回复
分析楼上的都有,主要掌握 常见指针用法 以及 函数指针
但觉得那种用法 拿来看看还可以,但用来声明也没有什么实际意义,没多必要再这个问题上多纠结

char (*(*x[3])())[5],
(先“最简单化”一个普通的模型,事实上看具体应用可能更复杂)
1).这个可以首先类比简单的 char p[5];,即p是一维的
p是一个”内存入口地址“,后面的5表示p的“关联地址(即关联5个内存单元)"

2).联想 char p[5];
char *q=p;这种用法,
正如1)所说这里p,q都是地址,即指针的实质就是一个地址(附),可以想到(*(*X[3])()) 这个就表示一个地址了,返回一个一维指针

3.分析(*(*X[3]())先进行分解,先用ptr替代正题*x[3](),这样就等效为(* ptr)形式了,结合2)知道 (*ptr)就等效于一个一维指针了,那这你想到什么?显然要用二维指针了,即ptr表示一个二维指针
常见列子:
Int **Dptr;
Int *ptr=*Dptr;//对Dptr进行解运算
(引导: 关于二维指针我久不多说了,直接给个列子
Int a=3;//假设a的地址依然0X00000006
Int **p=(int**)&a;
Int *q=(int*)&a;
//这个时候p和q保存的内容都市0X00000006!),只是表示的类型不同!…..
)
容易推理得到 ptr是一个二维指针了!
再看ptr等价于(*x[3])()了,看类型久知道这里x[3]是一个函数指针,不管,用pFunc替代
即ptr等价于(*pFunc)()了,ptr表示一个二维指针,可以推导出最可能的函数声明
Char** (*pFunc)() ;//char** 是一个返回类型,这里返回一个二维char型指针,函数不带参数列表


附:(何谓地址?啰嗦一下,也帮你复习一下,首先要充分理解p,q是一个地址!(当然也是占用内存的,地址要达到寻址4GB(windows 32位系统),显然要32位,所以一般c++中指针都是32位即四个字节表示一个地址(指针),p,q都是占用内存中的4个字节并且以一个32位整数表示地址!,所以p,q虽然是地址,但实际上可以理解p,q表示的是存储内容!即p,q是一个32位整数,你可能想到,竟然是一个整数,那么为什么一个Int型为什么不可以用一个指针赋值?事实上是可以的!当然直接这样用
int a=3;//假如a在内存中的存储地址是 0X00000006
int *p=&a;//p就表示0X00000006了(p=0X0000006)
Int b=p; //错误,因为p虽然是一个整数,而且数据值是0x00000006,但是类型不匹配!
//即使p值是一个整数(表示一个地址)
Int b=(int)p;//这个是可以的 这个时候b=6!(注意不是3!)
理解到这一点,很自然的猜到,既然p是一个存储内容,那么p是不是也有一个自己的地址,当然,p也是有地址的!int b=(int)&p;这个时候就可以直接通过printf(“%d”,b)输出p的地址的十进制值了
)


这样后 久可以考虑(*(*x[3])())返回的是一个char *p1了


char (*(*x[3])())[5],这个简单的多,用来分析还是可以的,用的时候最好不要搞的这么复杂,竟然后面还跟一个数组【5】, char (*(*x[3])())[5] 用起来的没法用,都没法标注这个数组的起始地址,还要结合x[3]再来一串的解引用,虽然可以定义一些宏来简化,但这个声明的意义我倒觉得不大
有点像这样的用法int **************************p;这么多嵌套的指针,这也是当然可以的,但谁会这么用
东莞某某某 2010-06-10
  • 打赏
  • 举报
回复
这类复杂的声明,解读要根据运算符的优先级及其结合方向。

[],()的运算符都高于* ,结合方向都是自左到右的。

所以对于char (*(*x[3])())[5],分析步骤如下:

1: (*x[3]) x是一个大小为3的数组,数组元素是指针
2: (*x[3])() x是一个大小为3的数组,数组元素是指针,指针指向一个函数
3:(*(*x[3])()) x是一个大小为3的数组,数组元素是指针,指针指向一个函数,该函数返回一个指针
3:char(*(*x[3])())[5] x是一个大小为3的数组,数组元素是指针,指针指向一个函数,该函数返回一个指针,这个指针指向一个大小为5的char数组
z569362161 2010-06-10
  • 打赏
  • 举报
回复
char (*(*x[3])())[5]

x为三个元素的数组,数组元素类型为指针,指针指向一个函数,函数参数类型为空,函数的返回值为指针,指针指向包含5个元素的char 数组
别逗我乐 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 jsjrj01 的回复:]
正解,如果楼主感兴趣,类似的还有,……,可以看下这个帖子
[/Quote]

答案,在19楼,
别逗我乐 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 jixingzhong 的回复:]
char (*(*x[3])())[5]
定义了一个函数指针数组,数组含3个元素;
每个元素为函数指针,指向函数类型为无参数,返回char (*)[5]的数组指针(即指向char[5]的指针)

可以参考 #5:int (*(*e)(int *))[5]; 的分析
[/Quote]

正解,如果楼主感兴趣,类似的还有,……可以看下这个帖子
phpjspasp 2010-06-10
  • 打赏
  • 举报
回复
googe right-left rule
赵4老师 2010-06-10
  • 打赏
  • 举报
回复
VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
cattycat 2010-06-10
  • 打赏
  • 举报
回复
你可以把那个右左法则的记下来,多练习一下。
这个就是函数指针数组,没有参数,返回值char[5]的。
vanchristin 2010-06-10
  • 打赏
  • 举报
回复
char (*(*x[3])())[5]

x为三个元素的数组,数组元素类型为指针,指针指向一个函数,函数参数类型为空,函数的返回值为指针,指针指向包含5个元素的char 数组
yuhuaijun 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 jixingzhong 的回复:]

看这个:

C指针声明解读之左右法则
C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的:
The ……
[/Quote]
太NBA啦。。。
wzywsk 2010-06-10
  • 打赏
  • 举报
回复
2楼的学习了
louyong0571 2010-06-10
  • 打赏
  • 举报
回复
3楼好厉害,我看晕了
jixingzhong 2010-06-10
  • 打赏
  • 举报
回复
char (*(*x[3])())[5]
定义了一个函数指针数组,数组含3个元素;
每个元素为函数指针,指向函数类型为无参数,返回char (*)[5]的数组指针(即指向char[5]的指针)

可以参考 #5:int (*(*e)(int *))[5]; 的分析
jixingzhong 2010-06-10
  • 打赏
  • 举报
回复
看这个:

C指针声明解读之左右法则
C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的:
The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.

这段英文的翻译如下:

右左法则:首先从最里面的圆括号内未定义的标识符开始阅读看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

  总之对声明进行分析,最根本的方法还是按优先级和结合性来类比替换,从那些最基本的声明进行类比,简化,从而进行理解。下面分析几个例子,来具体阐述如何使用这种方法。

#1:int* (*a[5])(int, char*);

  首先看到标识符名a,"[]"优先级大于"*",a与"[5]"先结合。所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,指针指向"int* (int, char*)",很明显,指向的是一个函数,这个函数参数是"int, char*",返回值是"int*"。OK,结束了一个。:)

#2:void (*b[10]) (void (*)());

  b是一个数组,这个数组有10个元素,每一个元素都是一个指针,指针指向一个函数,函数参数是"void (*)()"【注:这也是一个函数指针, 参数为空,返回为void】,返回值是"void"。完毕!

#3:int(*)() (*c)[9];

   c是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是"int(*)()"(也即一个函数指针,指向一个函数,这个函数的参数为空,返回值是int型)。


#4:int (*(*d)[5])(int *);

(*d)------指针;
(*d)[5]------这个指针指向一个数组;
*(*d)[5]------这个数组中每个元素都是指针类型;
int (int *)------ 什么类型的指针?这个类型的。


#5:int (*(*e)(int *))[5];
*e-----向右遇到括号,向左遇到*,说明e是个指针,啥指针呢?
(*e)(int *)------跳出括号向右遇到(int *),说明这个指针是个函数指针,形参为int*, 返回值为何?且听下回分解:);
*(*e)(int *)------返回值为何?向右遇到括号,再向左,喔,遇到*了,那就是返回了一个指针了。啥指针呢? 同样地,下回分解;
(*(*e)(int *))[5]-------向右遇到[],说明那是个指向数组的指针,是啥数组呢?不急,慢慢来;
int (*(*e)(int *))[5]-------向左遇到int,喔,明白了,就是个简单的整型数组。OVER


当然实际当中,当需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性将是一个巨大损害。谁要是写出这样BT的指针声明,那就真是丢rp了,估计会被骂死!。
还是用typedef来对声明逐层分解替换下吧,增强可读性。

例如对于上面的声明:int (*(*func)(int *))[5]; 可以这样分解:
typedef int (*pArr)[5];
typedef pArr (*func)(int *);
这样就容易读得多了啊!


再看看这个啥意思? typedef int (* (* (*FUNC)(int *) )[5] )(int *); ---- 晕了吧。

其实typedef int (* (* (*FUNC)(int *) )[5] )(int *);
等价与下面的:)

typedef int (*PF)(int *);

typedef PF (*PARRAY)[5];

typedef PARRAY (*FUNC)(int *);

(*(void (*)())0)();------->这个呢?
按左右法则:
(void (*)()) -----是一个返回值为void,参数为空的函数指针原型。
  (void (*)())0-----把0强转成一个返回值为void,参数为空的函数指针,指针指向的地址为0.
  *(void (*)())0-----前面加上*表示整个是一个返回值为void的函数的名字
  (*(void (*)())0)()------这当然就是一个函数调用了。

再typedef化简下:
typedef void (*pf)();
(*(pf)0)();
加载更多回复(6)

70,019

社区成员

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

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