在学习C语言的过程中,会先遇到数组指针,指针数组此类的概念。这些概念实在是晦涩难懂,在进一步学习之后,你会发现更加恐怖的还有各种各样的声明,比如:
char * const *(*next)();
那么这些声明到底是什么意思呢?
1理解C语言声明的优先级规则
序号 | 说明 |
---|---|
A | 声明从他的名字开始读取,然后按照优先级顺序依次读取 |
B | 优先级从高到低依次是:a、b、c |
a | 声明中被括号括起来的那部分 |
b | 后缀操作符:括号表示这是一个函数,方括号表示这是一个数组 |
c | 前缀操作符星号*表示:指向…的指针 |
C | 如果const和(或)volatile关键字的后面紧跟说明符(如int,long等),那么它的作用于类型说明,在其他情况下,const和(或)volatile关键字作用于它左边紧邻的指针星号。 |
用上表对声明char * const *(*next)();进行分析:
适用规则 | 解释 |
---|---|
A | 首先,看变量名“next”,并注意到它直接被括号括住 |
a | 所以,先把括号的东西作为一个整体,得出“next是指向…的指针” |
B | 然后考虑括号外面的东西,在星号前缀和括号后缀之间做出选择 |
b | b规则告诉我们优先级较高的是右边的函数括号,所以得出“next是一个函数指针,指向一个返回…的函数” |
c | 然后处理前缀“*”,得出指针所指的内容 |
C | 最后,把“char * const”解释为指向字符的常亮指针 |
综上:把上诉分析结果概括起来,这个声明表示“next是一个指针,指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针。
如果你觉得分析太麻烦,这里有一个超级方便的方法,就一个C程序,运行后直接输入就能得出答案,实例如下:
输入上面的实例:char * const *(*next)();得到下图结果:
同时也能输入一个简单的如:int *fun(); 这个就很简单表示:一个函数,返回一个指向int的指针。
下面贴出这份程序的代码:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag { IDENTIFIER, QUALIFIER, TYPE };
struct token
{
char type;
char string[MAXTOKENLEN];
};
int top = -1;
struct token stack[MAXTOKENS];
struct token This;
#define pop stack[top--]
#define push(s) stack[++top] = s
/* figure out the identifier type */
enum type_tag classify_string(void)
{
char *s = This.string;
if (!strcmp(s, "const"))
{
strcpy(s, "read-only");
return QUALIFIER;
}
if (!strcmp(s, "volatile"))
return QUALIFIER;
if (!strcmp(s, "void"))
return TYPE;
if (!strcmp(s, "char"))
return TYPE;
if (!strcmp(s, "signed"))
return TYPE;
if (!strcmp(s, "unsigned"))
return TYPE;
if (!strcmp(s, "short"))
return TYPE;
if (!strcmp(s, "int"))
return TYPE;
if (!strcmp(s, "long"))
return TYPE;
if (!strcmp(s, "float"))
return TYPE;
if (!strcmp(s, "double"))
return TYPE;
if (!strcmp(s, "struct"))
return TYPE;
if (!strcmp(s, "union"))
return TYPE;
if (!strcmp(s, "enum"))
return TYPE;
return IDENTIFIER;
}
/* read next token into "this" */
void gettoken(void)
{
char *p = This.string;
/* read past any space */
while ((*p = getchar()) == ' ');
if (isalnum(*p))
{
/* it starts with A-Z, 0-9 read in identifier */
while (isalnum(*++p = getchar()));
ungetc(*p, stdin);
*p = '\0';
This.type = classify_string();
return;
}
if (*p == '*')
{
strcpy(This.string, "pointer to");
This.type = '*';
return;
}
This.string[1] = '\0';
This.type = *p;
return;
}
/* the piece of code that understandeth all parsing */
void read_to_first_identifier()
{
gettoken();
while (This.type != IDENTIFIER )
{
push(This);
gettoken();
}
printf("%s is ", This.string);
gettoken();
}
void deal_with_arrays()
{
while (This.type == '[')
{
printf("array ");
gettoken(); /* a number or ']' */
if (isdigit(This.string[0]))
{
printf("0..%d ", atoi(This.string) - 1);
gettoken(); /* read the ']' */
}
gettoken(); /* read next past the ']' */
printf("of ");
}
}
void deal_with_function_args()
{
while (This.type != ')')
{
gettoken();
}
gettoken();
printf("function returning ");
}
void deal_with_pointers()
{
while (stack[top].type == '*')
{
printf("%s ", pop.string);
}
}
void deal_with_declarator()
{
/* deal with possible array/function following identifier */
switch (This.type)
{
case '[' : deal_with_arrays(); break;
case '(' : deal_with_function_args();
}
deal_with_pointers();
/* process tokens that we stacked while reading identifier */
while (top >= 0)
{
if (stack[top].type == '(')
{
pop;
gettoken(); /* read past ')' */
deal_with_declarator();
}
else
{
printf("%s ", pop.string);
}
}
}
int main()
{
/* put tokens on stack until we reach identifier */
read_to_first_identifier();
deal_with_declarator();
printf("\n");
return 0;
}
直接粘贴复制就能使用!!