《程序特征》第一章:绪论

1.程序是什么

程序是什么?程序在1940年代第二次世界大战中因为用计算机代替物理计算而出现,在80年的发展中,众多的计算机软件科学家给予了不同的定义。

1.1传统定义

程序是“数学表达式”。最早的程序是科学计算程序。由于量子力学的出现,在牛顿经典力学的基础上,物理学出现了新的分支,原子物理学,固体物理学,众所周知的晶体管是固体物理学发展的结果。新的学科需要很多的计算,决定了程序的数学性质。

程序的三种变量是程序的基础,有数字变量,字符变量和布尔变量。三种变量又组成表达式,布尔表达式的值是{true,false},然后表达式组成程序的语句。这种构成方式与数学的项,因式和计算表达式类似。

程序的语句有赋值语句(assignment),x=f(a,b,c),f(a,b,c)是表达式或者数学函数sinx,cosx(库函数),并且x是变量而a,b,c是常量,条件语句(conditional statement),if 布尔表达式B then C1 else C2,并且C1和C2是程序的语句,和循环语句(loop statement),while B {C1;}(C语言表示方法),布尔表达式B是循环实现迭代的条件。

程序的两个语句C1和C2,用C1;C2表示,称为程序的规格(specification)。条件语句的规格表示:

if B -> C1|C2,  B为真,条件成立,则选择C1;B为假,选择C2。有用菱形代替“|”的表示方法。

循环语句的规格表示:

while B * C, B为真,则循环语句开始下一个迭代,否则循环结束到程序的下一个语句。*表示循环,与文法的闭包(closure)用法一样。

规格是数学思想,用严谨(rigorous)的方法表示程序。程序的数学性质代表人物有高德纳,霍尔和。高德纳是加州理工学院数学系的学生,开始写他的名著《计算机程序设计的艺术》,他把数学思想引导到计算机程序设计中,他认为不同学科的区别在科学思维的不同。在他看到巴克斯-诺尔范式以后,就认为数学的严谨能用在计算机程序设计中,因此他发明了LR(k)分析文法。计算机高级语言有很多,结构语言C,面向对象技术C++,函数式语言与逻辑式语言Lisp和Prolog,高级语言的困难不仅在语法的设计,更重要的是语言的编译器,LR(k)文法将程序语句的语法结构找到,判断语法是否正确。并且高德纳发明了属性文法,因此编译器不再困难。LR分析文法的精确仍然表示程序的数学性质。高德纳另一个更重要的发明是算法分析。他在加州理工,计算机公司和斯坦福大学工作,将高等数学的级数与概率论引到分析程序或算法的效率上,称为时间复杂度,区分一个问题的不同实现程序的性能的好坏。例如,一个程序有三层的循环语句,

   while(){ /*第一层*/

      for(){/*第二层*/

          while(){...}/*第三层*/

     }}

此程序的时间复杂度应是n的三次方O(n#3),n是输入数据的长度或大小。然而,若有一个程序能解决相同问题,只有一个两层的循环语句,因此时间复杂度是O(n#2),效率更好。因此,“高德纳教给我们区分不过如此和极其优秀。”

高德纳的学生陶尔扬,用Ackermann函数表示算法复杂度,Ackermann函数增长很快,反函数就增长很慢。在会计学的平摊amortization方法引到算法分析后,发明了动态数据结构的摊还分析,并且与他的学生斯里特使用物理的势函数表示算法复杂度。

霍尔是英国人,他在计算机公司工作时,发现程序在行数变多时,出现的错误数量是灾难。因此,他离开公司到英国的大学任教,后来去了剑桥大学。霍尔在计算机编程方面的重要贡献是霍尔逻辑,{P}C{R},P和R是数学表达式,表示语句C在执行前应遵守的条件和执行后的结果,称为断言(assertion)。霍尔逻辑用来实现程序语句的正确性证明,在程序分析和设计中得到广泛应用,例如程序验证(program verification)。

计算机程序设计经过了80年的发展,高级语言,编译器,商业软件,数据库,面向对象技术,分时操作系统,高性能计算机程序设计,并行程序设计,多核多线程,Windows微内核模式,Client/Server模式,开始处理复杂数据结构线性表,栈与队列,树与二叉树,图与邻接表,二叉搜索树,优先队列(堆),类与对象,动态树,map-reduce。数据结构的基本操作,例如队列的出队和入队操作,并不是数学表达式,高级语言的系统函数,例如strcpy函数仍然不是数学计算,因此计算机程序向多个方向发展,增加了字符处理函数,数据结构操作,类的封装与接口,并发编程,模式设计与组件,大数据等功能,因此程序的数学特征不再是一统天下。

1.2  数理逻辑定义

程序是逻辑。埃德蒙.克拉克的不动点分析,与模态逻辑(modal logic)。克拉克的逻辑发展到SAT求解机。模态逻辑不是逻辑式程序设计,可以用在各种程序中。

2.程序模式

2.1《代码阅读》第二章 基本编程元素

一、一个完整的程序

echo是UNIX系统上一个简单有用的程序,用在标准输出上(通常为屏幕)打印(显示)它的参数。

计算机的标准输入,标准输出,错误显示在程序设计中是stdin,stdout,stderr。”打印其参数“的意义是,echo向用户展示信息,是UNIX操作系统的一个命令,在命令行输入echo "this moment",将显示this moment,,因此“this moment"是echo的参数。

echo源程序取自NetBSD的upgrade脚本。库函数保存在头文件中,C和C++的程序应包含头文件,才能正确使用库函数,如同库函数是programmer自己编写的一样。C、C++与Java程序从main函数(在Java中叫方法)开始执行,windows、Java applet和serlet host、掌上电脑以及嵌入式系统,可能会使用另外的函数作为程序的入口,例如WinMain或init。

在C和C++程序中,main函数的两个参数argc与argv,将特定的命令行参数从操作系统传递到程序,变量argc制定参数的数量,argv是字符串数组,包含所有实参,程序名称(echo)位置为0,以NULL元素结束。C与C++程序中,典型的main函数定义为

int

main(int argc,char **argv)

而相应的Java类定义为

public static void main(string args[]){

program1.  UNIX中的echo源程序

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

int main__P((int,char *[])); /*在函数声明中使用宏是为了向pre-ANSI隐藏参数*/

int

main(argc,argv)

    int argc;

    char *argv[];

{

    int nfiag;

    if(*++argv && !strcmp(*argv,  "-n")){/*-n不是UNIX系统的换行符*/

         ++argv; 

         nflag=1;/* 参数指定了-n*/

   }

   else

          nflag=0;

   while (*argv) {   /* 循环条件,将处理的参数不为空        */

        (void)printf("&s",*argv);

        if(*++argv)   /* 若下一个字符串不为空*/

             putchar(' ');  /*输出一个空格分隔符*/

   }

   if(!nflag)  /* 若没有指定-n,输出换行符*/

         putchar('\n');

    exit(0);

程序阅读:

1.程序的库函数有printf()和putchar(),显示字符串或者一个字符显示屏幕上。不仅能在操作系统的命令行输入字符串,UNIX系统的C程序中用对应的scanf()和getchar(),从键盘接收一个字符串或者一个字符。

2.程序用到一个复杂数据结构,指针数组*argv[],argv[i]是一个指针,指向一个字符串。因此,当编程时,对多个字符串进行处理,而且不等长,常用到指针数组实现存储和创立这些字符串。eg.dez  

                    char *mstring[3]={“this”,“moment”,"\0"};

                     char *p=mstring[0];/*p指向mstring的第一个字符串*/

                   while ((*p)!="\0"){

                           printf("%s",*p);

                            p++;

                  }

                 exit(0);

3.argv的应用

echo与getopt并不兼容,因此指定输出不以换行符结束的-n,则-n参数需要程序员自己编写代码处理。首先,程序将argv移动到第一个位置argv[1],而不是argv[0]="echo",检验argv[1]参数是否存在,是否=-n,用strcmp()比较。在if的布尔表达式中,使用B1&&B2,则当B1=0时,系统将不再对B2求值。

4.库函数的返回值

printf()返回实际显示的字符的数量,转换为void是为了忽略该结果。putchar()在写入字符失败后返回EOF。所有的输出函数,在程序的标准输出stdout被重定向到一个文件时,可能由于各种原因而失败。

(1)存储输出的设备没有剩余空间。可能是输出缓冲区。

(2)设备上用户的空间配额可能已经耗尽。输出缓冲区满。

(3)(进程)试图向文件写入超过边界限制的数据。例如,超过系统文件长度。

(4)输出设备上可能发生硬件错误。

(5)一个文件的描述符或与标准输出相关联的流无法有效写入。写到标准输出的流无法写入文件。

不检查输出操作的结果,可能会导致程序悄然失败,在没有示警的情况下失去输出。

strcmp()的返回值,若两个字符串相等,则返回0(false)。

5.变量初始化

使用没有初始化的变量是导致问题的一个常见原因。nflag没有初始值,因此它的值是存储单元中的当前未知值。nflag被if-else-语句赋值为1或0,因此程序中并不使用此未知值。在检查程序时,应核实所有程序控制路径,在使用变量前,已经对变量正确初始化。

二、函数和全局变量

应灵活应用函数,如同if--else语句,while语句一样。

程序expand有一个有趣的地方,它的实现(implementation)使用了C语言中的所有控制语句。expand将参数指定的文件中的制表符(\t,ASCII码为9),展开成多个空格,默认是每8个字符设置成一个制表位。

2.2

主要用查德威克的《算法》第一章的程序模式。

程序

函数

API

数组

面向对象技术。  “抽象”数据类型

线性表

输入输出

2.3 编译器观念

在编译器看来,程序是基本块组成,一个基本块不会跳转到其他基本块中,而其他基本块也不会在这个块的中间跳转过来。一个基本块能包含多个语句,或者只有一个语句。程序的基本块之间的关系能用流图表示,或者用有向无环图表示。

3 数据结构

计算机程序的线性性。计算机存储器在逻辑视图上是线性特征,CPU执行对数据的操作也是线性方式,这决定了高级语言程序必须是线性的,才能在计算机上执行。现在不链接图灵可计算问题,应了解只有编写线性的程序,要编程的问题才会得到解决。程序的线性不是线性代数x+y ,而没有平方。程序的线性是数据结构的线性。图是many-to-many的逻辑关系,然而图算法的程序得到一个线性输出结构,或者过程是线性的,根据发现不同方面的图的线性性。例如输出图的最小生成树,最短路径问题是发现最短路径的SPT(最短路径树)。

4 程序功能

程序处理数据(data processing)的功能。

程序特征的章节组织方式:

第二章  按问题编程

第三章 程序结构和控制流与数据流

第四章 程序的正确性

第五章 用不变式推理程序

第六章  程序执行过程

第七章  程序功能结构

第八章  经典程序与算法

第九章  编程珠玑

第十章  集合论与文法

参考书是《编程珠玑》、《C语言高级程序设计》、《C++》、麻省理工《算法导论》、

               《代码阅读》、查德威克《算法》,《编译原理》,

                  卢开澄《计算机算法导引--设计与分析》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值