1.4 C语言

C语言是目前世界上广泛使用的通用计算机语言之一。使用C语言既可编写系统软件,也可编写各种应用软件,所以在数百种计算机语言中,C语言仍然是目前最流行、最受欢迎的计算机语言。

1.4.1 C语言的发展和特点

1. C语言的发展历程

C语言的最初设计与实现是由著名的计算机科学家Dennis Ritchie在UNIX操作系统环境下完成的,如图1-10所示。C语言起源于Basic Combined Programming Language(BCPL)语言。1970年美国贝尔实验室的Ken Thompson,如图1-11所示,以BCPL语言为基础,进行简化改进,设计出了接近硬件的B语言(取BCPL的第一个字母),并用B语言编写了第一个UNIX操作系统。1972年至1973年间,Dennis Ritchie在B语言的基础上设计出了C语言(取BCPL的第二个字母),并与Ken Thompson合作开发了C语言版的UNIX操作系统。

016-1

图1-10 Dennis Ritchie

016-1

图1-11 Ken Thompson

C语言的设计初衷是为了开发设计多用户、多任务的UNIX操作系统。随着UNIX操作系统的成功设计与日益广泛地应用,C语言也得到了迅速地推广。1978年以后,C语言已经先后移植到大、中、小型及微型计算机上,C语言发展成为通用的程序设计语言。现在C语言已经风靡全世界。

1978年,Brain W.Kernighan和Dennis Ritchie合著了影响深远的The C Programming Language一书,书中介绍的C语言是后来广泛使用的C语言版本的基础,它被称为标准C。1983年,美国国家标准化协会(American National Standards Institue,ANSI)根据C语言问世以来各种版本对C的发展和扩充,制定了新的标准,称为ANSI C。

1987年ANSI又公布了新的标准87 ANSI C。1990年国际标准组织(International Standard Organization,ISO)认可87 ANSI C为ISO C的标准。1999年,在做了一些必要的修正和完善之后,ISO发布了新的C语言标准,命名为ISO/IEC 9899:1999(1999年出版)。2011年,ISO发布了最新的C语言标准,命名为ISO/IEC 9899:2011(2011年出版)。至此,C语言的发展基本停止,直到今天几乎再没有什么变化。

在广泛流行的各种版本的C语言编译系统中,虽然其基本部分是相同的,但版本之间也略有差别。目前,在计算机上常使用的版本有Microsoft Visual C++(简称VC++)、Visual Studio、Dev C++,等等。

2. C语言的主要特点

C语言在很多方面继承和发扬了高级语言的成功经验和特色,如数据结构、多种存储类别、格式自由、模块化结构、参数传递方式以及结构化控制等。同时,C语言作为一种系统程序设计的工具,决定了它具有许多方面的特殊性。

(1)由于起初的C语言是面向系统程序设计的,因此,它十分注重效率。C语言的语言特征和计算机提供的功能相匹配,可读性远远胜于汇编语言,这样可以大幅度提高软件开发效率。C语言的表达非常简练,编译时又不做太多的安全检查,便于高效地生成高质量的目标代码。C语言基本上可以自由翻译,允许“隐式转换”,摆脱了数据表示需严格区分的约束,给编程者带来很大的方便。因为C语言追求高效率,所以C语言目标码的执行效率仅比汇编语言低10%~20%。其编译效率是其他高级语言所不能比拟的。

(2)由于追求高灵活性,所以C语言的规模不大,只有一个很小的内核,其强大的功能是通过函数库来实现的。

(3)因为C语言能够满足系统程序设计的一些底层要求,能够触及系统内部,可以反映计算机的硬件结构,如一块内存的申请、寄存器的位操作及逻辑运算等。所以,C语言除了具有高级语言的特点外,还具有汇编语言的能力,是一种介于汇编语言和高级语言之间的程序设计语言。这在目前的高级语言中是很特殊的,因此也有人将C语言称为中级语言。

以上的特殊性具体表现为C语言的如下特点。

(1)程序设计模块化。C语言是一种模块化的程序设计语言,而函数是C语言程序的基本单位。从结构上看,C语言程序是由一系列函数和外部变量声明构成的,一个源程序又是由多个代表程序段的文件组成的,这种程序的构造方法非常适合于模块化程序设计的要求。

(2)函数方式操作。C语言虽然只有10个基本语句,但可以通过函数方式,构造出许多使用者所需要的功能模块,如字符串运算、基本I/O操作等。使用这些函数,如同使用基本语句那样方便。

(3)数据类型多样化。C语言不但具有字符类型、整数类型和浮点数类型这些基本的数据类型,还具有指针、数组、结构和联合体等导出的数据类型。这种多样化的数据类型增强了程序对数据的处理能力。

(4)运算功能强。C语言中除了具有一般的高级语言使用的算术运算和逻辑运算外,还有位操作功能(按位与,按位或,按位非)。此外,C语言还有自加、自减运算(如x++、y−−、++z)以及组合运算(如+=,−=,*=)等。

(5)存储类型丰富。C语言对已定义的变量,可追加存储类型说明和定义。存储类型有函数内部的和函数外部的、有静态的和非静态的,也有寄存器变量和非寄存器变量等。存储类型说明还可以是复合说明,如静态外部变量、静态局部变量等。存储类型的说明表明了变量的作用域和存在时间的长短,即变量的可见性和寿命。变量的构造类型和存储类型同样可以用于函数定义,指明函数返回值的构造类型和存储类型。

(6)具有预处理能力。C语言有3种预处理:#include用于在程序某处插入事先设计的源程序文件,以达到共享某些具有通用性的源文件;#define用比较简短的标识符替代较长的字符串;另外还有条件编译#if、#ifdef等。这些功能给程序的组织和编译提供了便利。

(7)程序简洁。丰富的数据类型使数据的表示更加简练、紧凑;34种运算符能使表达式简短,如用“i++”表示“i=i+1”;用“&x”表示取x变量的地址;在程序书写上,用“{”和“}”代替begin、end;用“int”“char”代替integer、character;用宏定义可以缩写常数、变量、表达式、函数等。

1.4.2 C程序的基本结构

在深入学习C语言之前,让我们先通过一些简单的程序例子,初步了解C语言程序的基本结构和组成格式。

【例1-6】在屏幕上输出一行信息。

# include<stdio.h>
int  main()
{
    printf("输入理想的程序,输出快乐的人生!\n");
    return 0;
}

本程序的执行结果为:

输入理想的程序,输出快乐的人生!

其中main表示主函数,每一个C语言程序都必须有一个main主函数。主函数前面的int表示此函数的类型为整型。函数体由大括号{}括住,在上面的程序中函数体中只有“printf("输入理想的程序,输出快乐的人生!\n");”一条语句。其中,printf是C语言编译系统提供的函数库中的标准输出函数,其声明放在C语言编译系统提供的头文件“stdio.h”中。要在程序中使用系统提供的标准输出printf函数时,就需要通过“#include<stdio.h>”将其包含进来。“\n”代表换行符。这些知识将在后面的章节中进行详细介绍,读者一开始不必深究。

【例1-7】编写一个C语言程序,对键盘输入的任意3个整数求和。

#include <stdio.h>
int add(int a, int b, int c)    /*函数功能:计算3个整数相加之和*/      
{                               /*形式参数:整型变量a、b和c*/ 
    int d;                      /*定义本函数用到的变量d*/ 
    d=a+b+c;                    /*整型数据a、b和c的和放在d中*/ 
    return d ;                  /*将d的值作为函数add的返回值*/ 
} 
int main( )                     /*主函数*/ 
{ 
    int x, y, z, sum;                   /*定义4个整型变量x,y,z和sum*/ 
    printf("Input three integers:"); 
    scanf (" %d, %d, %d", &x, &y, &z);  /*输入3个整型数到x、y与z*/ 
    sum=add(x, y, z);                   /*调用函数add计算x、y与z之和*/ 
    printf("sum=%d\n", sum);            /*输出x、y与z之和*/ 
    return 0; 
}

在运行上面这个程序时,首先,屏幕上显示一条提示信息:

Input three integers:

要求用户从键盘输入3个整数。假设用户键入10、9和8,即

Input three integers:10,9,8↙

这里,符号↙表示按一下Enter键,表示数据输入的结束。此时,屏幕上显示如下信息:

sum=27

本程序中包含了两个函数:主函数main和一个被调用的函数add。add函数是一个具有相对独立功能的模块,其作用是对3个整数求和。在执行时主函数调用add函数,并将主函数中的3个整型变量x、y与z作为实参传给add函数的形参a、b与c,最后将add的计算结果d作为返回值赋给变量sum,然后输出到屏幕上。scanf是标准输入函数,其声明也包含在头文件“stdio.h”中。其作用是从键盘上输入3个数赋给变量x、y与z。“%d”表示在此位置上用一个十进制整数代替。各行右侧的“/*……..*/”是注释部分,注释内容写在“/*”和“*/”间,内容可以用汉字或其他语言的字符表示。

通过以上例子,我们可对C语言程序的结构做如下说明。

1. 函数是C语言程序的基本单位

C语言程序是由函数构成的,一个C语言程序必须有且仅有一个用main作为名字的函数,这个函数通常被称为主函数。C语言程序总是从main函数开始执行,而与它在程序中的位置无关。在有main函数的前提下,可以根据需要包含零到多个其他函数。函数可以是系统提供的库函数,如【例1-6】中的printf函数,也可以是用户自定义函数,如【例1-7】中的add函数。C语言的这个特点便于进行模块化程序设计。

2. 函数由函数首部和函数体两部分组成

(1)函数首部就是每个函数在定义或声明时的第一行,它包括函数名、函数类型、形参名、形参类型的说明,如例1-7中函数add的首部为:

  int      add (   int      a,    int     b,     int        c)
函数类型    函数名   形参类型   形参名

函数名后的形参必须用一对圆括号括起来,没有形参时一对圆括号也不能省略,它已成为函数的标志,如【例1-6】中对主函数main的定义。

(2)函数体由函数首部下面最外层的一对花括号中的内容组成,它可以包括变量声明和所调用函数的声明,还可以包括若干执行语句,声明部分可以看作是对函数中“对象”的描述,执行语句是对函数所要实现的“动作”的描述。特殊地,函数体中也可以什么都没有,成为一个空函数。例如:

void empty( )
{
}

3. C语言程序的书写格式与规则

(1)C语言程序中的每条语句和声明的最后都必须以分号作为结束标志,分号是C语句的必要组成部分。

(2)任何变量必须先定义类型,然后才能使用。

(3)C语言程序一般都使用小写英文字母,x与X代表不同含义。

(4)C语言程序的书写格式比较自由,既允许在一行内写多条语句,也允许将一条语句分写在多行上,而不必加任何标识。为了提高程序的可读性和可测试性,建议编程者在写程序的时候,一行内只写一条语句,养成良好的、规范的程序设计风格。

(5)C语言程序中有一些用“/*”和“*/”包含起来的内容,称为注释,是对程序功能的必要说明和解释。注释可以出现在程序的任何位置,但“/*”和“*/”必须配对使用。C语言编译器在编译程序时完全忽略注释,不对注释的内容进行语法检查,所以既可以用英文也可以用中文来书写注释内容,一行写不下时可以继续在下一行书写,只要是在一对“/*”和“*/”中间的内容都被当作注释来处理。写注释时应注意左斜线“/”和星号“*”之间不能留有空格。虽然有无注释并不影响程序的功能和正确性,但由于注释能起到“提示”代码的作用,有助于读者更快、更好地理解程序。因此,规范化程序设计提倡给程序添加必要的注释。

1.4.3 C程序的执行过程

用高级语言编写的程序被称为“源程序”,用C语言编写的程序被称为C语言源程序。C语言源程序不能在计算机上直接运行,C语言源程序的运行需要经过编辑、编译、连接及执行4个步骤,如图1-12所示。

016-1

图1-12 C语言程序的执行过程

(1)编辑:编辑是用户把编写好的C语言源程序输入计算机,并以文本文件的形式存放在磁盘上。其标识为:“文件名.c”。其中文件名是由用户指定的符合操作系统规定的任意字符组合,扩展名要求为“c”,表示是C源程序。例如,file1.c、li1.c等。

(2)编译:编译是把C语言源程序翻译成用机器语言表示的目标文件。编译过程由C语言编译系统提供的编译程序完成。编译程序自动对源程序进行句法和语法检查,当发现错误时,就将错误的类型和所在的位置显示出来,提供给用户,以帮助用户修改源程序中的错误。此时应重新进入编辑状态,对源程序进行修改后再重新编译,直到编译通过为止。如果编译通过就自动形成目标代码并对目标代码进行优化后生成目标程序文件。目标程序的文件标识是“文件名.obj”。这是系统规定的形式,扩展名“obj”是目标程序的文件类型标识。

(3)连接:程序连接过程是用系统提供的连接程序(也称链接程序或装配程序)将目标程序、库函数或其他目标程序连接装配成可执行的目标程序。可执行程序的文件名为“文件名.exe”,扩展名“exe”是可执行程序的文件类型标识。绝大部分系统生成的可执行文件的扩展名是“exe”。

有的C语言编译系统把编译和连接放在一个命令文件中,用一条命令即可完成编译和连接任务,减少了操作过程。

(4)执行:执行程序是指将可执行的目标程序投入运行,以获取程序处理的结果。如果程序运行结果不正确,可重新回到第一步,重新对程序进行编辑修改、编译和运行。与编译、连接不同的是,运行程序可以脱离语言处理环境。因为它是对一个可执行程序进行操作,与C语言本身已经没有联系,所以可以在语言开发环境下运行,也可直接在操作系统下运行。

必须指出,对不同型号计算机上的C语言版本,上机环境各不相同,编译系统支持性能各异,上述步骤有些可再分解,有些也可集成进行批处理,但逻辑上是基本相同的。