读《C Primer Plus》有感2——指向函数指针再举例及答惑
来源:互联网 发布:开淘宝店铺的流程 编辑:程序博客网 时间:2024/05/20 06:09
在上一篇(《指向函数指针举例》)中提到使用函数指针有两种逻辑上不一致的语法规则来实现这样的操作,并以问题的形式提出讨论,这几天看《C Primer Plus》找到了合理的解释。请看下面的例子:
void ToUpper(char *);void ToLower(char *);void (*pf)(char *);char mis[] = "Nina Metier";pf = ToUpper;(*pf)(mis);pf = ToLower;pf(mis);每种方法都似乎有道理。第一种方法:因为pf指向ToUpper函数,*pf就是ToUpper函数,因此表达式(*pf)(mis)与ToUpper(mis)是一样的。从ToUpper和pf的声明中就能看出ToUpper和(*pf)是等级的。第二种方法:因为函数名是一个指针,可以互换地使用指针和函数名,因此pf(mis)和ToLower(mis)一样。从pf的赋值语句就能看出pf与ToLower是等价的。为什么呢?说出来很狗血,是因为C的历史原因。
历史上,贝尔实验室的C和UNIX的开发者采用第一种观点,而Berkeley的UNIX的扩展者采用了第二种观点。K&R C不允许第二种形式。但是为了保持与现代代码的兼容性,ANSI C把二者座位等价形式全部接受。笔者装了这么久的B完全是因为今天上课前还不知道这个原因,而且这个问题一直困扰着我,石头终落地,但略感失望。
为了不这么狗血就结束了,这里再举一个使用函数指针的例子。
#include <stdio.h>#include <string.h>#include <ctype.h>char ShowMenu(void); void EatLine(void); //读至行末 void Show(void (*fp)(char *), char *str);void ToUpper(char *); //把字符串转换为大写void ToLower(char *); //把字符串转换为小写void Transpose(char *); //大小写转置void Dummy(char *); //不改变字符串int main(){char line[81];char copy[81];char choice;void (*pfun)(char *); //指向一个函数,该函数接受一个char *参数,并且没有返回值puts("Enter a string(empty line to quit):");while(gets(line) != NULL && line[0] != '\0'){while((choice = ShowMenu()) != 'n'){switch(choice) //switch语句用来设置指针{case 'u':pfun = ToUpper;break;case 'l':pfun = ToLower;break;case 't':pfun = Transpose;break;case 'o':pfun = Dummy;break;}strcpy(copy, line); //为Show()制作一份字符串拷贝Show(pfun, copy); //使用用户选择的函数}puts("Enter a string(empty line to quit):");}puts("Bye!");return 0;}char ShowMenu(void){char ans;puts("Enter menu choice:");puts("u)UpperCase l)LowerCase");puts("t)Transposed Case o)Original Case");puts("n)Next String");ans = getchar(); //获取用户的响应ans = tolower(ans); //转换大小写EatLine(); //剔除行中剩余部分while(strchr("ulton", ans) == NULL){puts("Please enter a u, l, t, o, n:");ans = tolower(getchar());EatLine();}return ans;}void EatLine(void){while(getchar() != '\n')continue;}void ToUpper(char *str){while(*str){*str = (toupper(*str));str++;}}void ToLower(char *str){while(*str){*str = (tolower(*str));str++;}}void Transpose(char *str){while(*str){if(islower(*str))*str = toupper(*str);else if(isupper(*str))*str = tolower(*str);str++;}}void Dummy(char *str){}void Show(void (*fp)(char *), char *str){(*fp)(str); //把用户选择的函数作用于str puts(str); //输出str}
再次提起注意,函数Toupper(),ToLower(),Transpose(),Dummy()都是相同类型的,因此4个函数都可以赋值给指针pfun。这个程序用pfun作为show()的参数,但是也可以直接将4个函数名称中的任一个作为参数,就像Show(Transpose, copy)一样。
至于菜单处理,函数ShowMenu()给出了几种技术。首先,代码:
ans = getchar(); //获取用户的响应ans = tolower(ans); //转换大小写和:
ans = tolower(getchar());给出两种方法。这两种方法都可以将用户的输入转换为一种大小写形式,这样就不用检查'u',又检查'U'等等。
函数EatLine()剔除输入行的剩余部分,这在两个方面很有用。第一,要输入一个选择,用户会键入一个字母,然后再按下回车键,这将产生一个换行符。如果不事先去掉这个换行符,它将作为下一个用户响应被读入。第二,假设用户键入整个单词uppercase而不是u作为响应,如果没有EatLine()函数,程序会把单词uppercase的每个字符当作一个单独的响应。有了EatLine(),程序只会处理u,并丢弃掉输入行的剩余部分。
其次,ShowMenu()函数是设计用来只将正确的选择返回给主函数。为了完成该任务,程序使用了头文件string.h中的标准库函数strchr():
while(strchr("ulton", ans) == NULL)这个函数在字符串"ulton"中找出字符ans首次出现的位置,并返回一个指向该位置的指针。如果没有找到这个字符,函数返回空指针。因此上面这个while循环判断条件和一下判断条件的作用相同,但使用起来更方便:
while(ans != 'n' && ans != 'l' && ans != 't' && ans != 'o' && ans != 'n')
需要检查的选择越多,使用strchr()就会越方便。
希望通过此篇及上一篇讲解中的两个稍大的例子能够到达廓清函数指针中一些概念的目的。这里特此感谢《C Primer Plus》及该书的作者Stephen Prata。
- 读《C Primer Plus》有感2——指向函数指针再举例及答惑
- C primer plus:指向函数的指针
- 指向函数指针举例
- 【C++】《C++ Primer Plus》笔记(2)——指针
- C Primer Plus学习 四十五 指向结构的指针
- 指向函数的指针(摘自C++Primer
- 细嚼慢咽C++primer(3)——引用形参,内联函数,重载函数,指向函数的指针
- 指向函数的指针(自C++Primer )
- 学习C Primer Plus前四章有感
- C/C++——指向函数的指针和指向函数的指针的数组
- C Primer Plus学习 二十 函数、数组和指针
- C Primer Plus学习 五十 函数和指针
- 字符串函数要点总结——《C Primer Plus》笔记系列2
- C Primer Plus(九) 函数
- C++:C++primer plus 指针问题理解
- c++primer plus复合类型之指针2
- C语言——指向函数的指针
- C++ Primer 指向成员函数的指针
- poj1002 Output Limit Exceeded
- Thinking in java(四)-i/o(1)
- HTTP请求&响应字段
- 关于stm32的GPIO复用
- 标志符的规则(规则是必须遵守的,否则编译器不能通过)
- 读《C Primer Plus》有感2——指向函数指针再举例及答惑
- Struts2自定义简单标签
- ubuntu12.04 gedit 打开 txt 文件乱码
- 微软发布 WP8 的 Skype 预览版
- 仅剩三天 Gmail 就不再支持IE8浏览器了
- JPEG 图片格式我们要用到 2030 年
- 狂欢光棍节:电商鏖战 网友血拼
- 批处理文件bat 语法备忘
- linux下Snort系统配置文档