第Ⅰ篇 基础入门
第1章 C语言概述
C语言是国际上广泛流行的计算机高级程序设计语言,从诞生就受到计算机世界的关注,它是计算机世界最受欢迎的编程语言之一,具有强大的功能,许多著名的软件都是用C语言编写的。在学习C语言之前,应该对C语言的特点和应用领域有一个比较清楚的认识。只有这样,才能有目的、有方向地去学习。
本章要点(已掌握的在方框中打钩)
□ C语言的特点和应用
□ C语言的结构
□ C语言的运行
1.1 初学编程首选C语言
C语言是在国内外广泛使用的一种计算机语言。其语言功能丰富、表达能力强、使用灵活方便,既具有高级语言的优点,又具有低级语言的许多特点,适合编写系统软件。很多新型的语言,如C++、Java、C#、J#、perl等都衍生自C语言。掌握了C语言,可以说就掌握了很多门语言。C语言是计算机的基础,大多数软件都需要用C语言来编写。
1.1.1 程序设计语言
程序设计语言是用于书写计算机程序的语言,用来向计算机发出指令。计算机程序指的是能实现某种功能的指令序列。程序是由程序设计语言来编写的。
程序设计语言种类繁多,从20世纪60年代以来,世界上公布的程序设计语言有上千种之多。总的来说,可以分成机器语言、汇编语言和高级语言三大类。
机器语言:它是由二进制0、1代码指令组成的。机器语言面向机器,不同的CPU有不同的指令系统。机器语言需要用户直接对存储空间进行分配,机器语言具有灵活、直接执行和速度快等特点,但难编写、难修改、难维护。
汇编语言:它是机器指令的符号化,与机器指令存在直接的对应关系,所以汇编语言存在难学难用、容易出错、维护困难等缺点。汇编语言的优点是,它可直接访问系统接口,汇编程序翻译成的机器语言程序的效率高。汇编语言一般用在高级语言不能满足设计要求,或不具备某种特定功能的技术性能的情况下,如特殊的输入和输出。
高级语言:它是面向用户的,基本上独立于计算机种类和结构的语言,其形式上接近于算术语言和自然语言。高级语言的一个命令可以代替几条、几十条甚至几百条汇编语言的指令。高级语言易学易用,通用性强,应用广泛。高级语言种类繁多,可以分为面向过程语言和面向对象语言。面向过程语言是以“数据结构+算法”的程序设计范式构成的程序设计语言,如FORTRAN语言、C语言等。面向对象语言是以“对象+消息”的程序设计范式构成的程序设计语言,如C++语言、Java语言等。
1.1.2 C语言在计算机领域的地位
首先讲讲C语言的诞生故事。20世纪60年代,贝尔实验室的研究员Ken Thompson开发了一个游戏Space Travel,但没有合适的操作系统平台运行游戏,因此他决定开发一个操作系统。他先后尝试用汇编语言、Fortran语言编写,但效果都不理想,后来他在BCPL语言的基础上设计了B语言,并用B语言写出第一个UNIX操作系统,但B语言功能有限。Ken Thompson的同事,贝尔实验室的D.M.Ritchie,在B语言的基础上设计了C语言,保持了BCPL语言和B语言的优点——精练,接近硬件,又克服了它们的缺点—简单,数据无类型。1973年初,C语言的主体完成。Thompson和Ritchie用C语言完全重写了UNIX操作系统。随着大名鼎鼎的UNIX的发展,C语言自身也在不断地完善。
1983年,美国国家标准学会(American National Standards Institute, ANSI)对C语言进行了标准化,当年颁布了第一个C语言标准草案(83 ANSI C),1987年又颁布了另一个C语言标准草案(87 ANSI C)。1994年,国际标准化组织(International Organization for Standardization, ISO)修订了C语言的标准。最新的C语言标准C99是在1999年颁布的,并在2000年3月被ANSI采用,正式名称是ISO/IEC9899:1999。
1983年,贝尔实验室的Bjarne Stroustrup在C语言基础上推出了C++, C++是一种面向对象的程序设计语言,它进一步扩充和完善了C语言。
1995年,Sun公司(已被Oracle公司收购)正式发布Java, Java去除了C++的一些不太实用及影响安全的成分,包含了Applet技术(将小程序嵌入网页中进行执行的技术)。
可以说C语言、C++语言、Java语言是同一系的语言,并长期占据程序设计语言使用率排行榜的前三名。
1.1.3 C语言的特点和应用领域
每一种语言都有自己的优缺点,C语言也不例外,所以才有了语言的更替,有了不同语言的使用范围。下面列举C语言的一些优点。
(1)功能强大、适用范围广、可移植性好
许多著名的系统软件都是由C语言编写的,而且C语言可以像汇编语言一样对位、字节和地址进行操作,而这三者是计算机的基本工作单元。C语言适合于多种操作系统,如DOS、UNIX等。对于操作系统、系统使用程序以及需要对硬件进行操作的场合,使用C语言明显优于其他解释型高级语言,一些大型应用软件也是用C语言编写的。
(2)运算符丰富
C语言的运算符包含的范围广泛,共有34种运算符。C语言把括号、赋值、强制类型转换等都作为运算符处理,从而使C语言的运算类型极其丰富,表达式类型多样化。灵活地使用各种运算符可以实现在其他高级语言中难以实现的运算。运算符的介绍见第4章的相关内容。
(3)数据结构丰富
C语言的数据类型有整型、实型、字符型、数组类型、指针类型、结构体类型、共用体类型等,能用来实现各种复杂的数据结构的运算。C语言还引入了指针的概念,从而使程序的效率更高。
(4)C语言是结构化语言
结构化语言的显著特点是代码及数据的分隔化,即程序的各个部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰,便于使用、维护以及调试。C语言是以函数形式提供给用户的,因此用户可以方便地调用这些函数,并具有多种循环和条件语句来控制程序的流向,从而使程序完全结构化。
(5)C语言可以进行底层开发
C语言允许直接访问物理地址,可以直接对硬件进行操作,因此可以使用C语言来进行计算机软件的底层开发。
(6)其他特性
C语言对语法的限制不太严格,其语法比较灵活,允许程序编写者有较大的自由度。另外,C语言生成目标代码的质量高,程序执行效率高。
C语言应用范围极为广泛,不仅仅是在软件开发上,各类科研项目也都要用到C语言。下面列举了C语言一些常见的领域。
① 应用软件。Linux操作系统中的应用软件都是使用C语言编写的,因此这样的应用软件安全性非常高。
② 对性能要求严格的领域。一般对性能有严格要求的地方都是用C语言编写的,如网络程序的底层和网络服务器端的底层、地图查询等。
③ 系统软件和图形处理。C语言具有很强的绘图能力和可移植性,并且具备很强的数据处理能力,可以用来编写系统软件、制作动画、绘制二维图形和三维图形等。
④ 数字计算。相对于其他编程语言,C语言是数字计算能力很强的高级语言。
⑤ 嵌入式设备开发。手机、PDA等时尚消费类电子产品相信大家都不陌生,其内部的应用软件、游戏等很多都是采用C语言进行嵌入式开发的。
1.1.4 C语言学习路线
要了解C语言,就要从语法学起,首先要了解它的结构,如变量,了解变量的定义方式(格式),其意义是什么(定义变量有什么用);其次就是要了解怎么去运用它(用什么形式去应用它)。这些都是语法基础,也是C语言的基础,如果把它们都了解了,那么编起程序来就会得心应手。例如,if-else和switch-case这两种条件语句都是用来判断执行功能的,那要什么时侯用if,什么时侯用switch呢?如果能够很好地了解它们的结构和作用,那么就知道,若它的条件分支有多个,而且条件的值是整数或一个字符值,就会选switch。如果条件分支太多时用if语句,一定会出现if的嵌套,if的嵌套越多,程序的开销就会越大,这样整个程序的运行效率就会大大降低。而switch则不同,它只要比较一次,就可以找出条件的结果。不过switch也有它的约束条件,就是它的条件值一定要为一个整型数或一个字符值,所以碰到它不能解决的问题时通常也会使用if语句,毕竟if语句使用起来比较方便,而且使用范围也比较广。所以说了解语法规则是很重要的,如果没有一个良好的语法基础,很难编出一个好的程序。
学好语法基础后就可以开始编程了。很多初学者在看完题目后不知从何入手,其实在编写程序的时候,应该养成画流程图的好习惯。因为C语言的程序是以顺序为主,一步步地从上往下执行的,而流程图的思路也是从上到下一步步画出来的。而且画流程图的过程也是你在构建编写程序的思路的过程,流程图画好了,编程的思路也基本定了,然后根据思路来编写程序即可。
除了要掌握上述基本的知识外,良好的编程习惯也是学好C语言的重要因素,例如,编写程序时要有缩进,写注释,程序写到一定的阶段时要做模块测试等。程序的维护是一个很重要的问题,如果一个复杂的程序在编完后才发现有错误,那么找出错误的工作量将会非常大。但是若在编写程序时做好格式的缩进和写注释,那么程序看起来就会很清晰,如果在每个阶段都做模块测试,确定之前的程序没有错误,这样错误机会也会减少很多。
设计程序的过程如同解决一个实际问题,你需要从多个角度来分析,首先要了解这个问题的基本要求,即输入、输出,以及完成从输入到输出的要求是什么,其次,从问题的要害入手,从前往后解决问题的每个方面,即从输入开始入手,着重考虑如何从输入导出输出,在这个过程中可确定所需的变量、数组、函数,然后确定处理过程——算法,最后得出结论。
学习一门编程语言之前,都要了解这门语言的精髓是什么。对于C语言而言,指针的定义与运用是它的一大特色,也是其能够得到广泛应用的重要原因之一。例如,指针可以作为数组的地址使数组的处理变得简洁;也可以通过指针给函数传递变量的地址,从而实现调用函数后返回多个值;指针还支持动态内存分配,使处理数值、字符数组的方法更为简单。本书对指针内容进行了更新,详细讲解了这方面的内容。
1.2 快速学会看懂C程序
1.2.1 一个简单的C程序
下面给出一个简单的C程序的例子。通过这个例子介绍C程序的基本结构。
范例1-1 从键盘输入两个数,求它们的乘积并输出
(1)在Code::Blocks 16.01中,新建名为“两个数的乘积.c”的【C Source File】源程序。
(2)在代码编辑窗口输入以下代码(代码1-1.txt)。
01 #include<stdio.h> 02 int main() 03 { 04 int mul, a, b; 05 printf("请输入两个数:\n"); 06 scanf("%d%d", &a, &b); /*输入两个数据*/ 07 mul=a*b; 08 printf("这两个数的乘积是%d", mul); 09 return 0; 10 }
【运行结果】
编译、连接、运行程序,输出结果如下图所示。
【范例分析】
从C语言的程序可以联想到数学中函数的使用。先举个例子,如数学中f(x)=x+1,这个函数的功能就是将自变量x加1,这是函数f的定义部分。f(3)就是x=3时这个函数的值。C程序的组织单位就是函数。从整体上看这个程序中主要的函数就是main()函数。
第01行是#include命令,是文件包含命令,后面< >中的stdio.h是头文件,这个语句的作用是进行预处理,之所以要加这个命令,是因为后面要使用到的输出函数printf()和输入函数scanf()的定义部分就放在stdio.h这个头文件中。
第02行是main()函数,其中int是关键字,是指定了main()函数的函数值的类型是整型的。main是函数名,后面()中的内容是这个函数的参数,如果没有表示默认。这一行是main()函数的函数头部分,主要声明的包括函数值的类型,函数名以及参数。
从第03行的“{” 到第10行的“ }”,是main()函数的函数体部分。“{”表示函数体的开始,“ }”表示函数体的结束。函数体中主要包括的就是语句序列。
第04行是定义了要用到的3个变量,类型是整型的,mul变量要存放两个数的乘积,a和b变量分别存放两个数据。
第05行pirntf()函数的功能是向屏幕输出一行字符串,就是()中的用一对双引号括起来的字符串。这一行的作用是输出一条提示信息。
第06行scanf()函数的功能是从键盘输入数据存放在指定的变量中,这里指定了两个变量a和b。/*输入两个数据*/是注释,注释的作用是对代码进行解释说明,方便理解代码的含义。
第07行是变量a和b相乘,将它们的乘积赋值给mul变量。
第08行是用printf()函数输出mul的值。
第09行是函数的返回值,返回值是0,就是main()函数的值。
1.2.2 C程序的基本结构
通过上面的例子,大家对C程序有了一定的了解。总结一下就是,函数是组织单位,语句是执行单位。程序的执行是从main()函数开始的,main()执行结束,程序也就结束了。可以说main()函数既是程序的起始,也是程序的结束。
一个C程序可以包含以下内容。
01 头文件
C语言提供有丰富的函数集,我们称之为标准函数库。标准函数库包括15个头文件,借助这些函数可以完成不同的功能。可以用#include命令将头文件包含进来,当然不仅可以是系统提供的头文件,也可以自己定义的头文件。
02 main()函数
每个C程序必须有而且只有一个主函数,也就是main() 函数,它是程序的入口。main() 函数有时也作为一种驱动,按次序控制调用其他函数,C程序是由函数构成的,这使得程序容易实现模块化;main() 函数后面的“()”不可省略,表示函数的参数列表;“{”和“}”是函数开始和结束的标志,不可省略。
主函数在程序中可以放在任何位置,但是编译器都会首先找到它,并从它开始运行。它就像汽车的引擎,控制程序中各部分的执行次序。
下图是对主函数各部分名称的说明。
03 函数定义部分
C语言编译系统是由上往下编译的。一般被调函数放在主调函数后面时,前面就应有声明,否则C语言由上往下的编译系统将无法识别。正如变量必须先声明后使用一样,函数也必须在被调用之前声明,否则无法调用!函数的声明可以与定义分离,要注意的是一个函数只能被定义一次,但可以声明多次。
函数定义:
返回类型函数名(参数类型1参数名1, …,参数类型n参数名n) { 函数体 … }
例如:
int fun(int a, int b) { int c; c=a+b; return c; }
04 注释
读者可能已经注意到,很多语句后面都跟有“/*”和“*/”符号,它们表示什么含义呢?
在前文已经说过,在编辑代码的过程中,希望加上一些说明的文字,来表示代码的含义,这是很有必要的。
费了很大精力,绞尽脑汁编写的代码,如果没有写注释或者注释写得不够清楚,一段时间后又要使用这段代码时,当年的思路全部记不得了,只得重分析、重理解。试问,因为当初一时的懒散造成了今日的结局,值得吗?又比如,一个小组共同开发程序,别人需要在该小组写的代码上进行二次开发,如果代码很复杂、没有注释,恐怕只能用4个字形容组员此时的心情:欲哭无泪。所以,编写代码时最好书写注释。
注释的要求如下。
(1)使用“/*”和“*/”表示注释的起止,注释内容写在这两个符号之间,注释表示对某语句的说明,不属于程序代码的范畴,如范例1-1代码中“/*”和“*/”之间的内容。
(2)“/”和“*”之间没有空格。
(3)注释可以注释单行,也可以注释多行,而且注释不允许嵌套,嵌套会产生错误,例如:
/* 这样的注释 /* 特别 */ 有用 */
这段注释放在程序中不但起不到说明的作用,反而会使程序产生错觉,原因是“这样”前面的“/*”与“特别”后面的“*/”匹配,注释结束,而“有用 */”就被编译器认为是违反语法规则的代码。
1.2.3 C程序从编写到运行的过程
计算机只能识别二进制代码,C程序不能在计算机上直接运行。要转换C语言为在计算机上可执行的文件,共包括以下四个步骤。
01 编辑
人们把编写的代码称为源文件或者源代码,输入修改源文件的过程称为编辑。在这个过程中还要对源代码进行布局排版,使之美观有层次,并辅以一些说明的文字,帮助理解代码的含义,这些文字称为注释,它们仅起到说明的作用,不是代码,不会被执行。经过编辑的源代码经过保存,生成后缀名为“.c”的文件。
02 编译
编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言。经过编译,把源文件转换为以“.obj”为后缀名的目标文件。如果编译不通过,则说明该程序存在语法错误,要回到第一步重新编辑。
03 连接
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等),在程序中可能调用了某个库文件中的函数等。所有的这些问题,都需要经链接程序的处理方能得以解决。
连接程序的主要工作就是将有关的目标文件彼此相连接,即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。并形成最终可执行的二进制机器代码(程序),后缀名是“.exe”的文件。
04 运行
计算机能够执行可执行程序。如果和预期的结果不同,则说明该程序存在逻辑错误,要回到第一步重新编辑。