C專家程式設計(2)
阿新 • • 發佈:2021-01-07
理解宣告(P64-66)
面對一些複雜的宣告形式,可以通過以下兩種方法來理解,分別是優先順序法和圖示法。下面以書上的
char * const *(*next)();
為例,分別進行分析。
- 優先順序法(P64)
適用規則 | 解釋 |
---|---|
A | 首先,看變數名next ,並注意到它直接被括號所括住 |
B.1 | 所以先把括號裡的東西作為一個整體,得出“next是一個指向...的指標” |
B | 然後考慮括號外面的東西,在星號字首和括號字尾之間作出選擇 |
B.2 | 規則告訴我們優先順序較高的是右邊的函式括號,所以得出“next是一個函式指標,指向一個返回...的函式" |
B.3 | 然後,處理字首* |
C | 最後,把char * const 解釋為指向字元的常量指標 |
這個宣告表示“next是一個指標,它指向一個函式,該函式返回另一個指標,該指標指向一個型別為 char的常量指標”
- 圖表法(P65)
signal函式宣告的解析
首先來看一下signal的宣告形式:
void (*signal(int sig, void(*func)(int)))(int);
簡化後為void(*signal(x,xx))(int)
,表明signal函式有兩個引數(x和xx),並返回一個函式指標,指向的函式接受int型別的引數並返回void。而xx引數表示的函式與signal本身的形式一樣。
因此可以使用typedef void(*pf)(int);
來簡化函式的宣告,簡化後為:pf signal(int, pf);
練習
char *(* c[10])(int **p); // 答案在文章末尾
程式設計挑戰
#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXTOKENLEN (256) #define MAXTOKENS (16) #define TOTAL_NUMS(array) (sizeof(array) / sizeof(array[0])) char *STR_TYPE[] = {"char", "short", "int", "long", "float", "double", "signed", "unsigned", "void", "struct", "union", "enum"}; char *STR_QUALIFIER[] = {"const", "volatile"}; typedef enum { TYPE, /* 型別 */ QUALIFIER, /* 限定符 */ INDENTIFIER /* 識別符號 */ } type_t; struct token { char type; char string[MAXTOKENLEN]; }; struct token stack[MAXTOKENS]; /* 儲存第一個標識之前的所有標記 */ struct token this; /* 儲存剛讀入的標記 */ char next_string[MAXTOKENLEN]; int top = -1; /* 棧頂 */ // 壓棧 static void push(struct token t) { stack[++top] = t; } // 出棧 static struct token pop(void) { return stack[top--]; } // 字串分類,獲取當前標識的型別 static type_t classify_string(void) { int i = 0; char *s = this.string; for (i = 0; i < (int)TOTAL_NUMS(STR_TYPE); i++) { if (strcmp(s, STR_TYPE[i]) == 0) { return TYPE; } } for (i = 0; i < (int)TOTAL_NUMS(STR_QUALIFIER); i++) { if (strcmp(s, STR_QUALIFIER[i]) == 0) { return QUALIFIER; } } return INDENTIFIER; } // 獲取標記 static void gettoken(void) { char *p = next_string; /* 取新的一段字串 */ while (*p == ' ') { /* 忽略空格 */ p++; } strcpy(this.string, p); /* 字串賦值 */ p = this.string; if (isalnum(*p)) { /* 如果是字母數字組合 */ while (isalnum(*++p)) ; /* 直到讀取到其他字元 */ strcpy(next_string, p); /* 修改字串 */ *p = '\0'; /* 加上字串結束符 */ this.type = (char)classify_string(); /* 判斷型別 */ } else if (*p != '\0') { /* 單字元標記 */ strcpy(next_string, p + 1); /* 修改字串 */ this.type = *p; this.string[1] = '\0'; } } // 讀至第一個識別符號 static void read_to_first_identifier(void) { gettoken(); while (this.type != INDENTIFIER) /* 不是識別符號,將標記入棧 */ { push(this); gettoken(); /* 取下一個標記 */ } printf("Identifier \"%s\" is ", this.string); gettoken(); } /*************** 解析程式 ***************************************/ // 處理函式引數 static void deal_with_function_args(void) { while (this.type != ')') { gettoken(); } gettoken(); printf("function returning "); } // 處理函式陣列 static void deal_with_arrays(void) { while (this.type == '[') /* 繼續讀取數字或']' */ { printf("array "); gettoken(); if (isdigit(this.string[0])) { /* 如果是數字 */ printf("0..%d ", atoi(this.string) - 1); /* 列印陣列大小 */ gettoken(); /* 獲取']' */ } gettoken(); printf("of "); } } // 處理任何指標 static void deal_with_any_pointers(void) { while (stack[top].type == '*') { pop(); printf("pointer to "); } } // 處理宣告器 static void deal_with_declarator(void) { if (this.type == '[') { deal_with_arrays(); } else if (this.type == '(') { deal_with_function_args(); } deal_with_any_pointers(); while (top > -1) { if (stack[top].type == '(') { pop(); gettoken(); deal_with_declarator(); } else { deal_with_any_pointers(); printf("%s ", pop().string); } } } int main(void) { // 測試用例參考 https://blog.csdn.net/yyhustim/article/details/9612185 char *str[] = {"char * const *(*next)()", "char *(* c[10])(int **p)", "const int * grape", "int const * grape", "int * const grape", "int sum(int a, int b)", "char (*(*x())[])()", "char (*(*x[3])())[5]"}; for (int i = 0; i < (int)TOTAL_NUMS(str); i++) { printf("== %s\n", str[i]); strcpy(next_string, str[i]); read_to_first_identifier(); deal_with_declarator(); printf("\n\n"); top = -1; } return 0; }
答案
執行上面的程式,給出的結果為:
Identifier "c" is array 0..9 of pointer to function returning pointer to char
即c是一個大小為10的陣列,其元素型別是函式指標,指向的函式的返回值是一個指向char的指標。