1,C语言概述
C语言是70年代问世,它实际先有语言后有标准。1978年贝尔实验室B.W.Kernighan和D.M.Ritchit合著“The C Promgaming language”一本书,这本书就作为C的基本标准,以后ANSI出了一ANSI C标准于1983年公布。C正因为没有标准,因此依赖于编译器实现,不同的编译器实际上就是不同的C标准。现在最新的标准是C0X标准。任何一个C语言都包含变量、函数、声明及注释。如下图所示:
2.数据类型、运算符及表达式
数据按照CMU中所说,任何信息在计算机中就等于BITs+Context。 所有的数据在机器内存中存储都一样,只是因为有不同的上下文的表述,就显示出不同的现实意义。在C语言中数据分不可再分解的基本类型和构造类型,还有针对指针的指针类型及空类型。如下图所示:
那为什么C语言来区分这些不同的类型呢,一个是为了同现实世界接轨,也就是更符合语义世界。另外一个通过指定类型,也让程序在运行时更好的分配内存空间。
从上图所示中,数据类型只是简单的表述了这个数据如10或10.0它是什么类型,那么在计算机中怎么表示呢,或者我们现实世界上是怎么表示的呢?首先在现实世界上,想要表述一个10的概念,你可以说一句”SHI”的汉语拼音,也可以用笔写下“十”的字符来表示。因此,在计算机世界上,它也是需要东西来表述10的,最基本的就是ASCI,有了ASCI符号表,原本二进制内存内容可通过这个ASCA码转换成图形符号。那么对计算机来说,计算机最基本的功能就是计算,从小我们的算术就是有很多符号来表示。因此在计算机世界里,同我们的基本算术一样,也是需要一些基本符号表。通过这些基本符号来表达一定的语义,如“=”,现实生活中,我们都这知道它就是等于,如5+4=8。这就是我们从小学习的基本算术。在计算机中,因为它需要让计算机能够理解一个通用的计算系统。所以它比较复杂了一点。但是基本上原理是一样的,比喻说5+4=8变成通用的就是VAR1+VAR2=VAR3。所以计算机设计了一个中间符号变量。你可以定义一个变量var1=5,然后进行相加。这样做的好处就是将现实世界人脑处理的计算过程抽象化了。变得通用。所以对任何数据来说,都存在一个常量与变量。也就是说VAR1你可以设置一个常量,也可以设置一个变量。这两个量从字面函义就可以明白。
C语言默认将数值分成整形与浮点型两种,后面还有一种字符的CHAR型。在32位机器中都是采用32位存储。除了Short,CHAR是16位之外。这一块其实不复杂,只要记住一点,这些类型,内存是按内存存储这些十进制数据的。存储的方式按机器方式不一样,大部分机器都采用补码的方式存储。但是从内存的角度来说,都可以用十六进制描述。所以所谓这些类型,其实都是现实当中的意义。因此,从这里也就可以理解字符型实际上跟短整型是一样的。也可以相互转换。所以字符都是通过ASCII码转化数字。然后存储在内存中。这些字符除了常见的数字字符,还包括大小写ABC等,及转义字符。对汉字来,目前汉字是采用两个字节存储一个汉字字符。
前面的这些都是基本数据类型,还有一种特殊的字符串常量。字符串是由多个字符组成用来表示特定含义的。如“C program”。如果用字符类型来表示,需要9个Char来表示。但是C语言提供了另外一种字符常量方式来存储这种数据。其后用“\0”结尾。就变成需要10个char来存取。如下图所示:
不同数值型的数据之间进行混合运算时基本原则都是按数据长度增加的方向进行转换。而对32位机器Float默认就是Double型。赋值时右边数据长度以左边为准。但类型不一定。强制转换时使用(类型说明符)(表达式)。
类型转换在C语言中非常重要,也是最基本的内存分配方式,需要注意的是自动转换通常是数据长度增加,但赋值则是左结合原则。会舍去一部分内容。
C语言中运算符分为算术运算符和关系运算符。按结合顺序的运算符级别分为15级,这种结合性有左结合也有右结合,通常是按优先级来决定。注意通常情况下关系运算符小于算术运算符。如a+b>c-d先算a+b再算c-d,但通常情况下如果避免混淆,最好用()隔开。
这其中有两个特殊的运算符,一个是自增自减,也就是++和――,需要注意其中表达式的值和单元素值的计算顺序。还有一个就是逗号运算符,逗号整个表达式的值只取最后一个表达式的值。(注意这个在不同的编译器实现是不一样的,如现在VS2005,实际上取得是第一个表达式的值,因此,除非特别需要,最好不要使用逗号表达式。)
3.过程程序设计
程序结构,如果仔细的思考一下,程序流程实际上代表了一种思考方式。比喻我们要思考如下一件事件,找到一个失联很长时间的同学的联系方式。那么首先我们需要知道的是这个同学的名字。这个就等于一个程序流程的外部输入。就着,我们需要采用一些方法去查找到这个同学的名字,比喻说打电话问相关的其它同学或者上网搜索或者发邮件问其它同学等方式,最后我们肯定能得到一个联系方式。这就是所要的结果。因此从这里我们就可以看出来,一个思考过程就是一个程序流程。比喻说我们要安排查找顺序,先电话后邮件再上网,就是就一个顺序结构,再比喻电话一个同学,不行可能还需要另外一个同学,就变成了一个分支结构。还是发邮件过程,比喻说发一次邮件,没有回,还要再发一次。就变成了循环过程。因此程序的三种基本结构就是顺序、分支、循环。那么还有其它的吗?好像经过研究没有了,其它的一切都可以通过这三种来组合出来。在程序设计过程中,程序通常都是需要使用语句就像人类使用语句一样来说明一个概念或者一个命令。语句在过程程序中非常重要。基本上C程序就是由各种不同目的语句组成。
C程序如何同外界交互呢?比喻说读取控制台的一个字符或者一个字符串呢,以及如何输入呢?这就是基本输入输入命令语句。这些已经内部实现在标准库中。不是C语言的标准,但是作为一个基本库提供给开发者。这里有两个函数针对字符getchar()和putchar(‘‘),针对字符串有scanf和printf.格式化输出需要控制输出数据类型、输出宽度、输出精度(用小数点),输出长度(用l和h)
对printf内部含有表达式的情况下,需要注意不同编译器的顺序,有些编译自左向右计算表达式,有些则是自右向左计算表达式。为避免编译器问题,最好不要引入带有自增自减或者多个表达式引用同一个变量的情况下,以避免不同的计算顺序产生的结果不一样。
对scanf需要注意可以使用*跳过赋值,如scanf(“%d %d*d %d”,&a,&b),如输入 1 2 3,则1给a,2跳过,3给b。另外使用宽度标准也可以截取,如scanf(“%4d%4d”,&a,&b)如输入12345678,则1234给a,5678给b。其它需要注意的是精度无用。字符输入时空格也是字符。如果想要控制字符输入,可以使用逗号格式或者空格格式。如scanf(“%c,%c”,&a,&b);
过程设计使用三种基本语句:顺序语句、分支语句和循环语句。顺序语句没什么好说的。对分支语句主要是使用IF/else if /else 再加上关系表达式进行判断,这个关系表达式,实际也不一定,赋值表达式也可以。通常写表达式时将常量在前如if(3==a)避免写错。if是可以内部嵌套。
上面是if的常用结构,注意else总是跟一个最近的。另外一个分支是?,三目运算符。
循环结构是程序中一种很重要的结构,其特点在给定条件成立的情况,反复执行,直接条件不成立。当然这当中需要修改条件。常用的循环语句如GOTO,for,while.do-while。其中while与do-while 区别在于do-while一定会先做一次。
在循环和分支switch语句中还常用到break和continue语句。需要注意的是如下所示:
4.数组
前面我们说的是基本数据类型,数组是构造数据类型,为什么需要数组这个概念,数据是具有相同类型的数据组成的序列。是一个有序集合。数组由元素和下标组成。数组在内存中存放是预先分配空间,因此数组大小必须先进行定义。定义之后也不可更改。
数据元素初始化有定义时用{}进行初始化,也可以使用for循环赋值,也可以采用scanf动态赋值。不管怎么样赋值,唯一一点不可变的就是大小在定义时确定。其它任何时候都不能改变。
一维数组、二维数组、多维数组其实一维数组的扩展。因为内存是一维存储方式。不论二维还是多维,都可以按行将数组拆分成一维。如下图所示:
其初始化也如同一维数组一样,从前向后进行赋值。
5.函数
函数可以说是C语言的灵魂,也是过程程序的关键点。C语言默认主入口是void main()函数。从程序开发的角度来说,程序随着解决问题的复杂性变得非常复杂,一个解二元方程题可以在main函数中直接解决掉,但是一个计算一个中学的所有学生的各科成绩、性别统计等相关信息的程序就不可能在一个main函数中解决掉。所以过程程序是分模块设计的。这也符合软件工程的模块化设计思想。通常的高级语言中都有子程序概念,C语言中以函数为子程序,以多个文件为程序模块组成。如下图所示:
如上图所示,一个C程序由一个或多个程序模块组成,每个程序模块可以作为一个源程序文件,通过一个编译控制文件进行单独编译最后组合链接到一起。从函数的角度来说,一个C程序由一个main 加上多个用户自定义函数和系统库函数编译连接到一起。每个函数是相互并行的,不能一个函数中嵌套一个函数。函数的实现或者定义形式如下:
其中形参部分,可有也可以没有,根据情况决定。通过函数调用使得形参获得实参的值或者实参的地址,并通过函数内部运算得到一个返回值返回给调用者,如果实参是以地址形式参与函数内部运算,运算完成之后,地址所存储的值也有可能发生改变。如下图所示:
如果实参是一些表达式,还需要进行计算,再传给形参,不同的编译器对实参语句的执行顺序是不一样的,有些自右向左,有些自左向右,对visual studio它是自右向左,但是需要注意的是它是所有表达式求完之后再赋值。函数的声明与定义是两个概念,定义可以在任何地方定义。如果定义在调用之前,可以不用在定义之前声明。如果定义在后,需要声明。声明可以在调用之前,也可以在文件最前。如果定义在其它文件,需要include进来声明文件。