1.1文学程序

文学程序(literate program):接口及其实现的代码与对其进行解释的正文交织在一起。文学程序由英文正文和带标签的程序代码块组成。例如,

1 〈compute x * y〉≡2 sum = 0;3 for (i = 0; i < n; i++)4 sum += x[i]*y[i];

定义了名为〈compute x * y〉的代码块,其代码计算了数组x和y的点积。在另一个代码块中使用该代码块时,直接引用即可:

1 〈function dotproduct〉≡2 int dotProduct(int x[], int y[], intn) {3 inti, sum;4

5 〈compute x o y〉6 returnsum;7 }

文学程序可以按各个小片段的形式给出,并附以完备的文档。英文正文包含了传统的程序注释,这些并不受程序设计语言的注释规范的限制。

下面是文学编程系统的另一个特性,她有助于逐点对程序进行描述;下面以一个检测输入中相邻的相同单词的double程序,作为文学程序的例子:

先从定义根代码块来实现double,该代码块将使用对应于程序各个组件的其他代码块:

1 〈double.c 3〉≡2 〈includes 4〉3 〈data 4〉4 〈prototypes 4〉5 〈functions 3〉

main函数处理double的参数。它会打开各个文件,并调用doubleword扫描文件:

1 〈functions 3〉≡2 int main(int argc, char *argv[]) {3 inti;4

5 for (i = 1; i < argc; i++) {6 FILE *fp = fopen(argv[i], "r");7 if (fp ==NULL) {8 fprintf(stderr, "%s: can't open '%s' (%s)\n",9 argv[0], argv[i], strerror(errno));10 returnEXIT_FAILURE;11 } else{12 doubleword(argv[i], fp);13 fclose(fp);14 }15 }16 if (argc == 1) doubleword(NULL, stdin);17 returnEXIT_SUCCESS;18 }19

20 〈includes 4〉≡21 #include

22 #include

23 #include

getword从打开的文件读取下一个单词,复制到buf [0..size  1]中,并返回1;在到达文件末尾时该函数返回0。

1 functions 3〉+≡2 int getword(FILE *fp, char *buf, intsize) {3 intc;4

5 c =getc(fp);6 〈scan forward to a nonspace character or EOF 5〉7 〈copy the word into buf[0..size-1] 5〉8 if (c !=EOF)9 ungetc(c, fp);10 return〈found a word? 5〉;11 }12

13 〈prototypes 4〉≡14 int getword(FILE *, char *, int);

getword除了从输入获取下一个单词之外,每当遇到一个换行字符时都对linenum加1。doubleword输出时将使用linenum。

1 〈data 4〉≡2 intlinenum;3

4 〈scan forward to a nonspace character or EOF 5〉≡5 for ( ; c != EOF && isspace(c); c =getc(fp))6 if (c == '\n')7 linenum++;8

9 〈includes 4〉+≡10 #include

size的值限制了getword所能存储的单词的长度,getword函数会丢弃过多的字符并将大写字母转换为小写:

1 〈copy the word into buf[0..size-1] 5〉≡2 {3 int i = 0;4 for ( ; c != EOF && !isspace(c); c =getc(fp))5 if (i < size - 1)6 buf[i++] =tolower(c);7 if (i

剩下的代码逻辑是,如果buf中保存了一个单词则返回1,否则返回0:

1 〈found a word? 5〉≡2 buf[0] != '\0'

doubleword读取各个单词,并将其与前一个单词比较,发现重复时输出。它只查看以字母开头的单词:

1 〈functions 3〉+≡2 void doubleword(char *name, FILE *fp) {3 char prev[128], word[128];4

5 linenum = 1;6 prev[0] = '\0';7 while (getword(fp, word, sizeof(word)) {8 if (isalpha(word[0]) && strcmp(prev, word)==0)9 〈word is a duplicate 6〉10 strcpy(prev, word);11 }12 }13 〈prototypes 4〉+≡14

15 void doubleword(char *, FILE *);16

17 〈includes 4〉+≡18 #include

输出是很容易的,但仅当name不为NULL时才输出文件名及后接的冒号:

1 〈word is a duplicate 6〉≡2 {3 if(name)4 printf("%s:", name);5 printf("%d: %s\n", linenum, word);6 }

总结:整个程序的设计符合学习C语言经常提的:自顶向下,逐步细化,模块化!

1.2程序设计风格

上例double说明了本书中程序所使用的风格惯例。一般来说,较长且富于语义的名称用于全局变量和例程,而数学符号般的短名称则用于局部变量。

代码中几乎没有注释,因为围绕对应代码块的正文代替了注释。本书将效法C程序设计方面的典范,最低限度地使用注释。

库函数strcpy将一个字符串复制到另一个字符串中并返回目标字符串,对该函数的不同实现就说明了"地道的C语言"和新手C程序员编写的代码之间的差别,后一种代码通常使用数组:

1 char *strcpy(char dst[], const charsrc[]) {2 inti;3

4 for (i = 0; src[i] != '\0'; i++)5 dst[i] =src[i];6 dst[i] = '\0';7 returndst;8 }

"地道"的版本则使用指针:

1 char *strcpy(char *dst, const char *src) {2 char *s =dst;3

4 while (*dst++ = *src++)5 ;6 returns;7 }

这两个版本都是strcpy的合理实现。指针版本使用通常的惯用法将赋值、指针递增和测试赋值操作的结果合并为单一的赋值表达式。它还修改了其参数dst和src,

这在C语言中是可接受的,因为所有参数都是传值的,实际上参数只不过是已初始化的局部变量。

1.3 效率

程序员似乎被效率问题困扰着。他们可能花费数小时来微调代码,使之运行得更快。遗憾的是,大部分这种工作都是无用功。当猜测程序的运行时间花费在何处时,程序员的直觉非常糟糕。

微调程序是为了使之更快,但通常总是会使之更大、更难理解、更可能包含错误。除非对执行时间的测量表明程序太慢,否则这样的微调没有意义。程序只需要足够快即可,不一定要尽可能快。

如果I/O占了程序运行时间的60%,在搜索例程中节省1%是无意义的。

微调:

微调通常会引入错误。最快崩溃的程序绝非胜者。可靠性比效率更重要;与交付足够快的可靠软件相比,交付快速但会崩溃的软件,从长远看来代价更高。

微调经常在错误的层次上进行。快速算法的直接简明的实现,比慢速算法的手工微调实现要好得多。例如,减少线性查找的内层循环的指令数,注定不如直接使用二分查找。

微调无法修复低劣的设计。如果程序到处都慢,这种低效很可能是设计导致的。当基于编写得很糟糕或不精确的问题说明给出设计时,或者根本就没有总体设计时,就会发生这种令人遗憾的情况。

一些C程序员在寻求提高效率的途径时,大量使用宏和条件编译。只要有可能,本书将避免使用这两种方法。使用宏来避免函数调用基本上是不必要的。仅当客观的 测量结果表明有问题的调用的开销大大超出其余代码的运行时间时,使用宏才有意义。操作I/O是较适宜采用宏的少数情况之一。例如,标准的I/O函数 getc、putc、getchar和putchar通常实现为宏。

条件编译通常用于配置特定平台或环境的代码,或者用于代码调试的启用/禁用。这些问题是实际存在的,但条件编译通常只是解决问题的较为容易的方法,而且总会使代码更难于阅读。如果应用程序必须在编译时配置,与C语言的条件编译工具相比,版本控制工具更擅长完成该工作。

用C语言编程实现接口COM组件,把《C语言接口与实现》读薄之第一章:引言相关推荐

  1. 8051单片机c语言编程模板,完美的8051单片机C语言编程模板.doc

    完美的8051单片机C语言编程模板.doc <8051单片机C语言编程模板> [程序开始处的程序说明] /***************************************** ...

  2. 有没有c 或c语言的短期培训学校,根河学c语言编程,根河学c语言编程的学校,根河学c语言编程报个培训班怎么样...

    根河学c语言编程,根河学c语言编程的学校,根河学c语言编程报个培训班怎么样 首页 > 软件 > 根河学c语言编程 作者:镀金池   发布时间:2017-11-30 11:02 另外,尽早调 ...

  3. .net调用c++方法时如何释放c++中分配的内存_C/C++编程笔记:C语言编程知识要点总结!大一C语言知识点(全)...

    一.C语言程序的构成 与C++.Java相比,C语言其实很简单,但却非常重要.因为它是C++.Java的基础.不把C语言基础打扎实,很难成为程序员高手. 1.C语言的结构 先通过一个简单的例子,把C语 ...

  4. 两个变量实现查找坏环c语言,C/C++编程笔记:C语言编程知识要点总结!大一C语言知识点(全)...

    程序员无言 2020-07-07 一.C语言程序的构成 与C++.Java相比,C语言其实很简单,但却非常重要.因为它是C++.Java的基础.不把C语言基础打扎实,很难成为程序员高手. 1.C语言的 ...

  5. c语言 方程改main的值_C语言编程笔记丨编写第一个C语言程序hello world,我教你哇...

    如果用C语言输出:Hello,world!,该如何编写程序? **代码如下:** #include//包含标准库的信息 main()//定义名为main的函数,不接受参数值 {//main函数的语句都 ...

  6. 《R语言编程艺术》——1.4 R语言中一些重要的数据结构

    1.4 R语言中一些重要的数据结构 R有多种数据结构.本节将简单介绍几种常用的数据结构,使读者在深入细节之前先对R语言有个大概的认识.这样,读者至少可以开始尝试一些很有意义的例子,即使这些例子背后更多 ...

  7. c语言编程 遍历字符串,请教大家一个C语言面试的编程题目 C语言:循环执行让用户输入一串字符串,如123456789......

    导航:网站首页 > 请教大家一个C语言面试的编程题目 C语言:循环执行让用户输入一串字符串,如123456789... 请教大家一个C语言面试的编程题目 C语言:循环执行让用户输入一串字符串,如 ...

  8. c语言编程题改错题怎么改,c语言编程改错题.doc

    c语言编程改错题 [程序功能]对N行N列二维数组的每一行排序,偶数行(0当作偶数)由小到大排序,奇数行由大到小排序. [含有错误的源程序] #include #define N 4 void swap ...

  9. 沈阳工业大学c语言编程题,金融工程专业《C语言程序设计》启发式教学探讨

    一.引言 C语言是一门高级程序设计语言,掌握C语言不仅有利于提高学生的思维能力,而且有利于培养学生的编程能力,对学习其他计算机语言课程具有很大的帮助.因此,<C语言程序设计>既是计算机各类 ...

  10. c语言编程规范总结,【技术小记 | C语言】C 语言编程规范

    image 欢迎大家访问我的个人博客:吴佳轶 | WuJiaYi,第一时间获取最新的文章. 规范制定说明 本套C语言编程规范为提高代码质量.便于维护.协同编码.可移植等特点而编写.要求所有参与编码人员 ...

最新文章

  1. 【分布式事务系列九】聊聊分布式事务
  2. 零基础学python全彩版实战答案-零基础学Python(全彩版)
  3. BACKUP PENDING状态的解除
  4. 教师查询系统C语言,教师管理系统c语言版
  5. php+compose+使用,docker使用 docker-compose配置PHP环境(php+nginx+mysql)及启动
  6. 基于SSM的员工管理系统设计(含源文件)
  7. linux ntp时间服务器配置
  8. php7 curl开源库,7个适用于PHP的最佳Curl包装器库
  9. app嵌入jsp页面的项目工作量_好程序员Java学习路线分享jsp为什么用的不多了
  10. 循环语句在c语言中的作用是什么,C语言中循环语句的使用
  11. javascript 怎样才能确定参数变量的个数呢?
  12. VMware15下安装Ubuntu18.04
  13. 五种MATLAB画圆方式程序
  14. 用于交通数据预测的深度时空3维卷积神经网络
  15. 安卓 USB 无权限请求权限崩溃 UsbManager.requestPermission()空指针异常
  16. SpringBoot 集成支付宝转账(提现功能)
  17. MANIFEST.MF是个什么?
  18. IE系列兼容性hack大全
  19. (二)树莓派系列教程:树莓派4B手动连接wifi,远程控制。命令行界面、桌面界面
  20. JAVA正则判断是否输入为QQ邮箱、手机号码

热门文章

  1. 专栏介绍:全国青少年信息学奥林匹克初赛真题(1995~2021)
  2. 色情网站的光棍节“福利”:加密式挂马玩转流氓推广
  3. JustNews WordPress 强悍插件不到一个月权重4开源无加密无需数据库无授权关键词自动扩充文章自动生成适合所有cms
  4. 吃鸡手游服务器响应超时闪退,我玩吃鸡为什么一直连接超时 | 手游网游页游攻略大全...
  5. SV学习笔记—包package的使用
  6. 易车及网购车平台的发展历程
  7. 网络通信协议的发展及socket/netty理解
  8. 能用机器完成的,千万别堆工作量|持续集成中的性能自动化测试 1
  9. 利用Selenium爬取煎蛋网妹纸图原来是这么简单!!!
  10. linux默认开启sudo_Linux 下使用 sudo 进行赋权