
第1部分 基础知识
第1章 C语言简介
C 语言是一门高级程序设计语言,也是现在国际上比较流行的计算机程序设计语言之一。C语言自1973年在美国贝尔实验室成为一种标准语言之后,便受到广大开发者欢迎,如今已经成为世界上使用最广泛、最流行的高级程序设计语言之一。那么,C语言到底什么样子呢?我们看下面简单的案例。
【例1-1】 第一个程序“Hello,World!”。
// example1-1
#include "stdio.h"
void main()
{
printf("Hello,World! \n ");
}
我们从【例1-1】入手,分析C语言的格式和特点和介绍C语言。
1.1 计算机语言的发展
介绍C语言之前,先了解计算机语言,因为C语言是计算机语言的一种。
计算机语言(Computer Language)是人与计算机之间传递信息的媒介,用于人与计算机之间的通信。为了使计算机按照人类的指令进行各种工作,计算机系统就需要有一套人能够编写并能翻译后计算机能读懂的程序,用来表示生活中的数字、字符和语法规则,以通过指令把命令传达给机器。由这些字符和语法规则组成的计算机的各种指令(或各种语句)就是计算机语言。
计算机语言的发展经历了机器语言、汇编语言、高级语言3个阶段。
1.1.1 机器语言
机器语言是指计算机能够完全识别的指令集合,是最低、最早的程序语言,是由“0”和“1”组成的二进制数(代码),而二进制是计算机的语言基础。计算机发明之初,人们将一串串由“0”和“1”组成的指令序列交由计算机执行。这就是计算机唯一能够真正识别的机器语言。使用机器语言编写程序是十分痛苦的,特别是程序有错需要修改的时候。
1.1.2 汇编语言
为了减轻使用机器语言编程的痛苦,人们进行了一些改进。用一些简洁的英文字母、符号串来替代一个(串)特定的已编写的指令的二进制串,比如用“ADD”代表加法,“MOV”代表数据传递等。这样一来,人们很容易读懂并理解程序在干什么,纠错及维护就变得方便了。这种程序设计语言即第二代计算机语言,称为汇编语言。然而,计算机是不认识这些符号的。这就需要一个专门的程序,专门负责将这些符号翻译成二进制代码的机器语言。这种翻译程序被称为汇编程序。
汇编语言十分依赖于机器硬件,移植性不好,但效率十分高,尤其在结合计算机硬件方向上更能发挥特长,所以至今仍是一种强有力的软件开发工具。
1.1.3 高级语言
从最初与计算机交流的痛苦经历中,人们意识到应该设计一种语言。这种语言接近于数学语言或人的自然语言,同时又不依赖于计算机硬件,编出的程序能在所有机器上通用。经过努力,1954年,第一个完全脱离机器硬件的高级语言—FORTRAN问世了。60多年来,共有几百种高级语言出现,有重要意义的、影响较大、使用较普遍的有FORTRAN、BASIC、Pascal、C、PROLOG、C++、VC、VB、Java等。从另一个角度分类,高级语言中的VC、Java等也被定义为面向对象语言,所以也有把面向对象语言划分为第四类语言。
1.1.4 计算机语言的概念
了解了计算机语言的发展,下面我们再了解几个概念。
指令:一条机器语言称为一条指令。指令是不可分割的最小功能单元。
程序:早期的程序就是一个个的二进制文件,如今程序可以定义为“计算机要执行的指令的集合”。
机器语言是第一代计算机语言。早期人们通过机器语言向计算机发出指令,无需借助翻译程序就能运行机器语言编好的程序来执行。
汇编语言是第二代语言,其实质和机器语言是相同的,都是直接对硬件操作,只不过指令采用了英文缩写的标识符,更容易识别和记忆。
高级语言是目前绝大多数编程者的选择。它们虽然需要借助翻译程序才能被计算机识别,但其简化了程序中的指令,并且去掉了与具体操作有关但与完成工作无关的细节。
高级语言的发展经历了从早期语言到结构化程序设计语言及面向过程到非过程化程序语言的过程。20世纪60年代中后期,软件各自为战,后期出现的“软件危机”就是因为兼容性错误和困难造成的。1970年面向过程的结构化程序语言—Pascal的出现,标志着结构化程序设计时期的开始。20世纪80年代初开始,面向对象的程序设计语言如C++、Visual Basic、Delphi出现。高级语言的下一个发展目标是面向应用,也就是说只需要告诉程序要干什么,程序就能自动生成算法进行处理。这是非过程化的程序语言。
1.2 C语言的发展及其特点
1.2.1 C语言的发展
C语言是目前世界上最流行、使用最广泛的面向过程的高级程序设计语言之一。C语言在操作系统、编译程序及硬件模块需求等方面的操作优势,明显优于其他高级语言,许多大型应用软件都是用C语言编写的。
C语言的原型是ALGOL 60(ALGOrithmic Language 60)语言(也称A语言)。1963年剑桥大学将ALGOL 60语言发展成为CPL(Combined Programming Language)语言。1967年马丁·理查兹(Matin Richards)简化了CPL语言产生了BCPL(Basic Combined Programming Language)语言。1970年美国贝尔实验室的肯·汤普森(Ken Thompson)将BCPL进行了修改,起了一个有趣的名字“B语言”,并编写了第一个UNIX操作系统。
1973年美国贝尔实验室的D.M.RITCHIE最终设计出了一种新的语言—C语言,名字取自BCPL的第二个字母。1978年布莱恩·科尔尼干(Brian W.Kernighian)和丹尼斯·里奇(Dennis M.Ritchie)出版了名著《The C Programming Language》(中文译名为《C程序设计语言》),称之为《K&R》标准,但是《K&R》中并没有定义一个完整的标准C语言。1983年,美国国家标准化协会(American National Standards Institute,ANSI)制定了一个C语言标准,通常称之为ANSI C。1987年,C语言有了ANSI标准,立刻成为最受欢迎的语言之一。
1990年,国际化标准组织(International Standard Organization,ISO)接受了87 ANSI C为ISO C的标准(ISO9899-1990),简称为C90。1999年,ISO对C语言标准进行修订,主要是增加了一些功能,尤其是C++中的一些功能,简称为C99。2011年又发布了新的标准,简称为C11。目前流行的C语言编译系统大多是以ANSI C 为基础进行开发的,但不同版本的C编译系统实现的语言功能和语法规则略有差别。
C语言在发展的过程中,逐步完善,拥有绘图能力强、可移植性好及很强的数据处理能力等优点。因此,系统软件的编写及二维、三维图形的绘制和动画制作与处理等都是它的强项之一。
1.2.2 C语言的特点
C语言的特点主要包括以下几个方面。
1.简洁紧凑,灵活方便
C语言一共有32个关键字、9种控制语句,程序书写自由,主要用小写字母表示。C语言把高级语言的基本结构和语句与低级语言的实用性结合了起来,简洁紧凑,灵活方便。
2.运算符和数据结构丰富
C语言的运算符较多,共有40多个。C语言把括号、赋值、强制类型转换等都作为运算符处理,从而使C的运算类型极其丰富,表达式类型多样化。程序开发者灵活使用C语言的各种运算符可以实现在其他高级语言中难以实现的运算。
C语言的数据类型有整型、实型、字符型、数组类型、指针类型、结构体类型、共用体类型等。这使得C语言能实现各种复杂的数据类型的运算。另外,C语言引入了指针概念,使程序效率更高。
3.C是结构式语言
结构式语言是C语言的显著特点。结构化方式使程序层次清晰,便于使用、维护及调试。C语言是以函数形式提供给用户的,多种循环、条件语句控制和函数调用使程序完全结构化。
4.C语法限制不太严格,程序设计自由度大
一般的高级语言语法检查比较严,能够检查出几乎所有的语法错误。而C语言允许程序编写者有较大的自由度,限制并不严格,尤其在越界检查方面,几乎没有限制。
5.允许直接访问物理地址,直接操作硬件
C语言既具有高级语言的功能,又具有低级语言的许多功能,能够像汇编语言一样对位、字节和地址进行操作,而这3者是计算机最基本的工作单元,因此,C语言可以用来编写系统软件。
6.程序执行效率高
C语言程序执行效率高,一般只比汇编程序生成的目标代码效率低10%~20%。
7.可移植性好
C语言有一个突出的优点就是适合于多种操作系统,如DOS、UNIX,也适用于多种机型。
当然,C语言也有自身的不足,比如C语言的语法限制不太严格,对变量的类型约束不严格,影响程序的安全性,对数组下标越界不做检查等。从应用的角度,C语言相比其他高级语言较难掌握。
1.3 C语言的程序格式和结构
1.3.1 最简单的C语言程序举例
要了解C语言的程序格式与结构,可以从引入案例的程序中分析C语言程序的特点,总结其格式和基本结构。
以【例1-1】第一个程序“Hello,World!”为例。
// example1-1 The first C Program 行1 — 注释
#include "stdio.h" //行2—编译预处理
void main() //行3 —函数
{
printf("Hello,World! \n "); //行5 —语句
}
本程序运行后输出如图1-1所示信息。

图1-1 Hello,World!
本程序与引例程序相比,增加了注释说明,解析如下。
第一行是注释,对程序的编译和执行不起任何作用,目的是使读者无需看后续很长的程序代码也能知晓本程序的功能。注释语句常用“//” 开头,其后的任何信息都是注释信息。除了“//”之外,还可以使用对称结构“/*…*/”作为注释语句,详细的注释信息在“/*”和“*/”之间,二者顺序不能更换,个数不能多。注释信息可以放在程序的任何位置,可以为任何文字或字符,可以单独成行,也可以与其前被注释的信息为一行。
第二行是编译预处理,对C语言程序中的输入/输出等系统函数调用声明,printf输出函数和scanf输入函数保存在“stdio.h”头文件中,所以编译预处理“#include "stdio.h"”不可少。如果有其他系统函数被调用,也必须有对应的编译预处理文件声明,详细的介绍见第9章。
第三行中的main是函数的名字,main前面的void表示此函数类型为空类型,即执行此函数不产生一个函数值。有些函数会返回一个值,如数学函数sin(x)、cos(x)等。C语言中规定:任何一个C语言程序都必须有一个main函数,并且只能有一个main函数。
第四行和第六行:C语言程序中,在函数后面的函数体是以“{”和“}”一对大花括号括起来的,在函数体后面的第一个“{”和最后一个“}”可分别对应函数体的开始与结束。
第五行为函数语句,以半角分号(;)作为语句结束符。在C语言中,没有行的概念,只是以分号(;)作为语句的结束符,也就是C语言程序以语句作为最基本的函数体单位。第五行的“printf("Hello,World!\n ");”把双引号内的内容“Hello,World!”原样输出,并换行,其中“\n”是换行符。
【例1-2】 第二个程序,计算两个数x和y的和。
#include "stdio.h" //行1 编译预处理
void main() //行2 main主函数
{
int x,y,sum; //行4 定义整数型变量x、y和sum
x=123; //行5 对变量x赋值
y=456; //行6 对变量y赋值
sum=x+y; //行7 求和赋值给变量sum
printf("sum is =%d\n",sum); //行8 输出sum
}
本程序运行后输出如图1-2所示信息。

图1-2 计算两个数x和y的和
本程序省略了注释行,没有注释信息。程序的主要作用是求已知的两个整数x和y的和,并输出sum的值。下面着重解析第四行到第八行。
第四行:声明部分,定义变量x和y,其中定义的x和y为整数类型(int)变量,存放整数。
第五行和第六行:赋值语句,对定义的变量x、y分别赋值123和456。
第七行:对已经赋值的整数x、y进行求和计算,计算后的和赋值给变量sum(存放和,否则求和数据会存放在计算机中的任何变量中,无法寻找和输出)。
第八行:输出sum。输出语句中使用了格式控制符,字符串“sum is=”原样输出,sum以“十进制整数类型”输出。格式控制符的相关知识将在第4章详细讲述。
【例1-3】 第三个程序,求两个数x和y最大值。
#include "stdio.h" //行1 编译预处理
void main() //行2 main主函数
{
int max(int x,int y); //行4 声明被调用函数
int a,b,c; //定义变量a、b、c
scanf("%d%d",&a,&b); //行6 输入变量a、b的值
c=max(a,b); //行7 调用max函数求最大值,结果赋值给变量c
printf("max is %d\n",c); //输出最大值
}
int max(int x,int y) //行10 自定义求最大值函数max,形式参数有x和y两个
{
int z; //定义变量z
if(x>y) z=x;
else z=y; //使用if语句求任意两个变量x、y的最大值
return z; //返回最大值z
}
本程序运行后输出如图1-3所示信息。

图1-3 求两个数x和y最大值
解析如下。
第四行:“int max(int x,int y);”声明调用函数max。max是自定义函数,其作用就是求出两个数的最大值并返回,详细的函数功能代码见第十行后。
第六行:从键盘上读入两个数分别赋值给变量a、b。
第七行:调用自定义函数max求变量a、b的最大值,并把最大值赋值给变量c存储。
第十行:自定义函数max的功能是求最大数,其中max有两个形式参数x和y,max函数的函数体,其作用是求x和y的最大值,把最大值赋值给z,最后把求出的最大值z返回。
本程序一共包括两个函数,其中一个是main主函数,另一个是求最大值的自定义函数max。main函数调用max函数把最大值返回到调用max函数的位置。
main函数中scanf函数的作用是输入变量a、b的值,而printf函数的作用是输出最大值到屏幕上。
1.3.2 C语言程序的结构
通过以上几个例子,可以总结出C语言程序组成和结构如下。
(1)一个程序由一个或多个源程序文件组成。简单的程序如【例1-1】和【例1-2】的源程序文件只由一个main函数组成,而【例1-3】的源程序文件包含两个函数。一般源程序文件包含以下几个部分。
① 预处理指令:主要包括“#include”“#define”等以“#”为开始,在程序运行前实现的预处理。
② 变量声明:函数体“{}”内的声明是局部声明,在函数“{}”之外的声明为全局声明,两者的有效作用域不同,详见第9章预处理命令。
③ 函数定义:函数是C程序中最重要的部分,可以说整个C程序几乎都是由函数组成的。函数就是实现一定功能的程序模块,所以说函数的定义是C程序的功能体现。
(2)函数是C程序的基本单位,是C语言程序的主要组成部分。一个C程序是由一个或多个函数组成的,但 main 函数必须有并且只能有一个。C 语言程序总是从 main 函数开始,以 main函数结束,其他函数只能通过main函数直接或间接调用。
(3)一个函数包含两个部分:函数首部和函数体。
① 函数首部:函数的第一行,包括函数名、函数类型、函数参数(形式参数)和参数类型。例如,【例1-3】中的int max (int x,int y)。
② 函数体:函数首部下面的大括号开始的部分,当然如果一个函数体内存在若干个大括号,则最外层(或第一个“{”和对应的最后一个“}”)的一对大括号才是函数体语句范围。
函数体一般包括以下部分。
● 声明部分:包括变量定义和调用函数的声明,如【例1-2】中的int x,y,sum;和【例1-3】中的int max(int x,int y);。
● 执行部分:由若干个语句组成,在函数中执行一定操作,如【例 1-1】中的 printf("hello world!\n");是为了执行输入实现打印功能的。
(4)C程序的函数由语句组成。C程序语句以半角分号(;)作为分隔符,其也是语句唯一的终止标志。
(5)C程序中没有程序行的概念,习惯使用小写字母。
(6)程序可以包含注释。注释在程序的执行中不起任何作用,也不会产生任何代码。
1.4 C语言程序的运行与调试
1.4.1 C语言程序的运行环境
一个C语言程序的运行离不开它的翻译程序,其称之为编译环境。目前使用最多的集成开发环境(Integrated Development Environment,IDE),就是把C语言程序需要连接的步骤—编辑、编译、链接和运行集成在一个界面上,通过不同的操作步骤实现。集成环境的优点:简单实用,功能丰富,直观易学。
不同的编译环境对C程序的操作是不同的。常用的编译程序有Turbo C 2.0、Turbo C++ 3.0、Borland C++、Visual C++6.0、Microsoft Visual Studio 2010等。在20世纪90年代,Turbo C 2.0编译环境应用最为普遍,但其缺点是进入DOS环境后不能使用鼠标操作,几乎只能通过键盘完成。随后的Turbo C++ 3.0编译环境虽然已经完成启动文件快捷方式“tc.exe”,但鼠标只能执行部分操作,如文件保存、基本菜单的选择等。如今编译环境有了长足发展,尤其是全国计算机等级考试(C语言模块)的编译环境—Microsoft Visual C++6.0的推广,使Visual C++6.0编译环境的应用占据了很大的部分。随着 CPU 处理能力的进一步增强,64 位机逐渐成为主流,Microsoft Visual Studio 2010支持64位的优势逐渐体现,在Windows8以上操作系统下安装使用Microsoft Visual Studio 2010越来越多。
Visual C++6.0为用户开发C程序提供的集成环境包括源程序的输入和编辑、源程序的编译和链接、程序运行时的调试和跟踪、项目的自动管理、为程序的开发提供各种工具并具有窗口管理和联机帮助等功能。尤其可贵的是,在Visual C++6.0编译环境中,鼠标、键盘非常方便,复制、粘贴、剪切等基本操作与Windows环境下的操作几乎没有区别。
1.4.2 C语言程序的几个概念
在了解C语言程序运行之前,先了解C语言中的几个概念。
程序:可以连续执行的指令集合。
源程序:使用高级语言编写的程序,如Visual Basic、C、C++、Java等编写的程序,其中C语言编写的程序可称为源程序,C源程序文件后缀为.c。
目标程序:由二进制代码表示的程序,C源程序生成的目标程序文件的后缀为.obj。
可执行程序:可移植可执行的文件格式,可加载到内存中由操作系统加载程序执行,如C源程序经过编译和链接后生成的后缀为.exe的可直接运行的文件。
编译程序:具有翻译功能的软件如Visual C++ 6.0、Microsoft Visual Studio 2010等称为编译程序。
以上几个概念在C语言的调试运行的不同阶段出现。在编译程序Microsoft Visual C++ 6.0中输入C源程序,保存后的源程序经过编译命令生成目标程序,目标程序链接库函数后进一步生成可执行程序,最后运行可执行程序查看程序运行结果。
1.4.3 C语言程序的运行调试
本书采用Visual C++ 6.0作为程序设计调试的环境,常用的Microsoft Visual Studio 2010的调试运行步骤在实验指导中详细介绍。
1.启动Visual C++ 6.0
通过鼠标双击桌面上的Visual C++ 6.0的图标,或通过菜单方式启动Visual C++ 6.0,即用鼠标单击“开始”菜单,选择“程序”,选择“Microsoft Visual Studio 6.0”,选择“Microsoft Visual C++6.0”启动Visual C++ 6.0。图1-4所示为启动后的可视化集成环境,窗口包括标题栏、菜单栏、工具栏和状态栏等。

图1-4 Visual C++ 6.0集成环境
2.生成源程序文件
选择“文件(File)”菜单中的“新建(New)”命令,产生“新建(New)”对话框,单击“文件”选项卡,选择C/C++ Source File选项,文件命名为*.c格式如lt104.c,并设置源文件保存目录,单击“确定”,生成源程序文件,如图1-5所示。

图1-5 源文件生成
注意
指定的文件名后缀为“.c”,如果输入的文件名缺少后缀“.c”,则系统默认为 C++源程序文件,自动加上后缀“.cpp”,因此后缀“.c”不能省略。
3.编辑源程序
在程序编辑区输入源程序,如图1-6所示,选择“文件”菜单下的“保存”。

图1-6 编辑源程序
注意
(1)图1-6所示的C源程序存在错误,这是为程序调试故意设置的。
(2)注意文件名,工作区的文件名为“lt104.c”,而Visual C++ 6.0的标题名为“创天中文VC++”。
(3)源程序编辑的重要一步是保存。
4.编译和调试程序
单击“编译”(Compile)菜单,选择“编译lt104.c”(Compile lt104.c)项后的编译结果如图1-7所示。

图1-7 编译结果
屏幕下面的调试信息窗口显示源程序编译结果:lt104.obj - 9 error(s),2 warning(s)。相关说明如下。
(1)调试中的错误主要分两类。一类是以error提示的致命错误必须修改,修改不通过则无法进入下一步生成目标文件;第二类是以 warning(警告)提示的轻微错误,不影响生成目标程序和可执行程序,但有可能影响运行的结果,需要具体问题具体分析。因此,对错误要尽量改正为“No error,No warning”。
(2)修订error和warning错误,通过信息提示栏右边的滚动条确认修订信息的详细内容,双击error行或warning行,即可在程序行左边出现小的蓝色方块,表示此处修改位置,如图1-8所示。对error和warning多次修改多次编译,一直到无错误提示。
5.程序构建
选择“编译”(Compile)菜单执行构件“lt104.exe”(Build lt104.exe)命令,仍然通过信息提示栏修订Error和Warning到无误为止。
6.程序运行
选择“编译”(Compile)菜单运行后缀为“.exe”的文件查看运行结果,正确的程序在 DOS窗口的运行结果如图1-9所示。

图1-8 编译信息提示与定位

图1-9 运行结果
注意
图1-9中的第二行“Press any key to continue”并非程序所指定的输出,而是Visual C++6.0在输出运行结果后系统自动加上的一行提示信息。
7.关闭程序重建程序
选择“文件”菜单(File)的“关闭工作区”(Close Workspace)命令关闭工作区,重复第1步操作新建文件。
关闭工作区是新建C程序的正确步骤;如果没有关闭工作区而是选择“文件”菜单下的“结束”命令,则仅仅结束工作区的主程序,而编译运行后的文件依然存在,即main函数并未关闭。这时新建C程序的main主函数,则新建的main主函数与未关闭的main主函数同时存在,链接和运行时程序错误信息提示栏都会提示Error。通常,明显的错误特征是Visual C++ 6.0的标题名和主工作区的文件名不一致,如图1-10所示。

图1-10 工作区与标题名不一致提示
C程序在Visual C++ 6.0编译环境运行的各个步骤会生成不同的文件,生成的文件具有不同的特性,详细内容见表1-1。
表1-1 C程序运行步骤的生成文件

1.5 C程序的设计开发流程
C程序的大小取决于其对应的功能。如果编写一个功能简单的程序,按照以上的程序运行步骤就足够了,但实际上有很多复杂的问题需要解决,需要更完善的C程序来运行,从而简化人工作业。从确定问题到最后完成任务,一般需要以下5个工作阶段。
① 问题分析。问题分析是第一道工序,也是基础工序,即分析给定的条件,确定最后要达到的目标,找出解决问题的规律,理清解题的思路,选择有效的解题方法,随时寻找可使问题规律化、科学化、简单化的解决方案,构建解决问题的模型(一般称为建模)。
② 设计算法。算法从广义上讲,就是为解决一个问题而采用的方法和步骤,可以选择成型的算法,如计算闰年的算法、求解三角形面积的公式等,否则需要改进算法或自行设计适合解决问题的算法。这时可以借助于流程图(将于第2章进行介绍)来表示。
③ 编写程序。根据选择的模型和设计的算法,选用程序设计语言编写解决问题的源程序。
④ 对源程序编译、链接和执行。对源程序编译、链接和执行,并分析运行结果。结果要全面,符合预期。
⑤ 编写文档。编写的文档应包括程序名称、程序功能、程序环境、程序的装入和启动、程序输入的数据、采用的算法、注意事项及操作步骤等内容。
本章小结
C语言是一种受欢迎、应用广泛的程序设计语言,其既有高级语言的特点,又具有汇编语言的特点;既是一个成功的系统设计语言,又是一个实用的程序设计语言;既能用来编写不依赖计算机硬件的应用程序,又能用来编写各种系统程序。
习题
1.查阅文献,了解C语言的详细发展过程及主要应用。
2.查阅文献,了解ANSI版本的变化。
3.查阅文献,了解K&R的标准与著作。
4.查阅文献,了解各种库函数保存的文件,打开文件了解里面的内容。
5.分别了解不同的C语言编译环境对C语言程序的保存、编译、构建(也称为组建)及运行结果。
6.运行C语言程序。在Visual C++ 6.0环境下运行本章的两个例题并了解相关步骤及错误修订过程。
7.选择本章中任意一个例题进行模仿改造,实现另外的功能。
8.有条件的学习者可安装Microsoft Visual Studio 2010,并在其中编译、构建和运行C程序,进而掌握其流程。