当前位置:文档之家› C语言速成教程

C语言速成教程


C语言速成教程
——教你如何10小时学会 C 语言









内容 page
■ 第一章 C 语言简介与Turbo C 的使用 2
■ 第二章 C 程序的结构 4
■ 第三章 常数与变数 10
■ 第四章 基本输出入函式 13
■ 第五章 流程图与抉择指令 21
■ 第六章 循环与自动重复 32
■ 第七章 数组与指针 40
■ 第八章 函数与呼叫 46
■ 第九章 档案存取 55










■ 第一章 C 语言简介与Turbo C 的使用

◎ C 语言的优点:
○ 效率高:C 语言的编译器会产生最小的程序代码。
○ 可移植性/移植性高:经过些许的修改,可以在不同的平台使用。
○ 功能强而有弹性。
○ 需要记忆的东西很少,易于写作。

◎ Turbo C 的安装:已安装在学校主机。
Turbo C 的环境设定:Turbo C 安装的目录必须设定在 PATH 的系统变量。
如: PATH=C:\TC;C:\DOS;...... 如此 TC 才能正常工作。

◎ Turbo C 的使用

只要设定好 PATH 变量,在 DOS 提示号输入 TC ,就可以执行 Turbo C 的
整合环境了。TC 将编辑(Edit)、编译(Compile)、连结(Link)、除错(Debug)、
档案管理(File)、...等等的功能整合在一起,所以我们称之为整合环境。
最好先用 CD 的指令,变更工作目录到你要写 C 的目录,再执行 TC,这样
所产生的档案,就会里这个目录里面,便于备份与管理。

◎ 移动光标
方向键 ←↑↓→ 可以用来移动光标。

◎ 删除文字
将光标移到你要删除的文字上,再按下 Del 键即可。
将光标移到要删除文字的右边,再按下 BS 退位键也可以。

◎ 加载文字文件(C 语言原始码文件)

按下功能键 F3 或 按 F10 选 File → Load 就会出现一个询问窗口要求输入文件名:

┌───── Load File Name ─────┐
│*.C │
└──────────────────┘
其中的文件名可以使用万用字符 * 或 ? ,或直接指定你要的檔名。
若是使用万用字符,TC 会再秀出一个窗口让你选择所要的档案,
你可以用方向键移动反白光棒,按 Enter 键则是选择反白的档案。

◎ 储存编辑的文字文件

按下功能键 F2 或 按 F10 选 File → Save 就会储存目前编辑档案。
若你想另外取一个档名,并加以存盘,就必须 按 F10 选 File → Write to
就会出现一个询问窗口要求输入文件名:

┌────── New Name ──────┐
│_ │
└──────────

────────┘
输入新的档名,按下 Enter 即可。

◎ 编译并执行目前的所编辑的程序
Turbo C 是一种编译语言系统,你所写的程序,经过 TC 的编译(pass 1)及
连结(pass 2)后,产生可执行档(.exe),才能在 PC 上执行。
按下 Ctrl + F9 或 按 F10 选 Run → Run ,TC 会编译目前所编辑的程序,
如果没有错误发生,TC 会立即执行所编辑的程序。
TC 在执行完程序后,会立刻切换回到 TC 的整合环境,如果你还想看刚才程序
执行的结果,可以按下 Alt + F5 或 按 F10 选 Run → User screen ,就会
切换到执行画面,再按下任何一键,就会回到 TC 的整合环境。

◎ 结束 Turbo C
按下 Alt + X 或 按 F10 选 File → Quit 便可结束 Turbo C。
若你还有已编修尚未储存的档案,TC 会问你要不要存。
╔══════ Verify ══════╗
║NONAME.C not saved. Save? (Y/N)║
╚════════════════╝
要存就按 Y ,不想存就按 N 。


■ 第二章 C 程序的结构

◎ C 程序的结构:
┌────────────┐
│hello.c │←─ 范例文件名
├────────────┤
1│#include │←─ 范例原始码
2│main() │
3│{ │
4│ printf("Hello!"); │
5│} │
├────────────┤
│Hello! │←─ 范例执行结果
└────────────┘

第一列: #include
是用来定义一些函式的原型(prototype)、数据结构(struct)或是常数(constant)。 C 在使用变量之前,该变量都要先行宣告(declear)才可使用,而使用函式也是一样,必须先宣告它的原型才可以。宣告函式的原型是为了让 C 能在编辑时作数据的型别检查,以减少错误的发生。 内建的函式原型定义都放在 INCLUDE\*.H 中,用 #include 就会将 INCLUDE\stdio.h 这个档引含。 stdio.h 由档名可知道是跟标准输出入(standard I/O)有关,档内定义了档案输出入、屏幕输出、键盘输入等相关函式的原型、数据结构及常数。 本例中的 printf() 就属于标准输出的函式。 引含 .h 档并不会让你的执行档变大或是变慢,而且还能让编辑器作正确的型别检查,所以要养成写 #include 的习惯。 ☆虽然在某些状况下,不加 #include <> 所产生的执行档,一样可以正常的执行。

第二列: main()
main() 就是主程序。程序在执行时,就是由这个函式开始执行。 在 C 语言中,内定的型别是 int ,所以原来的 main() 相当于是 i

nt main(int)
★ 在这里正确的写法应该是 void main(void), 因为在这个简单的程序中,没有回传值,也没有输入参数。
☆ 回传值,是指一个函式在执行后传回的数值。
☆ 输入参数,是指一个函式可由参数决定执行的结果,这个部分在第八章中有详细的说明。

第三列: {
第五列: }
在第三列及第五列之间,属于 main() 函式的程序代码。
{ 表示程序由此开始, } 表示程序到此结束。

第四列: printf("Hello!");
是本程序要求系统做动作的指令,称之为「叙述」。在 C 语言中,每一叙述都以分号(;)做为结束。 在这个程序中,利用缩排的方式,使程序的层次分明,增加可读性。
在 C 语言中,调位字符( 如:空白(space)、定位(tab)及换列字符 )在编译时都会被忽略,所以可适时加入调位字符,使程序好看一点。 要注意的是,别把一个完整的个体拆开,如:main、printf 等,这些字本身是一个完整的个体,不可予以拆开。而在各个个体之间,可以任意加入调位字符。
☆ C 语言中的英文字母是有分大小写的,printf() 与 PrintF() 不同, 内建的函式大多是小写的,你自己写的函式,则可以用大写来做区隔。

◎ printf 的功用
printf() 的功用是在屏幕上输出数据。在 TC 中,在编辑区内输入printf ,再将光标移到 printf 这个字上,按下 Ctrl + F1 就会看到以下Help画面:

┌────────── Help ───────────┐← 这是 TC 的 Help 窗口
│ │
│ printf: formatted output to stdout │← printf 是将格式化的
│ │ 数据输出到 stdout
│ int printf(const char *format, ...); │← printf 的语法
│ │
│ Prototype in stdio.h │← 要用 printf 应该
│ │ #include 的檔
│ Print formats a variable number of arguments │← 使用说明:不同的格式
│ according to the format, and sends the output │ 须要不同的参数,这些
│ to stdout. Returns the number of bytes output. │ 数据会送到stdout。传
│ In the event of error, it returns EOF. │ 回值是输出的byte数,
│ │ 若发生错误则传回 EOF
│ See also ecvt fprintf putc │← 可参考相关指令:
│ puts scanf vprintf │ ecvt,fprintf,putc,
│ │ puts,scanf,vprintf
└────────────────────────┘


在用 TC 的整合环境中,只要将光标移到想进一步了解的指令或内建的函式上,按 下 Ctrl + F1 就可以叫出 TC 的 Help 说明窗口,得到该指令或函式的相关说明。

printf 的语法: int printf(const char *format, ...);
其中 const char *format 指的是一个格式化的字符串。 const 是常数的意思,在此表示 format 这个字符串指针传入 printf 函式后,它的值不会被改变。
... 指的是不定参数,参数的数目取决于 format 字符串的内容,这些参数,通常是一些你要秀出来的变量。 简单来说: printf( "输出格式(含控制字符串)" , 要印出的数据 );
在 C 语言中是用双引号(")来引含字符串,也就是在双引号内的数据,是一个字符串。本章只介绍 %d 这个控制字符串,其它的控制字符串在第四章会讲到。 %d 表示以整数 10 进位的方式秀出数据。在输出格式(含控制字符串) 内有几个%d ,在要印出的数据内就要有几个整数来对应。



┌────────────────────────────────┐
│arith.c │
├────────────────────────────────┤
1│#include
2│void main(void) │
3│{ │
4│ printf("%d + %d = %d\n", 8 , 2 , 8+2 ); │
5│ printf("%d - %d = %d\n", 8 , 2 , 8-2 ); │
6│ printf("%d * %d = %d\n", 8 , 2 , 8*2 ); │
7│ printf("%d / %d = %d\n", 8 , 2 , 8/2 ); │
8│} │
├────────────────────────────────┤
│8 + 2 = 10 │
│8 - 2 = 6 │
│8 * 2 = 16 │
│8 / 2 = 4 │
└────────────────────────────────┘

我们以第四列的叙述作说明:

printf("%d + %d = %d\n", 8 , 2 , 8+2 );
↑ ↑ ↑ │ │ │
│ │ └───│──│──┘
│ └─────│──┘
└────────┘
在 输出格式(含控制字符串) 内有 3 个 %d ,所以在 要印出的

数据 的部分有
8 , 2 , 及 8+2 三个整数对应,所以输出来的结果就是

8 + 2 = 10

在 输出格式(含控制字符串) 的最后有 \n 符号,这是一个控制字符,表示要
更换到下一列,其它的控制字符在第四章会提到。
若将本例中的 \n 都删除,那秀出的结果会像这样子:

8 + 2 = 108 - 2 = 68 * 2 = 168 / 2 = 4


◎ C 的四则运算

计算机语言用的四则运算符号几乎都是相同的:

四则运算符号 意 义 范 例 结 果
============ ===================== ============== ==========
+ 加法 4 + 2 6
- 减法 ( 或代表负号 ) 4 - 2 2
* 乘法 4 * 2 8
/ 除法 4 / 2 2
============ ===================== ============== ==========
相关运算符号 意 义 范 例 结 果
============ ===================== ============== ==========
++ 变数值加 1 i++ 或 ++i i 值加 1
-- 变数值减 1 i-- 或 --i i 值减 1
% 整数除法的余数 4 % 2 0
============ ===================== ============== ==========

在书中提到 C 语言没有提供次方的功能,指的是在某些计算机语言可以用 ** 表示
次方,如: 2 ** 3 ,表示 2 的 3 次方;有的用 ^ 表示,如: 2 ^ 8 ,表示
2 的 8 次方。在 C 语言,没有运算符号可以表示次方,但是 C 语言有提供次方
的函式: pow(), pow( 2 , 3 ) 表示 2 的 3 次方。

一个式子如果有多个运算的话,C 是以先乘除后加减的方法来运算,当然我们也
可以用括号 ( ) 来改变这个法则,只要有括号,就优先运算。另外,在 C 语言内
中括号 [ ] 及 大括号 { } 是有其它的用途,所以在作数学运算时,只要用括号
,就只能用小括号 ( ),小括号可以多层,C 在运算时,是由最内层开始运算。

范例: ( 1 + 2 * ( 3 + 4 ) ) * 5 - 6 * 7 / 2 + 8
= ( 1 + 2 * ( 7 ) ) * 5 - 6 * 7 / 2 + 8
= ( 15 ) * 5 - 6 * 7 / 2 + 8
= 75 - 42 / 2 + 8
= 75 - 21 + 8
= 62

◎ 批注(Comments)

通常老师会要求初学者在程序的每一列加上批注,这是为了让初学者知道自己在写些什么程序代码,了解为什么要这样写,而不只是照著书 Keyin 程序。写批注有助于自己了解程序的内容,便于日后的修改。但写

批注对于某些程序设计师而言可说是一种噩梦,因为写批注所花的时间可能会与写程序的时间相去不远,认为写批注只是在浪费时间。 对一个相当好的程序设计师而言,也许写批注真的是浪费时间,因为好的程序代码本身就已经隐含了批注,这也是写程序相当高的境界。 对一般的程序设计师而言,写一些批注还是比较好的作法,特别是某些程序代码是你花了一段时间才想到的「特殊」方法,加上一些批注,说明一下这个「特殊」的方法,以后要修改才能快速进入状况,否则,你可能会佩服自己当时是如何想到的这个方法,又再花一段时间才知道自己在写些什么程序代码。 讲了这么多批注的正反面(正面居多)论调,在 C 语言中要如何写批注呢? 只要用 /* 和 */ 将你要的批注内容包起来就可以了。C 在编译时,会将 /* */ 内的数据略去,就如同调位字符一样。唯一的例外是:当 /* */ 在一组双引号 " 内时,它们就属于这组双引号所包含的字符串。 在 C++ 语言中则可用//当批注.

┌────────────────────────────────┐
│comments.c or comments.cpp │
├────────────────────────────────┤
1│#include /* prototype : printf() */ │
2│void main(void) // main program │
3│{ │
4│/* 所有的程序代码都变成批注,所以这个程序目前是空的 */ │
5│/* printf("%d + %d = %d\n", 8 , 2 , 8+2 ); */ │
6│/* printf("%d - %d = %d\n", 8 , 2 , 8-2 ); │
7│ printf("%d * %d = %d\n", 8 , 2 , 8*2 ); │
8│ printf("%d / %d = %d\n", 8 , 2 , 8/2 ); // division │
9│*/ │
10│} // end of program │
├────────────────────────────────┤
└────────────────────────────────┘


◎ 巢状批注(Nested Comments)

┌────────────────────────────────┐
│nestcom0.c │
├────────────────────────────────┤
1│#include /* prototype : printf() */ │
2│void main(void)


3│{ │
4│/* 这个程序必须把巢状批注的设定打开,才不会有错误 */ │
5│/* │
6│ printf("%d + %d = %d\n", 8 , 2 , 8+2 ); │
7│/* printf("%d - %d = %d\n", 8 , 2 , 8-2 ); */ │
8│ printf("%d * %d = %d\n", 8 , 2 , 8*2 ); │
9│ printf("%d / %d = %d\n", 8 , 2 , 8/2 ); │
10│*/ │
11│} │
├────────────────────────────────┤
└────────────────────────────────┘

上面的例子,有四组批注 /* */ ,其中第三组及第四组的批注之间有部分重迭。
想要 Compile 没有错误,必须第 5 列的 /* 与 第 10 列的 */ 配,也就是
第 5 列到第 10 列都是批注;另外第 7 列的 /* 与 第 7 列的 */ 配,也就是
第 7 列是批注。这种批注方式,我们称之为巢状批注。
Turbo C 内定是不可使用巢状批注的,上面的例子会是第 5 列的 /* 与 第 7 列
的 */ 配,结果在第 10 列的 */ 会变成是多余的,造成 Compile 错误。
打开巢状批注的方法:
按下 F10 → Options → Compiler → Source → Nested comments Off
将 Off 设为 On 就可以了。

◎ 巢状批注的使用时机

在前面的例子只是为了说明巢状批注,也许你会觉得这样的用法是自找麻烦,
但是以下的例子,你就会认为有巢状批注的功能还是比较好的。
在 nestcom1.c 中,每一列的 printf(); 后面都加上了批注。
若要把这几列程序变成批注,不使用巢状批注,就会像 nestcom2.c 一样,
必须在每一列的 printf(); 前后再加上 /* */,若是使用巢状批注,
就像 nestcom3.c 一样,只要在这几列的前后加 /* */ 就可以了。

┌────────────────────────────────┐
│nestcom1.c │
├────────────────────────────────┤
1│#include /* prototype : printf() */ │
2│void main(void) │
3│{ │
4│ /* 这个程序在每一个叙述后都加上了批注 */ │

5│ │
6│ printf("%d + %d = %d\n", 8 , 2 , 8+2 ); /* 8 + 2 = 10 */ │
7│ printf("%d - %d = %d\n", 8 , 2 , 8-2 ); /* 8 - 2 = 6 */ │
8│ printf("%d * %d = %d\n", 8 , 2 , 8*2 ); /* 8 * 2 = 16 */ │
9│ printf("%d / %d = %d\n", 8 , 2 , 8/2 ); /* 8 / 2 = 4 */ │
10│ │
11│} │
├────────────────────────────────┤
└────────────────────────────────┘


┌────────────────────────────────┐
│nestcom2.c │
├────────────────────────────────┤
1│#include /* prototype : printf() */ │
2│void main(void) │
3│{ │
4│/* 这个程序不用把巢状批注的设定打开,也不会有错误 */ │
5│ │
6│/* printf("%d + %d = %d\n", 8 , 2 , 8+2 ); */ /* 8 + 2 = 10 */ │
7│/* printf("%d - %d = %d\n", 8 , 2 , 8-2 ); */ /* 8 - 2 = 6 */ │
8│/* printf("%d * %d = %d\n", 8 , 2 , 8*2 ); */ /* 8 * 2 = 16 */ │
9│/* printf("%d / %d = %d\n", 8 , 2 , 8/2 ); */ /* 8 / 2 = 4 */ │
10│ │
11│} │
├────────────────────────────────┤
└────────────────────────────────┘
┌────────────────────────────────┐
│nestcom3.c │
├────────────────────────────────┤
1│#include /* prototype : printf() */ │
2│void main(void) │
3│{ │
4│/* 这个程序也必须把巢状批注的设定打开,才不会有错误 */ │
5│/* │
6│ printf("%d + %d = %d\n", 8 , 2 , 8+2 )

; /* 8 + 2 = 10 */ │
7│ printf("%d - %d = %d\n", 8 , 2 , 8-2 ); /* 8 - 2 = 6 */ │
8│ printf("%d * %d = %d\n", 8 , 2 , 8*2 ); /* 8 * 2 = 16 */ │
9│ printf("%d / %d = %d\n", 8 , 2 , 8/2 ); /* 8 / 2 = 4 */ │
10│*/ │
11│} │
├────────────────────────────────┤
└────────────────────────────────┘



■ 第三章 常数与变数

C 语言的数据可分为常数(constant)及变量(variable),常数指的是固定不变的数,
例如:0,1,2 等数值,或是用双引号定义的字符串,我们也称之为字符串常数。
变量指的是数值可以改变的数,例如:一个整数变量,我们可以把它设成 1,然后再
改为 10,或是其它的整数数值。
一个程序若没有变量,那纯粹只是将常数秀出来而已,好比是用文字编辑器编辑一个
档案,再用 type 把它秀出来一样。有了变量,就可以做不同的变化。

◎ 变量的型态──Char, int, long, float, double etc.。

◎ 变数的命名

如同档案的命名,变量的名字要取得有意义,在 C 中,名字可以取得很长,但是
要用英文的,所以你可以把变量用中翻英来命名。

◎ 变量的命名规则

○ 变量名称的第一个字符必须是英文字母(A 到 Z 或 a 到 z)或是底线( _ )。
○ 第二个字符以后可以使用前述字符,再加上数字 0 到 9 。
○ 变量名称的大小写是不同的。
○ 变量名称的最前面 32 个字符有效。
○ 不可以使用「保留字」当变量的名称,保留字是给编译器使用,不可以当成
变量名称。TC 有以下的保留字:

流程: if else for do while
switch default case break continue
goto return
型别: char int long float double
void register signed unsigned
short near far huge
typedef struct union enum
auto const static volatile extern
interrupt cdecl pascal asm
运算: sizeof
缓存器: _AX _AH _AL _cs _CS
_BX _BH _BL _ds _DS
_CX _CH _CL _es _ES
_DX _DH _DL _ss _SS
_SI _DI _BP _SP

◎ 变量的设定

使用变量时,应该先考虑这个数可能的数值范围,用

以选定变量的型别,例如:
用一个数来存班上的人数,一个合班的大班级可能超过百人,但最大不太可能
超过千人,所以选一种变量型别可存 1000 以下的数值,在此可选整数。
若是要用一个数来存你的存款,则整数的上限 32767 可能某些同学一个月的薪资
就是它的数倍,所以要选长整数,它的上限是 2147483647 。在数学运算时,
想要有小数的就要用浮点数(float)。
在 C 语言中,变量宣告的语法如下:

┌────────────────────┐
│ 型别 变量名称1 [,变量名称2 [,...]] ; │
└────────────────────┘

例如: int NumberOfStudent; /* 学生人数 */
long MoneyInBank, interest; /* 银行存款 */
float RateOfInterest; /* 利息利率 */
char EndOfString; /* 字符串结束 */
char OneStudentName[9]; /* 学生姓名 */

在宣告变量时,我们可以设定变量的初始值(initial value),语法如下:

┌────────────────────────────┐
│ 型别 变量名称1=初始值1 [,变量名称2=初始值2 [,...]] ; │
└────────────────────────────┘

例如: int NumberOfStudent=60; /* 学生人数 */
long MoneyInBank=1000000L; /* 银行存款 */
float RateOfInterest=5.0; /* 利息利率 in % */
char EndOfString='\0'; /* 字符串结束 */
char OneStudentName[9]="王大明"; /* 学生姓名 */

注意: 在银行存款的设定数值 1000000 后加上一个 L ,表示这个常数数值
1000000 是一个长整数。因为 C 语言内定的型别是整数,为了防止
不可预期的状况发生,最好是自己把它设定成你想要的型别,不要
假设 TC 会帮你做好好的,要假设 TC 很笨不会帮你做,这样在发展
大程序要除错时,就可以把问题简化,不必再考虑是不是数据型别错误,
只要把程序流程或算法搞定就可以了。
在 TC 中,不加 L,结果还是正确的,但是在其它的环境下可能会不同。
多加一个 L 并不会使程序变大或变慢,又能保障正确使用,何乐不为。

○ 复习一下字符与字符串:

char 字符只占一个 byte,以一组单引号 ' 引含字符数据,其表示法如下:
⊙ 单一字符: 'A' 、'a' 、'0' 。
⊙ 八进制数值: '\101'、'\141'、'\60' 、'\0'

⊙ 十六进制数值: '\x41'、'\x61'、'\x30'、'\x0'

字符串则是由一个以上的字符所组成的,而且以 '\0' 这个字符做为结尾。
表示法: "123"、"ABC"、"abc"。以上的三个例子都是占 4 bytes。
用 strlen() 可以取得字符串的长度(不含 '\0' 字符)。
如: int StringLen=strlen("123");
这样,StringLen 就等于 3 。
☆ 在使用 strlen() 时,必须加入 #include

◎ 设定叙述

前面已经说明了变量在宣告时给定初值的方法,接下来是在程序执行的过程中设定变量数值的方法。 即然是变量,表示它的数值可能在程序执行的过程中会改变多次,如果一个变量在整个程序执行中都不会改变,或许你该把它设成常数。
在设定变量时,可以用等号 = 来设定变量新值,语法如下:

┌────────────────────────────┐
│ 变量名称 = 表达式(表达式、函式传回数值或两者混合); │
└────────────────────────────┘

这个意思是等号左边「变量名称」的数值会等于等号右边「表达式」的运算结果。
在 C 中,等号 = 是用来设定变量数值的,所以在等号的左边必须是变量,不可以
是常数。在逻辑上的相等,在 C 中是用两个等号 == 来表示,有关逻辑的表示,
在第五章中会作介绍。以下我们来看一些设定的例子,计算圆的面积:

PI = 3.1415926;
r = 4;
area = PI * r * r ;

以下是用变量的方式表示的范例:
┌────────────────────────────────┐
│var.c │
├────────────────────────────────┤
│#include
│void main(void) │
│{ │
│ int i,j; │
│ │
│ i = 10; │
│ j = 2; │
│ printf("%d + %d = %d\n", i , j , i+j ); │
│ printf("%d - %d = %d\n", i , j , i-j ); │
│ printf("%d * %d = %d\n", i , j , i*j ); │
│ printf("%d / %d = %d\n", i , j , i/j ); │


│ i = 20; │
│ j = 2; │
│ printf("%d + %d = %d\n", i , j , i+j ); │
│ printf("%d - %d = %d\n", i , j , i-j ); │
│ printf("%d * %d = %d\n", i , j , i*j ); │
│ printf("%d / %d = %d\n", i , j , i/j ); │
│} │
├────────────────────────────────┤
│10 + 2 = 12 │
│10 - 2 = 8 │
│10 * 2 = 20 │
│10 / 2 = 5 │
│20 + 2 = 22 │
│20 - 2 = 18 │
│20 * 2 = 40 │
│20 / 2 = 10 │
└────────────────────────────────┘


变量使用的有效范围:

整体变量(Global Variable): 整体程序内
区域变量(Local Variable):函式内
静态变量(Static Variable): 单一程序内



■ 第四章 基本输出入函式

这一章将介绍一些基本输出入的函式,使用者经由这些函式可以与计算机沟通,让程序读取使用者的输入部分。程序依使用者不同的要求,做不同的事,再将结果输出给使用者。

◎ 输出指令:printf()

在第二章中,曾经谈过 printf 指令,现在来详细的探讨它。
printf是一种格式化的输出指令,换句话说,你可以用它来编排你所要的输出格式。printf 的一般型式如下:

┌────────────────────────────┐
│ printf("控制字符串" , 表达式1 , 表达式2 , ... ); │
└────────────────────────────┘

控制字符串是你打算要秀出的讯息,其中利用 % 与 \ 这两个字符,来控制数值的
输出格式。
控制字符串中每一个 % 符号,表示在后面有一个表达式与它对应,表达式的值会代
入这个 % 的位置。在 % 后的字符表示代入数的型别,常用的句柄如下表:

┌────────┬──────────┐
│printf 的句柄 │ 代表代入的数值型别 │
├──

──────┼──────────┤
│%c │ 字符 │
│%d │ 十进制之整数 │
│%ld │ 十进制之长整数 │
│%f │ 浮点数 │
│%lf │ 倍精浮点数 │
│%Lf │ 长倍精浮点数 │
│%s │ 字符串 │
└────────┴──────────┘

表达式的型别必须跟句柄所代表的型别相符,否则会秀出不可预期的资料。
另一个控制符号 \ ,其实只是定义字符而已。在上一章已经介绍了字符的各种表
示法,如:'\x41' 表示 A 字符。
在 C 语言中,将一些特殊的控制字符另外定义,这些控制字符大部份跟光标的
控制有关,如下表:

┌────┬──┬──┬───────────────┐
│控制字符│Dec │Hex │功能 │
├────┼──┼──┼───────────────┤
│\n │ 10 │0x0A│换列,也就是将光标移到下一列 │
│\t │ 9 │0x09│将光标移到下一个定位(1+8n) │
│\b │ 8 │0x08│退一格,类似按下左键 │
│\a │ 7 │0x07│喇叭叫一声 │
│\r │ 13 │0x0D│回到列首 │
│\f │ 12 │0x0C│跳页,在列表时控制列表机跳页 │
│\\ │ 92 │0x5C│印出 \ 字符 │
│\' │ 39 │0x27│印出 ' 字符 │
│\" │ 34 │0x22│印出 " 字符 │
│\xHH │ │0xHH│印出 0xHH 所表示的字符 │
*│%% │ 37 │0x25│印出 % 字符 │
└────┴──┴──┴───────────────┘

其中,% 字符的定义与在控制字符串中的表示法不同,其余的字符在定义上与在控制
字符串中的表示法都相同。
printf 在做输出时,你也可以指定保留多少位置给对应的表达式放结果。指定的
方式是在 % 之后加一个数值,如 %5d:表示保留 5 个字符空间给一个十进制整数;
%12ld:表示保留 12 个字符空间给一个十进制长整数。
如果要输出数据的长度比你指定的保留空间还要大时,printf 就不理会你的设定,
把要输出的数据完整的输出,所以,你在设定保留空间时,应该注意输出数据的范围
及长度,保留够大的空间,确保输出格式的整齐。
在浮点数方面,你除了可以指定

保留的空间外,还可以指定小数点后要取几位。
如 %8.3f :表示保留 8 个字符空间给一个浮点数,小数部分则是占 3 个字符空间
,由于小数点本身占一个字符,所以整数部分占 8 - ( 3 + 1 ) = 4 个字符空间。
printf 在输出数据时,如果你指定保留的空间比要秀的数据长度还要大时,那
printf 先秀一些空白,再秀出数据,使总长度等于你所指定的宽度,这样等于是
让输出的数据向右对齐。如果你想要让数据是向左对齐的话,可以在指定宽度时
使用负数,如 %-5d:表示保留 5 个字符空间给一个十进制整数,若数据长度不足
5 ,则在秀出资料后补空白。

○ 整数(int)及长整数(long)
┌─────────────────────────────┐
│ % - + w d → int │
│ % - + w ld → long │
│ ↑ ↑ ↑ │
│ │ │ └─── 若有指定,则保留 w 个字符 │
│ │ │ 若无指定,秀出长度将由数据决定 │
│ │ └───── 若有指定,则一定会秀出正负号 │
│ │ 若无指定,则只有负数会秀出负号 │
│ └────── 若有指定,则向左对齐 │
│ 若无指定,则向右对齐 │
└─────────────────────────────┘

○ 浮点数(float)、倍精浮点数(double)及长倍精浮点数(long double)
┌─────────────────────────────┐
│ % - + w . p f → float │
│ % - + w . p lf → double │
│ % - + w . p Lf → long double │
│ ↑ ↑ ↑ ↑ │
│ │ │ │ └─ 若有指定,则保留 p 个字符给小数 │
│ │ │ │ 若无指定,内定是保留 6 个字符给小数 │
│ │ │ └─── 若有指定,则保留 w 个字符含小数及小数点 │
│ │ │ 若无指定,秀出长度将由数据决定 │
│ │ └───── 若有指定,则一定会秀出正负号 │
│ │ 若无指定,则只有负数会秀出负号 │
│ └────── 若有指定,则向左对齐 │
│ 若无指

定,则向右对齐 │
└─────────────────────────────┘

说了这么多,只有自己试试看才知道!以下是个简单的例子:
┌─────────────────────────────────┐
│print.c │
├─────────────────────────────────┤
1│#include
2│void main(void) │
3│{ │
4│ printf("|%ld|\n", 123456 ); │
5│ printf("|%5ld|\n", 123456 ); │
6│ printf("|%d|\n", 123 ); │
7│ printf("|%5d|\n", 123 ); │
8│ printf("|%-5d|\n", 123 ); │
9│ printf("|%f|\n", 12.345 ); │
10│ printf("|%9f|\n", 12.345 ); │
11│ printf("|%9.2f|\n", 12.345 ); │
12│ printf("|%-9.2f|\n",12.345 ); │
13│} │
├─────────────────────────────────┤
│|123456| ← 123456 大于 32767 要长整数才能表示,所以用 %ld│
│|123456| ← 所保留的 5 个字符不够使用,所以 TC 视同你没设│
│|123| │
│| 123| ← 保留 5 个字符,只使用 3 个字,向右靠齐 │
│|123 | ← 保留 5 个字符,只使用 3 个字,向左靠齐 │
│|12.345000| ← 小数没有指定,所以 TC 使用内定的 6 个小数。 │
│|12.345000| ← 保留 9 个字符,小数部分仍使用内定值 │
│| 12.35| ← 保留 9 个字符,小数 2 个字符,向右靠齐 │
│|12.35 | ← 保留 9 个字符,小数 2 个字符,向左靠齐 │
└─────────────────────────────────┘

◎ 输入指令:scanf()

C 语言使用 scanf 指令来读取keyboard输入的数据。scanf 的一般型式如下:

┌────────────────────────────┐
│ scanf("控制字符串" , &

变量1 , &变量2 , ... ); │
└────────────────────────────┘

scanf 与 printf 可以说是相对的,一个用来做输入,一个用来做输出。
scanf 的控制字符串与 printf 几乎是一样。

┌────────┬──────────┐
│scanf 的句柄 │ 代表输入的数值型别 │
├────────┼──────────┤
│%c │ 字符 │
│%d │ 十进制之整数 │
│%ld │ 十进制之长整数 │
*│%D │ 十进制之长整数 │
│%f │ 浮点数 │
│%lf │ 倍精浮点数 │
│%Lf │ 长倍精浮点数 │
│%s │ 字符串 │
└────────┴──────────┘
★ 注意:没有 %F 这种句柄,课本有误!
%D 的句柄只能用在 scanf() ,在 printf() 中无法使用。

在用 scanf 时还有一点要注意,在控制字符串后的变量,使用的是指针(pointer)。
什么是指标?指针就是指向内存的一个地址,在那个地址存放着数据。
例如:一个整数变量 i ,它是存在内存的某一个地址,那个地址在 C 语言中,
是以 &i 来表示,我们通常称 &i 是 i 的地址,也称为 i 的指标。
以下是常用的变量及其指针(因为它的地址固定不会改变,也称为指标常数):

┌──────────────────────────────────┐
│char c; /* 字符 */ /* c 的指针是 &c */ │
│int i; /* 整数 */ /* i 的指标是 &i */ │
│long l; /* 长整数 */ /* l 的指标是 &l */ │
│float f; /* 浮点数 */ /* f 的指标是 &f */ │
│double d; /* 倍精浮点数 */ /* d 的指标是 &d */ │
│long double ld; /* 长倍精浮点数 */ /* ld 的指标是 &ld */ │
│ │
│char str[80]; /* 字符数组(字符串) */ /* str[80] 的指标是 str */ │
│int a[100]; /* 整数数组 */ /* a[100] 的指标是 a */ │
│long b[100]; /* 长整数数组 */ /* b[100] 的指标是 b */ │
│float c[100]; /* 浮点数数组 */ /* c[100] 的指标是 c */ │
└──────────────────────────────────┘

以下的范例,将第三章的

范例var.c 变量改由 scanf 输入:
┌────────────────────────────────┐
│io.c │
├────────────────────────────────┤
1│#include
2│void main(void) │
3│{ │
4│ int i,j; │
5│ │
6│ printf("Enter 2 integers:"); │
7│ scanf("%d %d", &i, &j ); /* 用 i 与 j 的指标 &i,&j */ │
8│ printf("Now, I find that ...\n"); │
9│ printf("%d + %d = %d\n", i , j , i+j ); │
10│ printf("%d - %d = %d\n", i , j , i-j ); │
11│ printf("%d * %d = %d\n", i , j , i*j ); │
12│ printf("%d / %d = %d\n", i , j , i/j ); │
13│} │
├────────────────────────────────┤
│Enter 2 integers:20 4 ← 相当于 i = 20 , j = 4 │
│Now, I find that ... │
│20 + 4 = 24 │
│20 - 4 = 16 │
│20 * 4 = 80 │
│20 / 4 = 5 │
└────────────────────────────────┘

scanf 在读取多笔数据时,是把调位字符(如:空白、定位(tab)及换列字符)当
作数据的分隔的记号,也就是利用 scanf 输入多笔数据时,必须用调位字符
分隔输入的数据。如本例中,输入的 i 值与 j 值,可以用空白区隔,也可以用
换列或定位来区隔。在结束输入时则要用换列字符,也就是说要按 Enter 。

进阶的程序设计师通常不会用 scanf 作为数据的输入,因为只要输入的格式有
一点点错误, scanf 所得到的结果就无法预期。大部分的程序设计师会用
gets() 这个函式读入字符串,gets 是以换列字符作为结束记号,所以,利用
gets 可以读入包含空白及定位的字符串。读入的字符串可以用 atoi() 转成整数、
用 atol() 转成长整数、用 atof()

转成浮点数。
更进阶的程序设计师则是自行设计输入函式,并加入一些设定防止输入错误发生,
例如,在输入整数的函式中,使用者只有按下数字键才有反应,若按下非数字键,
则不会反应。也可以限定使用者输入的数据长度,防止输入的数值过大,等等。


以下的范例,将华氏温度(℉)换算成摄氏温度(℃)
┌────────────────────────────────┐
│f2c.c │
├────────────────────────────────┤
1│#include
2│void main(void) │
3│{ │
4│ int f,c; │
5│ │
6│ printf("Enter the temperature in F : "); │
7│ scanf("%d", &f ); /* 用 f 的指标 &f */ │
8│ c = ( f - 32 ) * 5 / 9 ; /* 换算公式 */ │
9│ printf("%d degrees in F is %d degrees in C.", f, c); │
10│} │
├────────────────────────────────┤
│Enter the temperature in F : 100 │
│100 degrees in F is 37 degrees in C. │
└────────────────────────────────┘

华氏温度(℉)与摄氏温度(℃)的互换公式如下:

C = ( F - 32 ) * 5 / 9
F = C * 9 / 5 + 32

以下是课本的范例,将年纪改用"日"来估算:
┌────────────────────────────────┐
│age.c │
├────────────────────────────────┤
1│#include
2│void main(void) │
3│{ │
4│ float years, days; │
5│ │
6│ printf("Enter the age of you : "); │
7│ scanf("%f", &years ); /* 用 years 的指标 &year

s */│
8│ days = years * 365.25 ; /* 换算公式 */│
9│ printf("You are %f days old.", days ); │
10│} │
├────────────────────────────────┤
│Enter the age of you : 28.5 │
│You are 10409.625000 days old. │
└────────────────────────────────┘

◎ 输入指令:getche()

使用 scanf() 读取字符时,必须再按下 Enter 键,该字符才会被读取。
在某些场合中,我们希望每按一个键,程序就会读取,不用再按下 Enter 键,
例如:在计算机游戏中,每按下方向键,所控制的人物就依所按的方向移动。
利用 getche() 可以达到这个目的。 getche 的一般型式如下:

┌────────────────────────────┐
│ ch = getche(); │
└────────────────────────────┘

将 getche() 所读到的字符传给 ch 。此外,getche() 会将读到的字符先秀在
屏幕上。

以下的范例,将所按的键秀出其 ASCII 码:
┌────────────────────────────────┐
│code.c │
├────────────────────────────────┤
1│#include /* 宣告 printf() 的原型 */ │
2│#include /* 宣告 getche() 的原型 */ │
3│void main(void) │
4│{ │
5│ char ch; │
6│ │
7│ ch = getche(); /* getche() 会传回你所按下键的字符 */ │
8│ printf(" -- You typed %c.\n", ch ); │
9│ printf("Character %c has ASCII code %d.\n", ch, ch ); │
10│} │
├────────────────────────────────┤
│A -- You typed A. │
│Character A has ASCII code 65. │
└─────────────────────

───────────┘
这个范例主要是用来查询一般字符的 ASCII 码,请勿输入方向键,否则它的结果
可能会让你失望。因为方向键及功能键等特殊按键会产生两个码,必须读两次
才能得到正确的结果。
第 9 行,用 %c 的控制字符,表示要秀出 ch 所代表的字符;
用 %d 的控制字符,表示要秀出 ch 所代表的数值。


☆★☆★☆★☆★ 练习 ☆★☆★☆★☆★

实作课本习题第 10 题,看看你所得到的结果与课本所列的的结果一不一样?

☆★☆★☆★☆★ 作业 ☆★☆★☆★☆★


■ Help参考数据:

┌────────── Help ───────────┐
│ printf: formatted output to stdout │格式化输出至 stdout
│ │
│ int printf(const char *format, ...); │printf 的语法
│ │
│ Prototype in stdio.h │必须 #include
│ │
│ Print formats a variable number of arguments │不同的格式须要不同的
│ according to the format, and sends the output │参数,这些数据会送到
│ to stdout. Returns the number of bytes output. │stdout。传回值是输出
│ In the event of error, it returns EOF. │的byte数,若发生错误
│ │则传回 EOF
│ See also ecvt fprintf putc │
│ puts scanf vprintf │相关指令
└────────────────────────┘
┌────────── Help ───────────┐
│ Format Specifiers │format 的格式
│ │
│ % [flags] [width] [.prec] [F|N|h|l] type │[ ] 表示不一定要用
│ │
│ type Format of Output │格式化输出的型别:
│ d signed decimal int │d 带正负号十进制整数
│ i signed decimal int │i 带正负号十进制整数
│ o unsigned octal int │o 不带正负号八进位整数
│ u unsigned decimal int │u 不带正负号十进制整数
│ x in printf = unsigned hexdecimal int │x 不带正负号16进位整数(小写)
│ lowercase; in scanf = hexadecimal int │ 在 scanf 为16进位整数
│ X in printf = unsigned hexdecimal int │X 不带正负号16进位整数(小写)
│ uppercase; in scanf = hexadecimal long │ 在 scanf 为16进位长整数
│ f floating point [-]dddd.

相关主题
文本预览
相关文档 最新文档