搜索
您的当前位置:首页正文

C语言专升本考试试题

来源:意榕旅游网
 C语言程序设计详解 1

第一章 C语言程序设计初步

一、主要知识点

(一) 程序设计语言的发展

1、机器语言 2、汇编语言 3、面向过程的语言 4、面向对象的程序设计语言

(二) C程序设计语言的执行过程

1、编辑 2、编译 3、连接 4、执行 (三) 用库函数组装C程序 例1:计算2.1715的正弦值。 #include “math.h” main( ) {

float a; /*定义a为实型变量*/ a=sin(2.1715); /*调用sin函数*/

printf(“%f\\n”,a); /*调用printf函数,输出a的值*/ }

程序详解:

1、在本例中用到的sin函数称为数学函数,它是为了用户使用方便,由一批厂家开发编写的函数,并不是C语言的一部分。在使用数学函数时,往往要用到函数执行时所需的一些信息(例如宏定义),这些信息包含在“math.h”中。因此在程序开头用#include “math.h”将有关的标头文件包括到程序中。

2、一个C语言源程序文件由一个或多个函数组成,C语言的基本组成单位是函数。一个完整的C语言程序有且只有一个称为主函数的main函数,程序总是从main函数开始执行,调用其它函数后再回到main函数,在main函数中结束整个程序的运行。

3、main是函数名称,没有参数可以不写,但圆括号不能省略,main()后面有一对花括号,花括号内的部分称为函数体,main函数可以在程序的任意位置。

4、C规定每个语句以分号(;)结束,分号是语句不可缺少的组成部分,每

行中可以写多条语句。

C语言程序设计详解 2

5、/*与*/之间为注释信息,对程序运行结果不发生影响,也不被编译,注释说明可以放在语句的任意位置。

6、float a;此语句是把a定义为一个实型变量。

7、C语言本身没有输入、输出语句,本例使用prinft函数输出数据。prinft函数的括号内包括两部分内容:双引号内的部分、双引号外的部分。双引号内的部分是“格式字符串”,用于指定输出双引号外的变量的打印格式。此例中双引号中有一个”%f”,它是输出一个保留小数点后6位数字的格式字符,小数点前的位数不指定。

二、经典例题详解

例2:一个C程序的执行是从____。

(A)本程序的main函数开始,到main函数结束

(B)本程序文件的第一个函数开始,到本程序文件的最后一个函数结束 (C)本程序的main函数开始,到本程序文件的最后一个函数结束 (D)本程序文件的第一个函数开始,到本程序main函数结束 答案:C

详解:一个C语言源程序文件由一个或多个函数组成。一个完整的C语

言程序有且只有一个称为主函数的main函数,程序总是从main函数开始执行,调用其它函数后再回到main函数,在main函数中结束整个程序的运行。

例3、以下叙述不正确的是____。

(A)一个C源程序可由一个或多个函数组成 (B)一个C源程序必须包含一个main函数 (C)C程序的基本组成单位是函数

(D)在C程序中,注释说明只能位于一条语句后面 答案:D

详解:/*与*/之间为注释信息,对程序运行结果不发生影响,也不被编译,

注释说明可以放在语句的任意位置。

三、习题 (一) 选择题

1、以下叙述正确的是____。

C语言程序设计详解 3

(A)在C程序中,main函数必须位于程序的最前面 (B)C程序的每行中只能写一条语句 (C)C语言本身没有输入输出语句

(D)在对一个C程序进行编译的过程中,可发现注释中的拼写错误 2、C语言规定:在一个源程序中,main函数的位置____。 (A)必须在最开始

(B)必须在系统调用库函数的后面 (C)可以任意 (D)必须在最后

3、一个C语言程序是由____。 (A)一个主程序和若干子程序组成 (B)函数组成 (C)若干过程组成 (D)若干子程序组成 (二) 填空题:

1、一个C源程序中至少包括一个________。

2、在一个C源程序中,注释部分两侧的分界符分别为________和

________。

第二章 数据描述与基本操作

一、主要知识点 (一) C的基本数据类型

整型 基本类型 字符型

实型(浮点型) 单精度型 枚举类型 双精度型

数据类型 构造类型

指针类型

空类型

C语言程序设计详解 4

(二) 常量和符号常量

1、常量定义:在程序运行过程中,其值不能被改变的量称为常量。常量常区分不同的类型,如12、0、-3为整型常量,’a’、’D’为字符常量。

2、符号常量:用一个标识符代表一个常量的,称为符号常量,即标识符形式的常量。常量不同于变量,它的值在作用域内不能改变,也不能再被赋值。

例1:已知商品的单价及数量求商品的总价值。 #define PRICE 30 main( ) {

int num,total; num=10;

total=num*PRICE; printf(“total=%d”,total); }

输出结果:total=300 程序详解:

1、程序中用#define命令行定义PRICE代表常量30,此后凡在此文件中出现的PRICE都代表30,可以和常量一样进行运算。

2、符号常量不同于变量,它的值在其作用域内不能改变,也不能再被赋值。如再用以下赋值语句给PRICE赋值:PRICE=40;是错误的。

(三) 变量

1、变量定义:其值可以改变的量称为变量。 2、标识符的命名规范

和其它高级语言一样,用来标识变量名、符号常量名、函数名、数组名、类型名、文件名的有效字符序列称为标识符,C语言中的标识符命名规范为:

①变量名只能由字母、数字和下划线三种字符组成,且第一个字符必须为字母或下划表。

②C语言中标识符的长度(字符个数)无统一规定,随系统而不同。许多系统(如IBM PC的MS C)取8个字符,假如程序中出现的变量名长度大于8个

C语言程序设计详解 5

字符,则只有前面8个字符有效,后面的不被识别。

③C语言有32个关键字(例如if、else、while)它们已有专门含义,不应用采用与它们同名的变量名。

④C语言将大写字母和小写字母认为是两个不同字。

例2:在下列符号中,可以选用哪些作变量名?哪些不可以?

a3B 3aB ∏ +a -b *x $ _b5_ if next_ day e_2 OK? Integer MAXNUMBER i*j

答案:_b5_ a3B next_ day e_2 MAXNUMBER可作变量名,其它的作变量名不可以。

详解:

①MAXNUMBER可作变量名。习惯上符号常量名用大写,变量名用小写以示区别,但大写字母作变量名并无错误。

②if、integer属于保留字,保留字不可作变量名。

③∏ +a -b *x $ OK? i*j不可作变量名,因为变量名只能由字母、数字和下划线三种字符组成。

④3aB不可作变量名,因为变量名的第一个字母必须为字母或下划线。 (四) 整型数据 1、整型常量

整型常量即整常数。C语言整常数可用以下三种表示形式。 ①十进制表示。如231、-56.478 ②八进制表示。以

8=1*8

0开头的数是八进制数。如

0123即(123)

2+2*81+3*80=64+16+3=83。

③十六进制表示。以0x开头的数是16进制。如0x123即(123)

16=1*16

2

+2*161+3*160=256+32+3=291。

2、整型变量

整型变量分为:基本型、短整型、长整型、和无符号型四种。 ①基本型,以int表示

②短整型,以short int表示或以short表示 ③长整型,以long int表示,或以long表示

④无符号型,存储单元中全部二进制位(bit)用作存放数本身,而不包括符号。

C语言程序设计详解 6

无符号型中又分为无符号整型、开符号短整型和无符号长整型,分别以unsigned int 、unsigned short 和unsigned long表示。

3、整型数据的取值范围

C标准没有具体规定各类型所占内存字节数,各种机器处理上有所不同,以IBM PC为例,数的范围如表2.1所示。表2.1

Int short[int] Long[int] Unsigned[int] Unsigned short unsigned long 所占位数 16 16 32 16 16 32 数的范围 -32768~32767 即-215~(215-1) -32768~32767 即-215~(215-1) -2147483648~2147483647 即-231~(231-1) 0~65535 即0~(216-1) 0~65535 即0~(216-1) 0~4294967295 即0~(232-1) 4、整型常量的分类

①一个整常量,如果其值在-32768~32767范围内,认为它是int型,它可以赋值给int型和long int型变量。

②一个整常量,如果其值超过了上述范围,而在-2147483648~2147483647范围内,则认为它是long int型,可以将它赋值给一个long int型变量。

③如果某一计算机系统的C版本确定的short int与int型在内存中占据的长度相同,则一个int型的常量出同时一个short int型常量。

④常量中无unsigned型。但一个非负值的整常量可以赋值给unsigned型整变量,只要它的范围不超过变量的取值范围即可。例如:将50000赋给一个unsigned int型变量是可以的,而将70000赋给它是不行的(溢出)。

⑤在一个整常量后面加一个字母l或L,则认为是long int型常量。 (五) 实型数据 1、实型常量

实数在C语言中又称为浮点数。实数有两种表示形式:

①十进制形式。它由数字和小数点组成(注意必须有小数点)。例如:0.123、.123、123.0、0.0都是十进制数形式。

②指数形式。如123.56e4或123.56E4都代表123.56*104。但字母e(或E)之前必须有数字,e后面指数必须为整数。例如:e3、2.1e3.5、.e3、e等都不是

合法的指数形式。

C语言程序设计详解 7

例3:下面四个选项中,均是不合法的浮点数的选项是_____。 (A)160. 0.12 e3 (B)123 2e4.2 .e5 (C)-.18 123e4 0.0 (D)-.e3 .234 1e3 答案:B 详解:

①160. 0.12 -.18 123e4 0.0 .234 1e3是实数的十进制形式或指数形式。

②e3 2e4.2 .e5 -.e3不是正确的指数形式。因为正确的字母e(或E)之前必须有数字,e后面指数必须为整数。对于数据表示形式.e5以及-.e3,e前的.与-.不是有效的数字表示形式。

③123是整数形式。 2、实型变量

C实型变量分为单精度(float型)和双精度(double型)两类。

在一般系统中,一个单精度型数据在内存中占4个字节(32位),一个double型数据占8个字节。单精度实数提供7位有效数字,数值的范围随机器系统而异。在IBM PC中,单精度实数的范围约为10-38~1038,双精度实数的范围约为10-308~10308。

例4: main( ) { float a;

a=111111.666666; printf(“%f”,a); }

输出结果:111111.640621 程序详解:

①一个实型常量不分float型和double型。一个实型常量可以赋给一个float型或double型变量。根据变量的类型截取实型常量中相应的有效位数字。

②由于float型变量只能接收7位有效数字,因此在把111111.666666赋给a时,a只接收了111111.6,由于输出函数printf中的%f格式表示输出小数点后的

C语言程序设计详解 8

6位小数,所以111111.6后的40621属于无意义数字。

③如果a改为double型,则能全部接收上述12位数字。 (六) 字符型数据 1、字符常量:

①普通形式的字符常量:用引号(即撇号)括起来的一个字符,如’a’、’D’、’$’、’?’等都是字符常量。

②转义符:以“\\”开头的字符序列。 常用的以“\\”开头的特殊字符见表2.2 表2.2

字符形式 \\n \ \\v \\b \\r \\f \\\\ \\’ \\ddd \\xhh 功能 换行 横向跳格 竖向跳格 退格 回车 走纸换页 反斜杠字符 单引号字符 1到3位8进进制所代表的字符 1到2位16进制数所代表的字符 例5:若有说明语句:char c=’\\729’;则变量c_____。 (A)包含1个字符 (B)包含2个字符 (C)包含3个字符 (D)说明不合法 答案:D

详解:”\\”后可以有1到3位8进制所代表的字符,本题中”\\”后的”72”属于8进制所代表的字符,而”9”则不属于8进制位所代表的字符,则’\\729’中包含了两个字符常量’\\72’和’9’。而字符常量是用引号(即撇号)括起来的一个字符,所以答案为D。

2、字符变量

字符变量是用来存放字符常量。注意只能存放一个字符。 3、字符数据在内存中的存储形式

C语言程序设计详解 9

将一个字符常量存放到一个字符变量中,实际上并不是把该字符本身存放到内存单元中去,而是将该字符的相应的ASCII码值存放到存储单元中去。

例6:将小写字母转换成大写字母 main( ) { char c1; c1=’a’; c1=c1-32; printf(“%c”,c1); }

输出结果:A 程序详解:

①’a’的ASCII码为97,所以c1=’a’;语句的功能是把97赋值给了c1。 ②c1=c1-32;语句的功能是把97-32的值65赋值给c1。

③printf函数中的%c格式表示以字符方式输出。ASCII码值为65的字符为A,所以运行结果为:A

(七) 字符串常量

字符常量是用一对双引号括起来的零个或多个字符序列。C规定以字符’\\0’作为字符串结束标志。所以字符串”a”实际上包含2个字符:’a’、’\\0’,因此,把它赋值给一个字符变量c:

c=”a”

是错误的。

例7:下面不正确的字符串常量是______。 (A)’abc’ (B)”12’12” (C)”0” (D)” ” 答案:A

详解:’abc’是用单引号引来的,所以’abc’不是正确的字符串常量。 (八) 算术运算符和算术表达式 1、基本算术运算符

①C语言中有5个基本算术运算符, +(加法运算符。如3+5、+3) -(减法运算符。如5-2、-3)

C语言程序设计详解 10

*(乘法运算符,如3*5) /(除法运算符,如5/3,5.0/3)

%(求余运算符,要求%两侧均为整型数据)

例8:在C语言中,要求运算数必须是整型的运算符是____。 (A)/ (B)++ (C)!= (D)% 答案:D

详解:对于%运算符来说,要求两侧均为整型数据,所以表达式3.5%2与3%2.0是错误的。

例9:写出下列程序的输出结果 main( )

{ printf(“%d,%d\\n”,5/3,5%3); printf(“%d,%d\\n”,-5/-3,-5%-3); printf(“%d,%d\\n”,-5/3,-5%3); printf(“%d,%d\\n”,5/-3,5%-3); }

输出结果: 1,2 1,-2 -1,-2 -1,2

程序详解:两个同号整数相除时结果为正整数,如5/3、-5/-3的结果值为1。两个异号整数相除时结果为负整数,多数机器采取“向零取整”法,即-5/-3=-1,5/-3=-1,但如果参加运算的两个数中有一个数为实数时结果为实数。对于求余(%)运算,运算结果与第一个数的符号相同。

②优先级别:先*、/、%后+、-

③运算量:双元运算量,%前后必须为整数。 ④左右结合性:自左至右参预运算。 2、自加自减运算符

①C语言中有4种形式的自加自减运算符: ++i (先使i加1后使用)

C语言程序设计详解 11

i++ (先使用后使i加1) --i (先使i减1后使用) i-- (先使用后使i减1) ②优先级别:高于算术运算。

例10:若x和n均是int型变量,且x和n的初值均为5,则计算表达式后x的值为______,n的值为______。

x+=n++ 答案:10 6

详解:根据优先级别选运算表达式n++,因为n++是后缀表示形式,所以n先参预运算,再运算表达式x+=n,则x为10,最后n自加为6。

例11: main( ) { int x,y,m,n;

x=2;y=2 m=x++*5; n=++y*5;

printf(“%d,%d,%d,%d”,x,y,m,n); }

输出结果:3,3,10,15

程序详解:对于后缀来说是先使用后运算,所以m的值为x在自加以前的2*5得10赋值给m后,x自加变为3。对于前缀来说是先运算后使用,所以m的值为x在自加以后的3*5得15赋值给n。

③运算量:单元运算量,此运算量必须为变量,所以表达式5++、(x+y)++是错误的。

④左右结合性:自右至左参预运算。 (九) 关系运算

1、C语言提供的关系运算符有:

>(大于) >=(大于或等于) <小于) <=(小于或等于) ==(等于)是 !=(不等于)

2、优先级别:关系运算符的优先级别低于纯算术类,高于值类。后两个的

C语言程序设计详解 12

优先级小于前四个。如表达式a+b3、运算量:关系运算符是双元运算符,整型、实型、字符都可以参预运算。 4、左右结合性:从左向右的结合方向 5、关于关系运算符的进一步说明:

①关系表达式的值是整型数0或1,故也可以将其看成一种整型表达式。例如: int i=1,j=7,a; a=i+(j%4!=0); a的值为2。

②要说明x在区间[a,b]中,普通数学中使用表达式a≤x≥b。但C语言中应写成a<=x&&x<=b。

③表达式5>2>7>8在数学上是不允许的,而在C中是允许的。按自左至右求解。

④字符数据的比较按其ASCII码值进行。

⑤在判定两个浮点数是否相等时,由于存储上的误差,会得出错误的结果。例如:

1.0/3.0*3.0==1.0 (十) 逻辑运算

1、C语言提供的逻辑运算符:

&&(逻辑与) ||(逻辑或) !(逻辑非)

2、优先级别:&&与||的优先级别低于关系运算符,高于条件运算符,&&

的优先级别高于||,!的优先级别与自加运算符(++)、自减运算符(--)同级。

3、运算量:&&和||是双元运算符,!是单元运算符。

例12:已知x=43,ch=’A’,y=0;则表达(x>=y&&ch<’B’&&!y)的值是______。 (A)0 (B)语法错 (C)1 (D)“真” 答案:C

说明:C语言不提供逻辑性数据“真”和“假”,在进行逻辑运算时则把

“非零”作为“真”,把0作为“假”,所以表达式!y的运算结果是1。

4、左右结合性:&&和||运算符的结合方向为自左至右,!的结合方向为自

右至左。

5、关于逻辑运算符的进一步说明:

C语言程序设计详解 13

①在一个&&表达式中,若&&的一端为0,则不必再计算另一端,该表达式

的值肯定为0。

②在一个||表达式中,若||的一端为0,则不必再计算另一端,该表达式的值

肯定为1。

例13:写出下面程序的输出结果。 main( ) { int x,y,z; x=y=z=0; ++x&&++y||++z;

printf(“%d,%d,%d”,x,y,z); x=y=z=0; ++x||++y&&++z;

printf(“%d,%d,%d”,x,y,z);

}

输出结果: 1,1,0 1,0,0 程序说明:

①因为&&的优先级别高于||,所以表达式++x&&++y||++z是一个或表达

式,根据||的一端为0,则不必再计算另一端的原则,先计算表达式++x&&++y的值为1,因为1或任何值都为1,所以表达式++z没有运算,输出结果为:1,1,0。

②表达式++x||++y&&++z也是一个或表达式,同样根据||的一端为0,则不

必再计算另一端的原则,先计算表达式++z的值为1,因为1或任何值都为1,所以表达式++y&&++z没有运算,输出结果为:1,0,0。

(十一) 赋值运算

1、基本的赋值运算符:

=(将赋值运算符右侧的表达式赋给左侧的变量) 2、自反算术赋值运算符

C语言中有5个基本自反算术赋值运算符,

C语言程序设计详解 14

+=(a+=3 等价于a=a+3) -=(a-=3 等价于a=a-3) *=(a*=3 等价于a=a*3) /=(a*=3 等价于a=a*3) %=(a%=3 等价于a=a%3)

3、优先级别:赋值运算符与自反算术赋值运算符属于同等级别,低于条件运算符,高于逗号运算符。如对于表达式x%=y+3完全等价于x%=(y+3)。

例14:若有以下定义,则能使值为3的表达式是______。 Int k=7,x=12;

(A)x%=(k%5) (B)x%=(k-k%5) (C)x%=k-k%5 (D)(x%=k)-(k%=5) 答案:D

详解:表达式(x%=k)-(k%=5)完全等价于(x=x%k)-(k=k%5)等价于5-2,此表达式的结果为3。

4、运算量:双元运算量,赋值运算符与自反算术赋值运算的第一个量必须为变量,且%=前后必须为整型数据。如对于表达式a*3+=2是错误的。因为此表达式完全等价于(a*3)=(a*3)+2。

5、左右结合性:自右至左参预运算。

例15:若a是int型变量,且a的初值为6,则计算表达式后a的值为______。 a+=a-=a*a 答案:-60

详解:表达式从左向右运算,先计算表达式a=a-36后a为-30,再计算表达式a=a+a后

a的值变为-60。

(十二) 条件运算:

1、条件运算符的基本形式及功能:

条件运算是一种在两个表达式的值中选择一个的操作。它的一般形式为: e1?e2:e3

它的操作过程为,若e1为真,则表达式的值为e2,若为假表达式的值为e3。

2、优先级别:低于逻辑运算,高于赋值运算。

3、运算量:三元运算量,e1一般为算术表达式,e2、e3可以是任意类型的

C语言程序设计详解 15

表达式,条件表达式的值的类型为e2与e3二者中类型较高的。

例16:若有条件表达式(exp)?a++:b--,则以下表达式中能完全等价于表达式(exp)的是______。

答案:exp!=0

说明:对于表达式e1?e2:e3 ,e1一般为算术表达式、逻辑表达式、关系表达式,结果为1(真)或0(假)。也可以为数值exp,结果为结果为非0(真)或0(假)在本例中与exp完全等价的表达式是exp!=0。

4、左右结合性:自右至左运算。 例17:以下程序的运行结果是______。

main()

{ int k=4,a=3,b=2,c=1; printf(“%d”,k程序解析:条件表达式是从右向左运算,所以在本例中先计算表达式c(十三) 逗号运算

1、逗号运算符的基本形式及功能:

逗号表达式的一般形式为: 表达式1,表达式2。逗号表达式的求解过程是:先求解表达式1,再求解表达式2。整个表达式的值是表达式2的值。

2、优先级别:逗号运算符是所有运算符中级别最低的。 例18:以下符合C语言语法的赋值表达式是______。

(A)d=9+e+f=d+9 (B)d=(9+e,f=d+9) (C)d=9+e,e++,d+9 (D)d=9+e++=d+7 答案:B

解析:表达式d=9+e+f=d+9中9+e+f=d+9是不正确的表示形式,因为赋值号(=)左边不能是表达式。表达式d=9+e,e++,d+9是逗号表达式,因为赋值运算符(=)的优先级别高于逗号运算符(,)。表达式d=9+e++=d+7中9+e++=d+7是不正确的表达式,因为赋值号(=)左边不能是表达式。

C语言程序设计详解 16

3、运算量:二元运算量。

4、左右结合性:从左向右运算。

例19:假设所有变量均为整型,则表达式 a=2,b=5,b++,a+b的值是______。 答案:8

解析:根据逗号运算符从左向右运算的原则,首先把2和5分别赋值给了a,b。再计算表达式b++,b变为6,再计算表达式a+b的值,最后整个表达式的值是是8。

(十四) 强制类型转换

1、强制类型一般形式及功能:

可以利用强制类型转换运算符将一个表达式转换成所需类型。例如:(double) a(将a转换成double类型)其一般形式为:

(类型名)(表达式)

2、优先级别:强制类型转换运算符与逻辑非(!)、自加(++)、自减(--)属于同等级别,高于算术运算符。

3、运算量:单元运算量

4、关于强制类型转换运算符的进一步说明:

①强制转换表达式时,表达式应该用括号括起来。如果写成(int )x+y则只将x转换成整型,然后与y相加。

②如果x原指定为float型,进行强制类型运算后得到一个int型的中间变量,它的值等于x的整数部分(截去小数部分),而x的类型不变(仍为float型)。

例20: main( ) {float x; int i; x=3.6; i=(int)x

printf(“x=%f,i=%d”,x,i); }

运算结果:x=3.600000,I=3

C语言程序设计详解 17

程序解析:变量x进行强制类型运算后,其类型仍为float型,值仍为3.6。 (十五) printf函数

printf函数可以输出任意类型的多个数据。 1、printf函数的一般格式 printf(格式控制,输出表列)

①“格式控制”是用双引号括起来的字符串,也称“转换控制字符串”,它包括两种信息:格式说明和普通字符。格式说明是由“%”和格式字符组成,如%d,%f等。它的作用是将输出的数据转换为指定的格式输出。格式说明总是由”%”字符开始的。普通字符即需要原样输出的字符。

②输出表列是指需要输出的一些数据,可以是表达式,它们之间用“,”隔开。 2、格式控制的完整格式:

% - 0 m.n l或h 格式字符 下面对组成格式说明的各项加以说明: ①%:表示格式说明的起始符号,不可缺少。 ②-:有-表示左对齐输出,如省略表示右对齐输出。 ③0:有0表示指定空位填0,如省略表示指定空位不填。

④m.n:m指域宽,即对应的输出项在输出设备上所占的字符数。N指精度。用于说明输出的实型数的小数位数。为指定n时,隐含的精度为n=6位。

⑤l或h:l对整型指long型,对实型指double型。h用于将整型的格式字符修正为short型。

3、格式字符:

格式字符用以指定输出项的数据类型和输出格式。 ①d格式:用来输出十进制整数。有以下几种用法:

%d:按整型数据的实际长度输出。

%md:m为指定的输出字段的宽度。如果数据的位数小于m,则左端补以

空格,若大于m,则按实际位数输出。

%ld:输出长整型数据。

②o格式:以无符号八进制形式输出整数。对长整型可以用“%lo”格式输出。同样也可以指定字段宽度用“%mo”格式输出。

例21:

main() { int a=-1;

C语言程序设计详解 18

printf(“%d,%o”,a,a); }

运行结果:-1,177777

程序解析:-1在内存单元中(以补码形式存放)为(1111111111111111)2,转换为八进制数为(177777)8。

③x格式:以无符号十六进制形式输出整数。对长整型可以用“%lx”格式输出。同样也可以指定字段宽度用“%mx”格式输出。

④u格式:以无符号十进制形式输出整数。对长整型可以用“%lu”格式输出。同样也可以指定字段宽度用“%mu”格式输出。

⑤c格式:输出一个字符。

⑥s格式:用来输出一个串。有几中用法

%s:例如:printf(“%s”,”CHINA”)输出“CHINA”字符串(不包括双引号)。 %ms:输出的字符串占m列,如字符串本身长度大于m,则突破获m的

限制,将字符串全部输出。若串长小于m,则左补空格。

%-ms:如果串长小于m,则在m列范围内,字符串向左靠,右补空格。 %m.ns:输出占m列,但只取字符串中左端n个字符。这n个字符输出在

m列的右侧,左补空格。

%-m.ns:其中m、n含义同上,n个字符输出在m列范围的左侧,右补空

格。如果n>m,则自动取n值,即保证n个字符正常输出。

⑦f格式:用来输出实数(包括单、双精度),以小数形式输出。有以下几种用法:

%f:不指定宽度,整数部分全部输出并输出6位小数。

%m.nf:输出共占m列,其中有n位小数,如数值宽度小于m左端补空

格。

%-m.nf:输出共占n列,其中有n位小数,如数值宽度小于m右端补空格。

⑧e格式:以指数形式输出实数。可用以下形式:

%e:数字部分(又称尾数)输出6位小数,指数部分占5位或4位。

C语言程序设计详解 19

%m.ne和%-m.ne:m、n和”-”字符含义与前相同。此处n指数据的数字部

分的小数位数,m表示整个输出数据所占的宽度。

⑨g格式:自动选f格式或e格式中较短的一种输出,且不输出无意义的零。 4、关于printf函数的进一步说明:

如果想输出字符“%”,则应该在“格式控制”字符串中用连续两个%表示,如:

printf(“%f%%”,1.0/3); 输出0.333333%。

(十六) scanf函数

scanf函数可以用来输入任何类型的多个数据。 1、scanf函数的一般格式 scanf(格式控制,地址表列)

①“格式控制”的含义同printf函数。普通字符即需要原样输入的字符。 ②地址表列是指由若干个地址组成的表列,它们之间用“,”隔开。 2、格式控制的完整格式: % * m l或h 格式字符

①格式字符与printf函数中的使用方式相同,以%d、%o、%x、%c、%s、%f、%e,无%u格式、%g格式。

②可以指定输入数据所占列宽,系统自动按它截取所需数据。如: scanf(“%3d%3d”,&a,&b); 输入:123456

系统自动将123赋给a,456赋给b。

③%后的“*”附加说明符,用来表示跳过它相应的数据。例如: scanf(“%2d%*3d%2d”,&a,&b);

如果输入如下信息:1234567。将12赋给a,67赋给b。第二个数据”345”被跳过不赋给任何变量。

④输入数据时不能规定精度,例如: scanf(“%7.2f”,&a);

是不合法的,不能企图输入:12345.67而使a的值为12345.67。

3、输入数据流分隔

C语言程序设计详解 20

①根据格式字符的含义从输入流中取得数据,当输入流中数据类型与格式字符要求不符时,就认为这一项结束。如:

scanf(“%d%c%f”,&a,&b,&c); 如果输入如下信息: 1234r1234.567

则scanf函数在接收数据时发现”r”类型不匹配,于是把”1234”转换成整型赋值给a,把”r”赋给变量b,最后把”1234.567”转换成实型数据赋给c。

②根据格式项中指定的域宽分隔出数据项。如语句:scanf(“%2d%3f%4f”,&a,&b,&c); 如果输入如下信息: 123456789012345

则scanf函数在接收数据时根据域宽把12赋值给a,345赋值给b,6789赋值给c。

③隐示分隔符。空格、跳格符(’\’)、换行符(’\\n’)都是C语言认定的数据分隔符。

④显示分隔符。在scanf函数的两个格式说明项间有一个或多个普通字符,那么在输入数据时,在两个数据之间也必须以这一个或多个字符分隔。如语句:

scanf(“a=%d,b=%f,c=%f”,&a,&b,&c); 则输入数据应该为: a=1234,b=67.8,c=98.123

4、关于scanf函数的进一步说明:

①scanf函数中的“格式控制”后面应当是变量地址,而不应是变量名。

例如,如果a、b为整型变量,则

scanf(“%d,%d”,a,b);

是不对的,应将”a,b”改为”&a,&b”。

②如果在“格式控制”字符串中除了格式说明以外还有其它字符,则在输

入数据时应输入与这些字符相同的字符。例如:

scanf(“%d,%d”,&a,&b);

输入时应输入:3,4。3与4之间的逗号应与scanf函数中的“格式控制”中的逗号相对应,输入其它符号是不对的。

C语言程序设计详解 21

③在用“%c”格式输入字符时,空格字符和转义字符都作为有效字符输入。 scanf(“%c%c%c”,&c1,&c2,&c3);

如输入:a b c 。字符’a’赋给c1,字符(空格)’ ’赋给c2,字符’b’ 赋给c3。

5、scanf的停止与返回

①格式参数中的格式项用法----正常结束。 ②发生格式项与输入域不匹配时----不正常退出: (十七) getchar、putchar函数 1、getchar函数

getchar函数是从终端输入一个字符。getchar函数没有参数,其一般形式为:getchar( )。

2、putchar函数

putchar函数的作用是向终端输出一个字符。 三、经典例题解析 例22: 四、练习

1、下面四个选项中,均是不合法的用户标识符的选项是____。C (A)A P_0 do (B)float la0 _a (C)b-a goto int (D)_123 temp INT

2、若x,i,j和k都是int型变量,则计算下面表达式后,x的值为______。x=(i=4,j=16,k=32)C

(A)4 (B)16 (C)32 (D)52

3、下列四个选项中,均是不合法的整型常量的选项是______。D (A)--0f1 -0xffff 0011 (B)-0xcdf 017 12,3456 (C)-018 999 5e2 (D)-0x48eg -068 03f

4、下面四个选项中,均是合法浮点数的选项是______。 (A)1e1 5e-9.4 03e2 (B)-.60 12e-4 -8e5 (C)123e 1.2e-.4 2e-1

C语言程序设计详解 22

(D)-e3 .8e-4 5.e-0 B

5、下面四个选项中,均是合法字符的选项是______。A (A)’\\’’ ‘\\\\’ ‘\\xf’ (B)’\\’ ‘\\017’ ‘\\n’ (C)’\\018’ ‘\\f’ ‘xab’(D)’\\0’ ‘\\101’ ‘xlf’ 6、以下不正确的叙述是______。D

(A)在C程序中,逗号运算符的优先级最低。 (B)在C程序中,APH和aph是两个不同的变量

(C)若a和b类型相同,在计算机了赋值表达式a=b后,b的值不变。 (D)当从键盘输入数据时,对于整型变量只能输入整型数值,对于实型变量只能输入实型数据。

C语言程序设计详解 23

第三章 C程序的流程设计

一、算法 1、算法的概念

为解决某一个问题而采取的方法和步骤,就称为算法。 2、算法的性质

①有穷性:一个算法应包含有限的操作步骤 ②一个初始:此动作序列只有一个初始动作

③确定性:算法中的每一个步骤都应当是确定性的,仅有一个后继动作。 ④有一个或多个输出:序列终止表示问题得到解答或问题没有解答,没有输出的算法是没有意义的。

二、选择型程序设计 1、if 语句的形式

①if(条件表达式) 语句

②if(条件表达式) 语句1 else 语句 2 注意:

①if语句中的条件表达式一般为逻辑表达式或关系表达式,但也可以是任意的数值类型(包括整型、实型、字符型、指针数据)例如下列语句也是合法的。 if(‘a’) printf(“%d” ,’a’);

②在if语句中,分号是语句的结束标志。

③在if和else后面可以只含一个内嵌的操作语句,也可以有多个操作语句,此时用花括号将几个语句括起来成为一个复合语句。

例1:以下不正确的if语句形式是( )。 A)if(x>y&&x!=y); B)if(x==y) x+=y;

C)if(x!=y) scanf(“%d”,&x) else scanf(“%d”,&y); D)if(xC语言程序设计详解 24

答案解析:scanf(“%d”,&x)末尾应加分号,因为分号是语句不可缺少的部分。 例2:已知int x=10,y=20,z=30;以下语句执行后x,y,z的值是( )。 If(x>y)

z=x;x=y;y=z;

答案:x,y,z的值分别是:20 30 30

答案解析:在此语句中,条件x>y为假,所以只执行x=y;y=z;两条语句。

例3、以下不正确的语句是( ) A)if(x>y);

B)if(x=y)&&(x!=0) x+=y; C)if(x!=y) scanf(“%d”,&x); D)if(x答案解析:y++的末尾无分号。 2、if 的嵌套

if(条件1)

if(条件2) 语句1 else

语句2 else if(条件3) 语句3 else

语句4

例4:以下程序的输出结果是( ) main( ) {

int a=100,x=10,y=20,ok1=5,ok2=0; if(xif(y!=10)

if (!ok1)

a=1; else

if(ok2) a=10; printf(“%d\\n”,a);

} 答案:100

C语言程序设计详解 25

例5:请阅读以下程序:若运行时输入2.0<回车>,则上面程序的输出结果是( )

#include main( ) {

float a,b;

scanf(“%f”,&a); if(a<0.0) b=0.0;

else if((a<0.5) &&(a!=2.0) b=1.0/(a+2.0); else if(a<10.0) b=1.0/a; else b=10.0; printf(“%f\\n”,b); }

答案:0.500000

例6:请阅读下面的程序:

main( ) {

int s,t,a,b;

scanf(“%d,%d”,&a,&b); s=1; t=1;

if(a>0) s=s+1; if(a>b) t=s+t;

else if(a==b) t=5; else t=2*s;

printf(“%d,%d”,s,t); }

为了使输出结果t为4,输入量a和b应满足的条件是( )。

答案:b>a>0

例7:运输公司对用户计算运费,距离越远,每公里运费越低,标准如下:

s<250km 250≤s<500 500≤s<1000 1000≤s<2000 2000≤s<3000 3000≤s

设每公里每吨货物的基本运费为p,货物重为w,距离为s,折扣为d,则总运费f计算公式为f=p*w*s(1-d),编写程序。(此程序可用if……else来完成,

C语言程序设计详解 26

也可以用switch来完成)。

3、switch结构

switch语句是多分支选择语句,其形式如下: switch(表达式)

{

case 常量表达式1:语句1 case 常量表达式2:语句2 …………

default:语句n+1 } 注意:

1、switch后面括弧内的“表达式”,可以是整型表达式或字符型表达式,也可以枚举型数据

2、当表达式的值与某一个case后面的常量表达式的值相等时,就执行此case后面的语句,若所有的case中的常量表达式的值都没有与表达式的值匹配的,就执行default后面的语句。

3、每一个case的常量表达式的值必须互不相同,否则就会出现互相矛盾的现象。

4、每个case的出现次序不影响执行结果。

5、执行完一个case后面的语句后,流程控制转移到下一个case继续执行,直到遇到break语句或执行完为止。

例8:请读以程序 #include main( )

{ int x=1,y=0,a=0,b=0; switch(x) {

case 1: switch(y) {

case 0:a++;break; case 1:b++;break; }

case 2:

a++;b++;break;

}

printf(“a=%d,b=%d”,a,b);

}

答案:a=2,b=1

C语言程序设计详解 27

程序解析:此程序是switch的嵌套结构,在此程序中break跳出内层switch结构,接着执行外层switch的case 2后的语句。

例9:下面程序的运行结果是( ) main() {int i;

for(i=1;i<=5;i++) switch(i%5)

{ case 0:printf(“*”);break; case 1:printf(“#”);break; default:printf(“\\n”); case 2:printf(“&”);

} }

答案:#& & &*

例10:编写程序给出一百制成绩,要求输出成绩等级‘A’、‘B’、‘C’、‘D’、‘E’,90分以上为A,80-89分为‘B’,70-79为‘C’,60-69为‘D’,60分以下为‘E’。

main() {int score;

scanf(“%d”,&score); switch(score/10) {case 10:

case 9:printf(“等级是A”);break; case 8: printf(“等级是B”);break; case 7: printf(“等级是C”);break; case 6: printf(“等级是D”);break; default: printf(“等级是E”);break; } }

三、循环型程序设计 1、while语句

while语句用来实现”当型”循环结构,其一般形式如下: while(条件表达式) 循环体语句 例11:设有程序段:

int k=10;

C语言程序设计详解 28

while(k=0) k=k-1; 循环体执行( )次。 答案:0

答案解析:在此程序的while结构中,条件表达式k=0的结果永远为0即为假,所以循环执行的次数为0。

例12:下面程序段的运行结果是( ) x=y=0;

while(x<15) y++,x+=++y; printf(“%d,%d”,y,x); 答案:8,20 例13、设有程序段 t=0;

while(printf(“*”)) { t++;

if(t>3) break;

} 循环执行( )次 答案:4

答案解析:while结构中的条件表达式printf(“*”)的值为输出数据的个数,在此例中,printf(“*”)的结果为1,即为真。

2、do-while语句

do-while语句的特点是先执行循环体,然后判断循环条件是否成立,其一般形式为:

do{

循环体语句

}while(条件表达式); 例14、若有如下语句 int x=3;

do {printf(“%d\\n”,x-=2);}

while(--x);

则上面程序段输出结果是( )。 答案:1

C语言程序设计详解 29

例15、以下程序段循环执行几次。 x=-1; do

{ x=x*x;} while(!x); 答案:1

例16、下面程序的运行结果是( ) main( ) {

int y=10;

do{y--;} while(--y); printf(“%d\\n”,y--); }

答案:0 3、for语句

C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况,它完全可以代替while语句,其一般形式为:

for(表达式1;表达式2;表达式2) 语句 说明:

①for语句一般形式中的“表达式1”可以省略,此时应for语句之前给循环变量赋初值。注意省略表达式1时,其后的分号不能省略。

②如果表达式2省略,即不判断循环条件,循环无终止地进行下去。 ③表达式3也可以省略,但此时程序设计者应另外设法保证循环正常结束。 ④可以省略表达式1和表达式3,只有表达式2,即只给循环条件,在这种情况下,完全等同于while语句。

⑤3个表达式都可省略,如:for( ; ; ) 语句,相当于while(1) 语句,即不设初值,不判断条件(认为表达式2为真值),循环变量不增值。无终止地执行循环体。

⑥表达式1可以是设置循环变量初值的赋值表达式,也可以是与循环变量无关的其他表达式。for(sum=0;i<=100;i++) sum=sum+i;

⑦表达式一般是关系表达式(如i<=100)或逻辑表达式(如a例17:若i为整型变量,则以下循环执行次数是( )。

C语言程序设计详解 30

for( i=2 ;i!=0 ; ) printf(“%d”,i--); 答案:21

例18:以下不是无限循环的语句是( ) A)for(y=0,x=1;x>++y;x=i++) i=x; B)for(;;x++=i) C)while(1){x++;} D)for(i=10;;i--) sum+=i; 答案:A

例19、执行语句for( i=1 ; i++<4 ; ); 后变量i的值是( ) 答案:4

例20、下面程序段的功能是计算1000!的末尾含有多少个零。请填空。 for(k=0,i=5;i<=1000;i+=5) {m=i;

while( ) {k++;m=m/5;} } 答案:m%5!=0 4、break与continue

在break语句可以使流程跳出switch结构,继续执行switch语句下面的一个语句。实际上,break语句还可以用来从循环体内跳出循环体,即提高结束循环,接着执行循环下面的语句。break语句的一般形式为:break;

continue语句只结束本次循环,而不是终止整个循环的执行。continue语句的一般形式为:continue;

例21:下列程序的运行结果是( )。 main( )

{ int i,j,x=0;

for(i=0;i<2;i++) {x++;

for(j=0;j<=3;j++)

{ if(j%2) continue; x++;} x++;

}

printf(“x=%d\\n”,x);

}

答案:

C语言程序设计详解 31

例22、下面程序的运行结果是( ) main( )

{ int k=0;char c=’A’; do

{switch(c++)

case ‘A’:k++;break; case ‘B’:k--;

case ‘C’:k+=2;break;

case ‘D’:k=k%2;continue; case ‘E’:k=k*10;break; default:k=k/3; } k++;

}while(c<‘G’); printf(“k=%d\\n”,k);

答案:

5、循环的嵌套

一个循环体中又包含另一个完整的循环结构称为循环的嵌套。内嵌的循环中还可嵌套循环,这就是多层循环。

6、举例: ①求和问题

例23:s=1+2+…………..+100 例24:s=1!+2!+………… +100!

例25:e=1+1/1!+1/2!+1/3!+…… 精确到10-6 例26:s=1-1/3!+1/5!-1/7!+……. 精确到10-6 #include “math.h” main( ) {

long t; double s;

for(s=0,t=1,i=0;fabs(1/t)>=1e-6;i++) {

t=(-1)*t*i; s=s+1/t; }

printf(“%lf”,s); }(例26程序设计)

例27:有一分数序列:2/1,3/2,5/3,8/5,13/6,21/13,…….

C语言程序设计详解 32

求出这个数列的前20项之和 main() {

int s=0, f1=1,f2=2; for(I=1;I<=20;I++) {

s=s+f2/f1; f2=f1+f2; f1=f2-f1;

}

printf(“%d”,s); }

例28:打印九九表

main( ) {int i,j;

for(i=1;i<=9;i++) {

for(j=1;j<=9;j++)

printf(“%2d*%2d=%2d”,i,j,i*j); printf(“\\n”);

} }

例29:打印出下列图形

* * *

* * *

* * *

main( ) {

int i,j;

for(i=1;i<=5;i++) {

for(j=1;j<=5+fabs(i-3);j++) printf(“ ”);

for(j=1;j<=5-2*fabs(i-3);j++) printf(“*”); printf(“\\n”);

}

}

C语言程序设计详解 33

例30、打印出下列图形

* ***

*****

***

例31、兔子繁殖问题 main( ) {

int i,f1,f2,f3;

for(i=3;i<=12;i++) {

f3=f1+f2; f1=f2; f2=f3; }

printf(“%d”,f3); }

例32、求最大公约数、最小公倍数。

main( )

{int r,u,v,m,n;

scanf(“%d,%d”,&m,&n); m=u;n=v;

if(u{r=u%v;u=v;v=r;}

printf(“最大公约数是:%d,最小公倍数是”,v,m*n/v); }

例33、sn=a+aa+aaa+aa…a,从键盘输入a及n后,求sn 方法一: main() {int n,a; long s;

scnaf(“%d%d”,&n,&a); for(i=1;i<=n;i++) s=s*10+i*a; printf(“%ld”,s); }

方法二:

C语言程序设计详解 34

main() {int n,a; long s,t=0;

scnaf(“%d%d”,&n,&a); for(i=1;i<=n;i++) {t=t*10+a

s=s+t; }

printf(“%ld”,s); }

例34、给出一个不多于5位的正整数,要求①求出它是几位数②分别打印出每一位数③逆序打印此数据。

main( ) {long a;

int i=0;s=0;

printf(“它的每一位数:”); While(a!=0) { i=i+1; x=a%10; a=a/10; s=s*10+x;

printf(“%d ”,x); }

printf(“\\n”);

printf(“它是%d位数\\n”,i); printf(“它的逆序是%d\\n”,s);

}

例35、输出1—100之间每位数的乘积大于每位数的和的数

main()

{ int n,k=1,s=0,m;

for(n=1;n<=100;n++) {k=1;s=0; m=n;

while(m!=0) {

k=k+m%10; s=s+m%10; m=m/10; }

if(k>s) printf(“%d”,n); } }

例36、猴子吃桃问题,猴子第一天摘下若干桃子,当即吃了一半,还不过

C语言程序设计详解 35

瘾又多吃了一个,第二天又将剩下的桃子吃掉一半,又多吃了一个,以后每天都吃前一天剩下的半多一个,到第10天,再吃桃时只剩下一个桃子,求第一天共摘下多少了桃。

main() {int i,s=1;

for(i=9;i<=1;i--) s=2*s+1;

printf(“第一天共摘下%d个桃子”,s); }

例37:准备客票:某铁路线上共有10个车站,问需要准备几种车票。 main()

{int i,j,s=0;

for(I=1;I<=9;I++)

for(j=I+1;j<=10;j++) s=s+1;

printf(“需要准备%d”,2*s); }

例38、有1020个西瓜,第一天卖一半多两个,以后每天卖剩下的一半多两个,问几天以后能卖完。

main( )

{ int day=0,s=1020; while(s<=0)

{s=s/2-2; day++; } printf(“%d”,day); }

例39、从三个红球、五个白球、六个黑球中任意取出八个球,且其中必须有白球,输出所有可能的方案。

main()

{int red,white,black;

for(white=1;white<=5;white++) for(red=0;red<=3;red++)

for(black=0;black<=6;black++) if(white+red+black==8)

printf(“%d个红球,%d个白球,%d个黑球”,red,white,black); }

例40、二分迭代法

二分迭代法的思想是:先取f(x)=0的两个粗略解x1与x2。若f(x1)与f(x2)符号相反,则方程f(x)=0在区间(x1,x2)中至少有一个根。

While(fabs(x1-x2)>=1e-6)

C语言程序设计详解 36

{ x3=(x1+x2)/2; if(f(x3)*f(x2)>0) x2=x3; else x1=x3; }

例41、牛顿切线法求a的平方根。 x=√a x2=a 构造函数 f(x)=x2-a x2=x1-f(x1)/f’(x1) double sq-root(double a) {double x; x=a;

while(fabs(x*x)-a>=1e-6)

x=(x+a/x)*0 5;

return(x);

}

例42、求积分用梯形法求sin(x)*cos(x)的定积分,设上限a、下限b分别为0,1.2。积分区间分割数n=100.

S=h/2[f(a)+f(b)]+h(f(a+h)+f(a+2h)+………..+f(b)) main( ) { int i,n=100;

double h,s,a=0,b=1.2;

s=0.5*(sin(a)*cos(a)+sin(b)*cos(b)); for(i=1;i<=n;i++)

s=s+sin(a+i*h)*cos(a+i*h); printf(“%lf”,s); }

例44、验证一个数是否为素数 main( )

{int n,I,flag=1;

C语言程序设计详解 37

scnaf(“%d”,&n);

for(i=2;i<=sqrt(n);i++)

if(n%i==0) {flag=0;break;}

if(flag==1)

printf(“%d是素数。”,n); else

printf(“%d不是素数。”,n); }

例45、输入一个数,输出这个数的质因子乘积的形式。例如输入72后,输出:72=2*2*2*3*3。

main()

{ int n,i=2,flag=0; scanf(“%d”,&n); printf(“%d=”,n); while(n!=1) {

if(n%i==0)

{if(flag==0)

{printf(“%d”,i);flag=1;}

else

{printf(“*%d”,i);}

n=n/i;

} else i=i+1 } }

C语言程序设计详解 38

第四章 模块化程序设计

一、函数 1、C程序结构

一个简单的函数调用例子。

main()

{printstar();

print_message(); printstar(); }

printstar() {

printf(“**************************\\n”); }

print_message() {

printf(“How do you do!\\n”); } 说明:

①用C语言编写函数至少要编写一个main()函数,执行C程序就是执行相应的main()函数,调用其他函数后流程回到main函数,在main函数中结束整个程序的运行。

②一个C程序可由一个主函数和若干个函数组成。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。

③所有函数都是平行的,即在定义函数时互相独立的,一个函数并不从属于另一个函数,即函数不能嵌套调用

④从用户使用的角度看,函数有两种:标准函数,用户自定义函数。 ⑤从函数的形式看,函数分两类:无参函数、有参函数。 例1:以下正确的说法是( )建立函数的目的之一是: A)提高程序的执行效率 B)提高程序的可读性 C)减少程序的篇幅 D)减少程序文件所占内存 答案:B

C语言程序设计详解 39

例2:以下正确的说法是( )

A)用户若需调用标准库函数,调用前必须重新定义

B)用户可以重新定义标准函数,若如此,该函数将失去原有含义 C)系统根本不允许用户重新定义标准库函数

D)用户若需调用标准库函数,调用前不必使用预编译命令将该函数所在文件包括到用户源文件中,系统自动去调。

答案:B 2、函数的定义

函数定义就是在程序中设定一个函数模块。 例3:

main( ) {

double sum(int a,double b );/*函数声明*/

}

double sum(int a,double b) /*函数定义*/ {

/*函数体*/

}

注意:

①函数名应符合C语言对标识符的规定。以字母或下划线开头,后跟字母、数字下划线的组合。

②形式参数写在函数后面的一对圆括号内,表示将从主调函数中接收哪些类型的信息,程序进行编译时,并不为形式参数分配存储空间。只有在被调用时,形式参数才临时地占有存储空间。

③函数返回值类型,如省略返回值类型系统默认为int型,对不需要使用函数返回值的函数,应定义为void类型。

④函数的外部性,函数不能嵌套,一个函数不能定义在别的函数内部。 3、函数声明

在主调函数中,要对在本函数中将要调用的函数事先作一声明。所谓“声明”是指向编译系统提供必要的信息:函数名,函数的类型,函数参数的个数,类型及排列次序。

①函数声明末尾要加;

C语言程序设计详解 40

②函数声明可以不写形参名,但必须写类型标识符。如上例中可以把声明改为:double sum(int ,double );但不能只写形式参名而不写类型如:double sum(a,b );

例4:若调用一个函数,且此函数中没有return语句,则正确的说法是() A)没有返回值

B)返回若干个系统默认值

C)能返回一个用户所希望的函数值 D)返回一个不确定的值 答案:D

例5、C语言规定,函数返回值的类型是由() A)return语句中的表达式类型决定 B)调用该函数时的主调函数类型所决定 C)调用该函数时系统临时决定

D)在定义该函数时所指定的函数类型所决定 答案:D

例6、下面函数调用语句含有实参个数为() func((exp1,exp2),(exp3,exp4,exp5)); 答案:2

例7、若输入的值是-125,以下程序的运行结果是( )。 #include “math.h” main() { int n;

scanf(“%d”,&n); n=fabs(n); fun(n); }

fun(int n) {

int k,r;

for(k=2;k<=sqrt(n);k++) {

r=n%k;

while(r==0)

{ printf(“%d”,k); n=n/k; if(n>1) printf(“*”); }

}

C语言程序设计详解 41

if(n!=1) printf(“%d\\n”,n); }

答案:-125=-5*5*5

例9、以下正确的函数定义形式是( )。 A)double fun(int x,int y) B)double fun(int x;int y) C)double fun(int x,int y); D)double fun(int x,y); 答案:A

例10、以下正确的函数形式是()。 A)double fun(int x,int y)

{z=x+y;return z;}

B)fun(int x,y)

{int z; return z;}

C)fun(int x,int y)

{int x,y;double z; z=x+y;return z;}

D)double fun(int x,int y)

{doble z;

z=x+y;return z;} 答案:D

4、函数的传值调用

参数是函数调用时进行信息交换的载体,关于形参与实参的说明: ①在定义函数中指定的形参,在未出现函数调用时,它们并不占用内存中的存储单元。只有在函数调用时,函数中的形参才被分配内存单元,形参与实参各占一个独立的存储空间,函数返回时,临时存储区被撤销。

②在被定义的函数中,必须指定形参的类型,实参可以是常量、变量或表达式,但要求它们有确切的值。实参与形参的类型应相同或赋值兼容。

③ C语言规定,实参变量对形参变量的数据传递是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回来给实能。

例11、 main( ) {

int a=3,b=5;

C语言程序设计详解 42

void swap(int x,int y); swap(a,b);

printf(“%d,%d”,a,b); }

void swap(int x,int y) {int temp;

temp=x;x=y;y=temp; } 输出结果:3,5

例12、以下正确的说法是()。 在C语言中,

A)实参与其对应的形参各占用独立的存储单元。 B)实参和与其对应的形参共占用一个存储单元

C)只有当实参和与其对应的形参同名时才共占用存储单元。 D)形参是虚拟的,不占用存储单元。 答案:A

例13、以下不正确的说法是()。 C语言规定

A)实参可以是常量、变量或表达式 B)形参可以是常量、变量或表达式 C)实参可以为任意类型

D)实参类型应与其对应形参的一致 答案:B

5、函数的递归调用

在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。

例14、用递归方法计算n!的函数rfact( )。假设n为正数。

求n!可以用递推方法,即从1开始,乘2,再乘3……一直乘到n。这种方法容易理解,也容易实现。递推法的特点是从一个已知的事实出发,按一定规律推出下一个事实,再从这个新的已知的事实出发,再向下推出一个新的事实。

float rfac1(int n) { int i; float t;

for(i=1;i<=n;i++) t=t*I; return(t); }

C语言程序设计详解 43

求n!也可以用递归方法,即5!=5*4!,而4!=4*3!,3!=3*2!,2!=2*1!,1!=1,可用下面的递归公式表示。

=1 n=1 rfact(n)

=rfact(n-1)*n n>1 long rfact(int n) {

if( n<=1)

return(1); else

return(n*rfact(n-1)); }

分析:递归总是由两部分组成的: ①递归方式 ②递归终止条件 例15、求1/n!

①递归方式 n>1 f15(n)=f15(n-1)*1/n ②递归终止条件 n=1 f15=1 double f15(int n) {

if(n==1) return(1); else

return(f15(n-1)*1/n); }

例16、s=1+1/2+1/3+…….+1/n

①递归方式 n>1 f16(n)=f16(n-1)*1/n ②递归终止条件 n=1 f16(n)=1 double f16(int n) {

if(n==1) return(1); else

C语言程序设计详解 44

return(f16(n-1)+1/n); }

例17、s=1-1/2+1/3-1/4+…..1/n 精确到10-6 ①递归方式 n>1 f17(n)=f17(n-1)±1/n ②递归终止条件 n=1 f17(n)=1 double f17(int n, int flag) {

if(n==1) return(1); else

return(f17(n-1,-flag)+1/n*flag); }

main()

{int n,flag;

scanf(“%d”,&n);

if (n%2==0) flag==-1; else flag==1;

printf(“%lf”,f17(n,flag)); }

例18、以下程序的功能是用递归法计算学生的年龄,已知第一位学生年龄最小,为10岁,其余学生一个比一个大2岁,求第5位学生的年龄。

①递归方式 n>1 f18(n)=f18(n-1)+2 ②递归终止条件 n=1 f18(n)=10 int f18(int n) {

if(n==1)

return(10); else

return(f18(n-1)+2); }

例19、求u,v两数的最大公约数

①递归方式 v!=0 f19(u,v)=f19(v,u%v) ②递归终止条件 v==0 f19(u,v)=u

int f19(int u,int v) {

if (v==0) return(u); else

return (f19(v,u%v)); }

C语言程序设计详解 45

例20、兔子繁殖问题、牛群繁殖问题

①递归方式 n>1 f20(n)=f20(n-1)+f20(n-2) ②递归终止条件 n=1 f20(n)=1 n=2 f20(n)=1 int f20(int n) {

if(n==1) return(1); else if(n==2) return(1); else

return(f20(n-1)+f20(n-2)); }

21、写出计算

Ackermann

函数

ack(m,n)的递归函数。对于

m>=0,n>=0,Ack(m,n)定义为: ack(0,n)=n+1 ack(m,0)=ack(m-1,1)

ack(m,n)=ack(m-1,ack(m,n-1))

①递归方式 n>1 ack(m,n)=ack(m-1,ack(m,n-1)) ②递归终止条件 n=0 ack(m,n)=ack(m-1,1) m=0 ack(m,n)=n+1

double ack(int m,int n) {

if(m==0)

return(n+1); else if(n==0)

return(ack(m-1,1)); else

return(ack(m-1,ack(m,n-1))); }

例22、分别写出Hermite多项式Hn(x)的值的递推和递归函数。Hn(x)定义如下:

H0(x)=1 H1(x)=2x

Hn(x)=2xHn-1(x)-2(n-1)Hn-2(x) 递推法:

C语言程序设计详解 46

double h1(int n,float x) {

float s1=1,s2=2*x,s3; int i;

if(n==0) return(1);

else if(n==1) return(2*x); else

{ for(i=2;i<=n;i++)

{s3=2*x*s2+2*(n-1)*s1; s1=s2; s2=s3;

}

} }

递归法:

①递归方式 n>1 h(n,x)=2*x*h(n-1,x)-2*(n-1)*h(n-2,x) ②递归终止条件 n=0 h(n,x)=1 n=1 h(n,x)=2*x double h1(int n,float x) {

if(n==0) return(1);

else if(n==1) return(2*x);

else return(2*x*h(n-1,x)-2*(n-1)*h(n-2,x)); }

例23、求a的平方根

递推法:

double sq_root(double a) { double x; x=a;

while(fabx(x*x)-a)>=1e-6) x=(x+a/x)*0.5; return(x); } 递归法:

①递归方式 fabx(x*x)-a)>=1e-6 sqroot(x,a)=sqroot((x+a/x)*0.5,a) ②递归终止条件 fabx(x*x)-a)<1e-6 sqroot(x,a)=x double sqroot(double x,double a) {

if(fabs(x*x)-a<1e-6) return(x); else

C语言程序设计详解 47

return(sqroot((x+a/x)*0.5,a)) }

例24、求一个给定数字的所有质因子,如72=2*2*2*3*3 递推法:

void yizi(int n) {int i=2,flag=0; while(n!=1) {

if(n%i==0) {

if(flag==0) {printf(“%d=%d”,n,i); flag=1; } else printf(“*%d”,i); n=n/i; }

else i=i+1; } } 递归法:

void yizi(int n,int i,int flag) {if (n!=1) {

if(n%i==0)

{

if (flag==0) {printf(“%d=%d”,n i); flag=1;} else printf(“*%d”,i);

yizi(n/i,i,flag); } else

yizi(n,i+1,flag); } }

例24、用递归法将一个整数n转换成字符串 void conver(int n) {int i;

if(i=n/10)!=0) convert(i);

putchar(n%10+’0’); }

二、变量的存储属性 1、动态变量

动态变量是C程序中使用最多的一种变量,在程序执行过程中自动进行建

C语言程序设计详解 48

立和撤销,它们存在于程序的局部,也只在这个局部中可以使用,这种变量称为动态变量,动态变量有两种:自动(auto)变量和寄存器(register)变量。

在一个函数内部定义的变量是局部 例25:

main() { int x=1; {

void prt(void); int x=3; prt( );

printf(“x=%d\\n”,x); }

printf(“x=%d\\n”,x); }

void prt(void) {

int x=5;

printf(“x=%d”,x); } 注意:

1、系统在程序执行过程中动态建立动态撤消,在赋值前它的值是不确定的。 2、局部可用。

3、外层的变量被内层的同名变量屏蔽。 例26:以下正确的说法是()

如果在一个函数中的复合语句中定义了一个变量,则该变量( ) A)只在该复合语句中有效 B)在该函数中有效 C)在本程序范围内均有效 D)为非法变量

例27:以下正确的说法为( )

A)在不同函数中可以使用相同名字的变量 B)形式参数是局部变量

C)在函数内定义的变量只在本函数范围内有效

D)在函数内的复合语句中定义的变量在本函数范围内有效 2、寄存器变量 register

C语言程序设计详解 49

通常把使用频率较高的变量定义为寄存器变量。 3、静态变量 static 注意:

①在编译时为其分配空间,如不赋初值,初值为0。 ②局部可用或全局可用。 ③静态变量具有可继承性。 4、外部变量

在一个文件中,定义在所有函数之外的变量称为外部变量。 注意:

①在编译时为其分配空间。 ②全局可用。

③限定本文件的外部变量只在本文件使用

static int a=3; main( ) { }

④将外部变量的作用域在本文件范围内(或在其它文件)扩充。 extern 三、编译预处理 注意:

①编译预处理是在编译前对源程序进行的一些预加工。 ②C语言 的预处理命令均以“#”开头,末尾不加分号 ③编译预处理命令可以出现在程序中的任何位置 1、宏替换 ①字符串宏替换 ②带参的宏替换 注意:

①宏名与宏体之间应以空格相隔 ②宏名不能用引号

③较长的定义在一行写不下时,可在末尾加 \\。

④对带参宏定义时、宏休及其各个形参应用括号括起来。

C语言程序设计详解 50

2、文件包含

格式1:#include“文件标识” 格式2:#include<文件名>

例28:以下叙述中不正确的是() A)预处理命令行都必须以#开头

B)在程序中凡是以#号开头的语句行都是预处理命令 C)C程序在执行过程中对预处理命令行进行处理 D)以下是正确的宏定义

#define IBM_PC

例29:以下叙述中正确的是()

A)在程序的一行上可以出现多个有效的预处理命令行 B)使用带参的宏时,参数的类型应与宏定义时的一致 C)宏替换不占用运行时间,只占编译时间 D)在以下定义中C R是称为“宏名”标识符 #define C R 045

例30:设有以下宏定义: #define WIDTH 80

#define LENGTH WIDTH+40

则执行赋值语句:v=LENGTH*20(v为int 型变量)后,v的值是( )。

C语言程序设计详解 51

第五章 数组

数组是指一组同类型数据组成的序列,用一个统一的数组名标识这一组数据,用下标来指示数组中元素的序号,同一数组中的所有元素必须属于同一数据类型。

一、一维数组 1、一维数组的定义

一维数据的定义方式为:类型说明符 数组名[常量表达式];例如:int a[10];说明:

①数组名定名规则和变量名相同,遵循标识符定名规则。 ②数组名后是用方括号括起来的常量表达式,不能用圆括号。 ③常量表达式表示元素的个数,即数组长度。

④常量表达式中可以包括常量或符号常量,不能包含变量。 例1:以下对一维数组a的正确说明是( )。 A)int a(10); B)int n=10,a[n]; C)int n;scanf(“%d”,&n); D)#define SIZE 10

int a[n]; int a[SIZE]; 答案:D

2、一维数组的初始化

①可对全部元素赋初值:例如:int a[5]={1,3,5,7,9}; ②可给部分赋值:例:int a[5]={1,3,5}; ③如果想使全部元素为1:

例 int a[5]={1,1,1,1,1};(注:不能省略) ④在对全部元素赋值时,可不指定数组长度。

例 int a[ ]={1,2,3,4,5,6};

⑤如对一个静态或外部的数组不进行初始化,隐含的初值为0。如不对动态数组初始化,则其初始值为一些不可预料的数。

例2:以下能对一维数组a进行正确初始化的语句是( )。 A)int a[10]=(0,0,0,0,0); B)int a[10]={}; C)int a[]={0}; D)int a[10]={10*1};

答案:C

C语言程序设计详解 52

例3:以下不正确的定义语句是( )。

A)double x[5]={1.0,2.0,3.0,4,0,5.0}; B)int y[5]={1,2,3,4,5,6}; C)char c1[]={‘1’,’2’,’3’,’4’,’5’}; D)char c2[]={‘\\x10’,’\\xa’}; 3、一维数组元素的引用

数组元素的表示形式为:数组名[下标] 例4:数组元素引用实例 main( ) {int I,a[10] for(I=0;I<=9;I++) a[i]=I; for(I=0;I<=0;I++) printf(“%d”,a[i]); } 说明:

①下标可以是整型常量、变量或表达式 ②不要越界

例5:若有说明:int a[10];则对a数组元素的正确引用是( )。 A)a[10] B)a[3.5] C)a(5) D)a[10-10]

例6:下面程序中有错误的行是( )注:每行程序前面的数字表示行号

1 main()

2 { int a[3]={1}; 3 int i;

4 scanf(“%d”,&a);

5 for(I=1;I<3;I++) a[0]=a[0]+a[i]; 6 printf(“a[0]=%d\\n”,a[0]); 7 } 答案:4

4、数组名作为函数参数

main( )

C语言程序设计详解 53

{void swap(int x[2]) int a[2]={3,5}; swap(a);

printf(“%d,%d\\n”,a[0],a[1]); }

void swap(int x[2]) {int t;

t=x[0];x[0]=x[1];x[1]=t;

}

输出结果:5,3 注意:

以数组名作参数时,采取的不是“值传递”方式,而是“地址传送”方式,即把实参数组起始地址传给形参数组,这样形参数组就和实参数组共占同一段内存单元。

5、一维数组的应用举例

例7:对n个数排序(由小到大)起泡法

基本思想:将相邻两个数a[0]与a[1]比较,按要求将这两个数排好序;再将a[1]与a[2]比较,.….依次处理,直到将最后两个数比较处理完毕。

void bubble(int a[],int n)

{int I,j,temp

for(I=1;I<=n-1;I++)

for(j=0;j<=n-I-1;j++) if(a[j]>a[j+1]) {

temp=a[j]; a[j]=a[j+1]; a[j+1]=temp;

}

}

例8:选择法:从所有元素中选择一个最小元素放在a[0]作为第一轮;第二轮是从a[1]开始到最后一个元素选择一个最小的放在a[1]中以此类推。n个数要比较n-1轮。

C语言程序设计详解 54

void selectsort(int a[],int n) {int I,j,p,temp;

for(I=0;Ifor(j=I+1;I{temp=a[p];a[p]=a[i];a[i]=temp;} } }

例9:插入法:有n个数,已按由小到大顺序排列好,要求输入一个数据,把它插入到原有数列中,而仍然保持有序。

void f(int a[ ],int n,int x) {int I,j;

while(a[i]<=x && Ix)

{for(j=n-1;j<=I;j--) a[j+1]=a[j]; a[j]=x; } else

a[i]=x; }

例10:插入法:下面程序的运行结果是( )。 main()

{ int I=0,n=3,j,k=3; int a[5]={1,4,5};

while(I<=n&&k>a[I]) I++; for(j=n-1;j>=I;j--) a[j+1]=a[j]; a[i]=k;

for(I=0;I<=n;I++)

printf(“%3d”,a[i]); }

答案:1 3 4 5

例11:插入法:若有以下程序段: …………..

int a[]={4,0,2,3,1},I,j,t; for(I=1;I<5;I++) {t=a[i];j=I-1;

while(j>=0&&tC语言程序设计详解 55

{a[j+1]=a[j];j--;} a[j+1]=t; }

for(I=0;I<5;I++)

printf(“%d ”,a[i]); …………

则该程序段的输出结果是( )。 答案:0 1 2 3 4

例12:下面程序用“两路合并法”把两个已按升序排列的数组合并成一个升序数组。请填空。

main()

{ int a[3]={5,9,19};

int b[5]={12,24,26,37,48}; int c[10],I=0,j=0,k=0; while(I<3&&j<5) if(__________)

{c[k]=b[j];k++;j++;} else

{c[k]=a[i];k++;I++;} while(________)

{ c[k]=b[j];k++;j++;} while(________)

{ c[k]=a[i];k++;I++;} for(I=0;Iprintf(“%3d”,c[i]); }

例13:折半查找法

void binary_search(int a[],int n,int x) {int mid,top=0,bot=n-1,I,find=0; do

{mid=(top+bot)/2; if(x==a[mid])

{printf(“found”);find=1;} else if(x例14:下面程序用“顺序查找法”查找数组a中是否存在某一关键字。请填空。

main()

{int a[8]={25,57,48,37,12,92,86,33}; int I,x;

C语言程序设计详解 56

scanf(“%d”,&x); for(I=0;I<8;I++) if(x==a[I])

{printf(“Found! The index is :%d\\n”,--i);____________;} if(____________)

printf(“Can’t found!”); }

例15:下面程序的运行结果是( )。 main()

{int a[9]={0,6,12,18,42,44,52,67,94}; int x=52,I,n=9,m; I=n/2+1; m=n/2;

while(m!=0) {

if(x{I=I-m/2-1;m=m/2;} else if(x>a[i])

{I=I+m/2+1;m=m/2;} else break; }

printf(“The index is:%d”,I); }

答案:The index is:6

例16:要求写一函数,实现对包含任意个数据的数列实现头尾颠倒。 void f(int a[ ],int n) {int I,t;

for(I=0;It=a[i];a[i]=a[n-i];a[n-i]=t; }

}

例17:下面程序的功能是输入5个整数,找出最大数和最小数所在的位置,并把二者对调,然后输出调整后的5个数。请填空。

main() {

int a[5],max,min,I,j,k; for(I=0;I<5;I++)

scanf(“%d”,&a[i]); min=a[0];

for(I=1;I<5;I++)

if(a[i]C语言程序设计详解 57

max=a[0];

for(I=1;I<5;I++)

if(a[i]>max) {max=a[i];________________;} ________________________ printf(“%d,%d”,k,j); for(I=0;I<5;I++)

printf(“%5d”,a[i]); } 答案:

例18:下面程序的运行结果是( )。 main()

{int a[10]={1,2,2,3,4,3,4,5,1,5}; int n=0,I,j,c,k;

for(I=0;I<10-n;I++) {c=a[i];

for(j=I+1;j<10-n;j++) if(a[j]==c)

{for(k=j;k<10-n;k++) a[k]=a[k+1]; n++;

} }

for(I=0;I<10-n;I++) printf(“%d”,a[i]); }

答案:12345

例19:当从键盘输入18并回车后,下面程序的运行结果是( )。 main() {

int x,y,I,a[8],j,u,v; scanf(“%d”,&x); y=x;I=0; do

{ u=y/2; a[i]=y%2; I++;y=u; }while(y>=1);

for(j=I-1;j>=0;j--) printf(“%d”,a[j]); }

答案:10010

例20:有17个人围成一圈,编号为0—16,从第0号的人开始从1报数,

C语言程序设计详解 58

凡报到3的倍数离开圈子,然后再数下去,直到最后只剩下一个人为止,问此人原不的位置是多少号。

main()

{int a[17],I,t=0,s=0; for(I=0;I<17;I++) a[i]=1; while(t<=16)

{ for(I=0;I<17;I++)

if(a[i]==0) {s=s+1;

if(s%3==0) {a[i]=0;t=t+1;} }

}

for(I=0;I<17;I++)

if(a[i]==1) printf(“%d”,i); }

二、二维数组 1、二维数组的定义

二维数组定义的一般形式为:

类型说明符 数组名[常量表达式][常量表达式] 注意:

二维数组在内存中是按一维连续顺序存放的。设有一个m*n的二维数组a,其中第i行第j列元素a[i][j]在数组中的顺序号计算公式为:i*n+j

例21:以下对二维数组a的正确说明是( )。

A)int a[3][] B)float a(3,4) C)double a[1][4] D)float a(3)(4) 答案:C

2、二维数组的引用

二维数组的元素的表示形式为:数组名[下标][下标]

例22:若有说明:int a[3][4];则对数组元素的正确引用是( )。 A)a[2][4] B)a[1,3] C)a[1+1][0] D)a(2)(1) 答案:C

3、二维数组初始化 ①分行给二维数组赋初值

如:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; ②可写在一个花括弧内

C语言程序设计详解 59

如:int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; ③可给部分赋值

如:int a[3][4]={1,2,3}; 如:int a[3][4]={{1},{2},{3}}; ④可省略一维长度

如:int a[ ][4]={1,2,3,4,5,6,7,8,9,10}; 如:int a[ ][4]={{1},{2},{3}};

例23:以下不能对二维数组a进行正确初始化的语句是()。 A)int a[2][3]={0}; B)int a[ ][3]={{1,2},{0}};

C)int a[2][3]={{1,2},{3,4},{5,6}}; D)int a[ ][3]={1,2,3,4,5,6}; 答案:C

例24:若有说明:int a[ ][3]={1,2,3,4,5,6,7};则a数组第一维的大小是(答案:3

4、函数参数(p 160)

例25:求一个3*4矩阵的所有靠外侧的元素之和。设矩阵为: 3 8 9 10 a= 2 5 –3 5 7 0 -1 4

main()

{int add(int m,int n,int arr[]);

int total,a[3][4]={3,8,9,10,2,5,-3,5,7,0,-1,4}; total=add(3,4,a[0]);

printf(“total=%f”,total); }

add(int m,int n,int arr[]) {int I,j,sum=0;

for(I=0;Isum=sum+arr[I*n+j]; for(j=0;jsum=sum+arr[I*n+j];

。 )

}

5、二维数组举例

C语言程序设计详解 60

例26:将一个二维数行、列互换后输出。 Void f(int a[ ],int n,int m ,int b[ ]) {int I,j;

for(I=0;Ib[j*n+i]= a[I*m+j]; for(j=0;jfor(I=0;Iprintf(“%4d”,b[j*n+i]); printf(“\\n”); } } 例27:求矩阵对角线元素之和

main()

{int a[3[3]={1,3,6,7,9,11,14,15,17},sum=0,I,j; for(I=0;I<3;I++) for(j=0;j<3;j++)

if((I==j)||(I+j==3)) sum=sum+a[I][j];

}

例28:下面程序的功能是检查一个二维数组是否对称(即:对所有I和j都有a[I][j]=a[j][I])。请填空。

main()

{int a[4][4]={1,2,3,4,2,2,5,6,3,5,3,7,4,6,7,4}; int I,j,found=0 for(I=0;I<4;I++) for(j=0;Jif(a[i][j]!=a[j][i] ) {found=1;break;} if(found) printf(“No”); }

例29:以下程序是求矩阵a,b的和,结果存入矩阵c中并按矩阵形式输出。请填空。

2 -1 -7 -9 a= -4 0 b= -8 10 3 1

main()

{int a[3][2]={2,-1,-4,0,3,1};

C语言程序设计详解 61

int b[4][3]={7,-9,-8,10}; int I,j,k,s,c[3][2]; for(I=0;I<3;I++) for(j=0;j<2;j++)

{for(s=0,k=0;k<2;k++) s+=a[i][k]*b[k][j]; c[i][j]=s; }

for(I=0;I<3;I++)

{

for(j=0;j<2;j++)

printf(“%6d”,c[I][j]); printf(“\\n”); } }

例30:下面程序的运行结果是( )。 main()

{int I,j,row,col,min;

int a[3][4]={{1,2,3,4},{9,8,7,6},{-1,-2,0,5}}; min=a[0][0]; for(I=0;I<3;I++) for(j=0;j<4;j++) if(a[i][j]{min=a[i][j];row=I;col=j;} printf(“%d,%d,%d\\n”,min,row,col); } 答案:

例31:找出一个二维数组中的鞍点,即该位置上的元素在该行上最大,该列上最小。也可能没有鞍点。

void f31(int m, int n, int arr[] ) {int I,j,k,max,row,col,flag; for(I=0;I{max=arr[I*n+0]; row=I;col=0; for(j=1;jif(arr[I*n+j]>max) {max=arr[I*n+j]; row=I;col=j;}

flag=1;

for(k=0;kif(arr[k*n+j]if(flag==1) printf(“鞍点的位置:第%d行,第%d列”,I,j); } }

例32:打印出以下的杨辉三角形(包括10行)

1 1 1 1 1

1 2 1

C语言程序设计详解 62

3 3 1 4 6 4 1

1 5 10 10 5 …....….....

main()

{int a[10][10],I,j; for(I=0;I<10;I++)

{

a[I][0]=1; a[I][I]=1; }

for(I=2;I<10;I++) for(j=1;Ja[I][j]=a[I-1][j]+a[I-1][J-1]; }

例33:下面是一个5*5阶螺旋方阵。试编程打印出此形式的n*n的方阵 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9

main()

{ int a[10][10],I,j,k=0,m,n; printf(“%d”,&n);

if(n%2==0) m=n/2; else m=n/2+1; for(I=0;I=I;j--) {k++;a[n-I-1][j]=k;} for(j=n-I-2;j>=I+1;j--) {k++;a[j][i]=k;} }

C语言程序设计详解 63

for(I=0;Iprintf(“%5d”,a[i][j]); printf(“\\n”); } }

例34:打印“魔方阵”。所谓魔方阵是指这样的方阵,它的每一行、每一列和对角线之和均相等。例如:三阶魔方阵为

8 1 6 3 5 7 4 9 2

答案:

三、字符数组

用来存放字符数据的数组是字符数组。字符数组中的一个元素存放一个字符。

1、字符数组的定义 char a[10];

2、字符串的结束标志

为了测定字符串的实际长度,C语言规定了一个“字符串的结束标志”,以字符‘\\0’代表。

例35:下面程序段的运行结果是( ) char c[5]={‘a’,’b’,’\\0’,’c’,’\\0’}; printf(“%s”,c); 答案:ab

3、字符数组的初始化 ①逐个字符赋值

C语言程序设计详解 64

char c[10]={‘c’,’o’,’m’,’p’,’u’,’t’,’e’,’r’}; ②对一个字符数组指定一个字符串初值 char c[10]={“computer”};

系统允许在初始化一个一维字符数组时,省略字符串常量外面的花括号。 如:char c[10]=”computer”

例36:下面是对s的初始化,其中不正确的是() A)char s[5]={“abc”}; B)char s[5]={‘a’,’b’,’c’}; C)char s[5]=”” D)char s[5]=”abcdef” 答案:D

例37:对两个数组a和b进行如下初始化 char a[]=”ABCDEF”;

char b[]={‘A’,’B’,’C’,’D’,’E’,’F’};则以下叙述正确的是( )。 A)a与b数组完全相同 B)a与b长度相同 C)a和b中都存放字符串 D)a数组比b数组长度长 答案:D

4、字符数组的输入和输出

①逐个字符输入输出。用格式符“%c”输入或输出一个字符。 ②将整个字符串一次输入和输出。用“%s”。

③为了解决scanf函数不能完整地读入带有空格字符的字符串,C语言提供了一个专门用于读字符串的函数gets,它读入全部字符(包括空格),直到遇到回车符为止,用gets(s)表示。

puts(s)的作用是将一个字符串(以’\\0’结束的字符序列)输出到终端,在输出时将字符结束标志’\\0’转换成’\\n’,即输出完字符串后换行。

例38:下面程序段的运行结果是() char c[5]={‘a’,’b’,’\\0’,’c’,’\\0’}; printf(“%s”,c);

A)’a’’b’ B)ab C)ab c D)a b 答案:B

C语言程序设计详解 65

例39:有两个字符数组a、b,则以下正确的输入语句是() A)gets(a,b); B)scanf(“%s%s”,a,b); C)scanf(“%s%s”,&a,&b); D)gets(“a”),gets(“b”); 答案:B

例40:有字符数组a[80]和b[80],则正确的输出语句是() A)puts(a,b) B)printf(“%s,%s”,a[],b[]); C)putchar(a,b) D)puts(a),puts(b) 答案:D

5、字符串运算函数

①字符串拷贝函数strcpy如strcpy(str1,”China”) strcpy(str1,str2) ②字符串连接函数strcat如strcat(str1,str2) ③字符串比较函数strcmp如strcmp(str1,str2) ④测字符中长度函数strlen如strlen(“Computer”) 例41;下面程序段的运行结果是( ) char c[ ]=”\\\v\\\\\\0will\\n”; printf(“%d”,strlen(c)); 答案:3

例42:下面程序段的运行结果是( )。 char a[7]=”abcdef”; char b[4]=”ABC”; strcpy(a,b); printf(“%c”,a[5]); 答案:e

例43:判断字符串a和b是否相等,应当使用() A)if(a==b) B)if(a=b) C)if(strcmp(a,b)) D)if(strcpy(a,b)) 答案:C 6、二维数组

二维数组可以认为由若干个一维数组所组成的,因此一个n*m的二维字符数组可以存放n个字符串。

例44:写出程序的输出结果()

C语言程序设计详解 66

main() {

char str[3][6]={“China”,”Japan”,”Korea”}; str[1][5]=’ ’;

printf(“%s\\n”,str[1]); }

答案:Japan Korea 7、字符串数组举例

例45:下面程序段将输出computer,请填空。char c[]=”It’s a computer”; for(I=0;_____________;I++)

{____________;printf(“%c”,c[j]); } 答案: I<=7 J=I+7

例46:下面程序段的运行结果是( char x[]=”the teacher”; I=0;

while(x[++i]!=’\\0’)

if(x[I-1]==’t’) printf(“%c”,x[i]); 答案:he 例47:删除字符

删除一个字符串中的一个字符 ① void del(char a[ ],char b[ ],int n) {int I,j=0;

for(I=0;a[i]!=’\\0’;I++) if(I!=n) b[j++]=a[i] }

② void del(char a[ ],int n)

{

strcpy(&a[n],&a[n+1]); }

。 )

C语言程序设计详解 67

删除一个字符串中的某个字符 void f(char a[ ],char x)

{int I;

for(I=0;a[i]!=’\\0’;I++)

if(a[i]==x) strcpy(&a[I],&a[I+1]); }

例48:下面程序的功能是将已按升序排好序的两个字符串a和b中的字符按升序归并到字符串c中,请填空。 #include “stdio.h” main() {

char a[]=”acegikm”; char b[]=”bdfhjlnpq”; char c[80],*p; int I=0,j=0,k=0;

while(a[i]!=’\\0’ && b[j]!=’\\0’) {if(a[i]c[k]=’\\0’;

if(____________) p=b+j; else p=a+I; strcat(c,p); puts(c); }

答案: c[k]=a[I++] c[k]=b[j++] a[i]==’\\0’

例49:有已排好序的字符串a,下面的程序是将字符串s中的每个字符按升序的规律插入到a中。请填空。 #include main() {

char a[20]=”cehiknqtw”; char s[]=”fbla”;

C语言程序设计详解 68

int I,k,j;

for(k=0;s[k]!=’\\0’;k++) {j=0;

while(s[k]>=a[j]&&a[j]!=’\\0’) j++ for(________________)

(__________________); a[j]=s[k]; }

puts(a); } 答案:

I=strlen(a);I>=j;I— a[i+1]=a[i]

例50:下面程序的功能是在三个字符串中找出最小的。请填空。 main()

{char s[20],str[3][20];

int I;

for(I=0;I<3;I++) gets(str[i]); strcpy(s,________);

if(strcmp(str[2],s)<0) strcpy(s,str[2]); printf(“%s\\n”,__________); } 答案:

(strcmp(str[0],str[1]))<0?str[0]:str[1] s

例51:下面程序的运行结果是( ) #include “stdio.h” main( )

{char s[ ]=”ABCCDA”,c; int k; for(k=1;(c=s[k])!=’\\0’;k++) {switch(c)

{case ‘A’:putchar(‘%’);continue;

case ‘B’:++k;break; default:putchar(‘*’);

case ’C’:putchar(‘&’);continue; }

putchar(‘#’); } }

答案:#&*&%

例52:输入一行字符,统计其中有多少个单词,规定单词间以一个或多个空

格相隔。

C语言程序设计详解 69

#include “stdio.h” main( ) {

char string[81]; int I,s=0,flag=0; gets(string);

for(I=0;string[i]!=’\\0’;I++) {

if((flag==0)&&(a[i]>=’a’&&a[i]<=’z’)||(a[i]>=’A’&&a[i]<=’Z’))

{flag=1; s=s+1; }

if a[i]=’ ’ flag=0;

}

printf(“%d”,s); }

C语言程序设计详解 70

第六章 指针

一、指针的概念

指针即地址,一个变量的指针就是指该变量的地址,存放指针的变量就是指针变量。

注意:指针变量中只能存放地址。 二、指针变量的定义和引用 1、指针变量的定义

int *p; 此语句定义了一个指针变量p,p中可存放一个整型变量的地址。 注意:

①*是指针变量的特征

②只是分配了一个存储单元,并没有指真正指向,要想使一个指针变量指向一个整型变量必须赋值。例如: int *p,I=3; p=&I;

2、指针变量的引用(两个有关指针的运算符) ①& 取地址运算符号

②* 指针运算符 *p表示p所指向的变量值。 例3:

int *p,a;

p=&a; /*指向变量a的值赋给p*/

scanf(“%d”,p); /*从键盘输入一个值赋值给p所指向的变量a*/ *p=5; /*把5赋值给变量p所指向的a*/

例4:使两个指针变量交换指向 main() {

int *p1,*p2,*p,a=10,b=20; p1=&a,p2=&b;

printf(“%d,%d\\n”,*p1,*p2); p=p1;p1=p2;p2=p;

printf(“%d,%d\\n”,*p1,*p2); }

C语言程序设计详解 71

a 10 &a p1 a 10 &b p1

b 20 &b p2 b 20 &a p2 (a) (b)

例5:交换两个指针变量所指向的变量的值。 main() {

int *p1,*p2,a=10,b=20,t; p1=&a,p2=&b;

printf(“%d,%d\\n”,*p1,*p2); t=*p1;*p1=*p2;*p2=t;

printf(“%d,%d\\n”,*p1,*p2); } a 10 &a p1 a 20 &a p1

b 20 &b p2 b 10 &b p2

(a) (b) 例6:以下程序错误的原因是( )。 main( ) {

int *p,*q,a,b; p=&a;q=&b; scanf(“%d”,*p); *p=*q; } 答案:

例7:若有定义int a=5;下面对(1),(2)两个语句的正确解释是( )。 1、int *p=&a; 2、*p=a; A) 语句1和2中的*p含义相同。

B) 1和2语句的执行结果都是把变量a的地址赋给指针变量p

C) 1在对p进行说明的同时进行初始化,使p指向a,2将变量a的值赋给

指针变量p。

C语言程序设计详解 72

D) 1在对p进行说明的同时进行初始化,使p指向a,2将变量a的值赋于*p。 答案:

例8:若有语句int *point,a=4;和point=&a;下面均代表地址的一组选项是( )。 A) a, point, *&a B) &*a,&a,*point C) *&point,*point,&a D)&a,&*point,point 答案:

三、指针作为函数参数

函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型,它的作用是将一个变量的地址传送到另一个函数中。

例9:输入a和b两个整数,按先大后小的顺序输出a和b。 main( ) {

void swap(int *px,int *py); int x,y;

swap(&x,&y);

if(xvoid swap(int *px,int *py) { int t;

t=*px; *px=*py; *py=t; }

main( ) swap(px,py)

X y 例10:一组数组有10个元素,要求输出最大值和最小值。

main( )

{int arr[10]={-1,2,3,-4,-5,7,8,9,10,-7},*p1,*p2,a,b; p1=&a;p2=&b;

max_min(arr,p1,p2); printf(“%d,%d”,a,b); }

void maxmin(int arr[ ],int *pt1,int *pt2)

&b px &a py

C语言程序设计详解 73

{int I;

*pt1= *pt2= arr[0]; for(I=1;I<10;I++)

{if(*pt1>arr[i]) *pt1=arr[i]; if(*pt2>arr[i]) *pt2=arr[i]; } }

四、指针与数组

1、一维数组的指针表示方法 (1)数组中各元素的地址。 int a[10]={1,2,3,4,5,6,7,8,9,10}; a 1 2

①&a[0] &a[1] &a[2] 、、、&a[i]、、、&a[9] ②a a+1 a+2 、、、a+i、、、、、a+9 注意:

在编译系统计算实际地址时,a+i中的i要乘上数组元素所占的字节数,即a+i*(一个元素所占的字节数)

(2)数组元素值

①a[0] a[1] a[2] 、、、、a[i]、、、、a[9] ②*(a+0) *(a+1) *(a+2)、、*(a+i) *(a+9) 说明:

引用一个数组元素,可以用下标法:如a[i]形式;也可以用指针法如*(a+i)形式。

例11:若有以下定义,int a[5],*p=a;则对数组元素的正确引用是() (A) *&a[5] (B) a+2 (C)*(p+5) (D)*(a+2) 答案:

例12:对数组元素地址的正确引用是()

(A)p+5 (B) *a+1 (C)&a+1 (D)&a[0] 答案:

例13:若有定义,则数值不为3的表达式是( ):

3 4 5 6 7 8 9 10

C语言程序设计详解 74

int x[10]={0,1,2,3,4,5,6,7,8,9},*p1;

A) x[3] B) p1=x+3,*p1++ C) p1=x+2,*(p1++) D) p1=x+2,*++p1 答案:

例14:分别用下标法、地址法访问数组元素

main( )

{int a[5]={1,3,5,7,9},I,*p; for(I=0;I<5;I++) printf(“%d”,a[i]); for(I=0;I<5;I++) printf(“%d”,*(a+i)); for(p=0;p①指针变量可以实现使本身的值改变,但不要出现a++,因为a是数组名,它是数组首地址是常量,它的值在程序运行期间是固定不变的。

②要注意指针变量的当前值。 2、二维数组的指针表示方法

例:int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 1、每行的起始地址 a 1 5 9 2 6 10 3 7 11 4 8 12

①&a[0][0] &a[1][0] &a[2][0] a[0] a[0][0] a[0][1] a[0][2] a[0][3]

1 2 3 4 a[1] a[1][0] a[1][1] a[1][2] a[1][3]

1

2 3 4 C语言程序设计详解 75

a[2] a[2][0] a[2][1] a[2][2] a[2][3]

1 2 3 4 ②a[0] a[1] a[2] a a[0] a[1] a[2] ③a+0 a+1 a+2

④*a *(a+1) *(a+2) ⑤&a[0] &a[1] &a[2] 2、各元素的地址

①&a[0][0] &a[0][1] &a[0][2] ②a[0]+1 a[0]+2 a[1]+2 ③*a+1 *(a+1)+1 *(a+2)+2 3、各元素的值

①*(&a[0][0]) *(&a[0][1]) *(&a[0][2]) ②*(a[0]+1) *(a[0]+2) *(a[1]+2) ③*(*a+1) *(*(a+1)+1) *(*(a+2)+2) 例15:指向数组元素的指针变量 main( )

{int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int *p;

for(p=a[0];p例16:指向一维数组的指针变量 main( )

{int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int I,j, (*p)[4]; p=a;

for(I=0;I<3;I++) for(j=0;j<5;j++)

printf(“%d”,*(*(p+I)+j));

} 注意:

C语言程序设计详解 76

int (*p)[5]表示p是指针变量,它指向一个包含5个元素的一维数组 int *p[5] 是指针数组。

例17:若有以下定义和语句int a[2][3],(*p)[3];p=a;则对a数组元素地址的正确引用为( )

(A)*(p+2) (B) p[2] (C) p[1]+1 (D)(p+1)+2 则对a数组元素的正确引用是()

(A)(p+1)[0] (B) *(*(p+2)+1) (C)*(p[1]+1) (D)p[1]+2 例18:若有以下定义:

int x[4][3]={1,2,3,4,5,6,7,8,9,10,11,12}; int (*p)[3]=x;

则能够正确表示数组元素 x[1][2]的表达式是( ) (A)*((*p+1)[2]) (B)(*p+1)+2 (C) *(*(p+5)) (D)*(*(p+1)+2) 答案:

例19:若有以下定义和赋值语句,则对b数组的第I行第j列元素的非法引用为( )。

Int b[2][3]={0},(*p)[3]; P=b;

A) *(*(p+i)+j) B) *(p[i]+j) C) (p+i)+j D) (*(p+i))[j]

例20:写出下面的输出结果 main( ) {

int *p,a[10]={1,2,3,4,5,6,7,8,9,10}; p=a;

scanf(“%d”,&*p); 按自右向左方向结合运算,因此先执行*再执行&。

printf(“%d”,*&a[0]); 按自右向左方向结合运算,因此先执行&再执行*。 printf(“%d”,*p++);

C语言程序设计详解 77

printf(“%d”,(*p)++); printf(“%d”,*++p); printf(“%d”,++*p); } 答案:

注意:++、 *、 &同优先级,是向右而左的结合方向。

3、数组指针作为函数参数

在数组一章中介绍了数组名作函数参数的情况。数组名代表数组起始地址,用数组名作参数传递的是地址(将数组起始地址传递组被调用函数的形参),既然地址可以作为参数传递,那么指向数组的指针变量当然也可以作为函数参数。

例21:求二维数组中全部元素之和 main( )

{ int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int *p=a[0],total; total=add(p,12);

printf(“total=%d\\n”,total); } int add(int arr[ ],int n) {

int I,sum=0; for(I=0;Isum=sum+arr[i];

return(sum); }

注意:

在用数组名作函数参数时,数组名代表数组首地址,在调用函数时,实际上是把数组的首地址传给形参,形参与实参共占用一段内存。

例22:有3个学生,每人考5门课,求每个学生的平均分和每门课的平均分数

main( )

{

float stu_ave(float (*p)[5]); float cour_ave(float *pt);

float score[3][5]={{100,60,70,80,67},{62,71,98,45,57},{90,39,89,39,90}}; int I;

for(I=0;I<3;I++)

printf(“%f”,stu_ave(score+i));

C语言程序设计详解 78

for(I=0;I<5;I++)

printf(“%f”,cour_ave(score[0]+i)); }

float stu_ave(float (*p)[5]) {

int j; float sum; float sum=0,ave; for(j=0;j<5;j++)

sum=sum +*(*p+j); return(sum/5) }

float cour_ave(float *pt) {int I;

float sum;

for(I=0;I<3;I++) {sum=sum+*pt; pt=pt+5; }

return(sum/3); }

五、字符串与指针

字符串----用双引号引起来的0个或多个有效字符序列称为字符串。 1、定义:

char string[10]; char *s 2、初始化

char str[12]=”china”; char *s=”china”; 顺次赋值,在末尾加’\\0’作为结束标志。 str

只把china的首地址赋给指针变量s。

s c h i n a \\0 c h i n a \\0 例23:下面判断正确的是( )

(A)char *a=”china”;等价于char *a;*a=”china”; (B)char str[10]={“china”};等价于

char str[10]; str[ ]={“china”};

C语言程序设计详解 79

(C)char *s=”china”; 等价于char *s;s=”china”;

(D)char c[4]=”abc”,d[4]=”abc”; 等价于char c[4]=d[4]=”abc”; 3、赋值

数组:char str[12];

strcpy(str,”I love China”); str=”I love China”; 指针:char *str2;

str2=”I love China”;

例24:下面能正确进行字符串赋值操作的是()。 A) char s[5]={“ABCDE”}

B) char s[5]={‘A’,’B’,’C’,’D’,’E’}; C) char *s;s=”ABCDE”; D) char *s; scanf(“%s”,s); 答案:

4、输入、输出 数组:char str[12];

scanf(“%s”,str); gets(str); printf(“%s”,str); puts(str);

指针:char str1[20],*str2=str1;

scanf(“%s”,str2); gets(str2); printf(“%s”,str2); puts(str2); 例25:下面程序段中,for循环的执行次数是( ) char *s=”\a\\018bc”;

for(;*s!=’\\0’;s++) printf(“*”); 答案:

例26:下面程序段的运行结果是( ) char *s=”abcde”; s+=2;printf(“%d”,s); 答案:

例27:设有下面的程序段 char s[ ]=”china’;char *p; p=s;

C语言程序设计详解 80

则下列叙述正确的是( )

(A)s和p完全相同 (B)数组s中的内容和指针变量p中的内容相等 (C)*p与s[0]相等 (D)s数组长度和p所指向的字符串长度相等 例28:以下正确的程序段是( ) (A)char str[20]; scanf(“%s”,&str); (B)char *p; scanf(“%s”,p);

(C)char str[20]; scanf(“%s”,&str[2]); (D)char str[20],*p=str; scanf(“%s”,p[2]); 答案:

例29:下面程序段的运行结果是() char str[ ]=”ABC”,*p=str; printf(“%d\\n”,*(p+3)); 答案:

例30:若有语句:char s1[ ]=”string1”,s2[8],*s3,*s4=”string2”;strcpy的错误调用是( )。

(A)strcpy(s1,”string2”); (B)strcpy(s4,”string1”); (C)strcpy(s3,”string1”); (D)strcpy(s1,s2); 例31:若有说明语句 char a[ ]=”It is mine”; char *p=”It is mine”;

则以下不正确的叙述是( ) (A)a+1表示的是字符t的地址

(B)p指向另外的字符串时,字符串的长度不受限制 (C)p变量中存放的地址值可以改变 (D)a中只能存放10个字符。 例32:下面程序段的运行结果是() char *p=”abcdefgh”; p+=3

printf(“%d\\n”,strlen(strcpy(p,”ABCD”))); A)8 B)12 C) 4 D)7 答案:

则对库函数 C语言程序设计详解 81

例33:下面程序的功能是将一个整数字符串转换为一个整数,如”-123”转换为-1234,请填空。

main()

{char s[6]; int n; gets(s);

if(*s==’-’) n=-chnum(s+1); else n=chnum(s); printf(“%d\\n”,n); }

chnum(char *p)

{ int num=0,k,len,j; len=strlen(p);

for( ;____________ ; p++ ) {

k=______________; j=--len;

while( _________ ) {k=k*10;} num=num+k; } } 答案:

例34:输入一个字符串,内有数字和非数字字符,

q p 如:a123x456 1760?302ab567

将其中连续的数字作为一个整数依次存放到一数组a中,如123存放到a[0]中,456存放到a[1]中。

main( )

{char s[80],*p,*q;

int a[80],I,t=0,flag=0; gets(s);p=s;q=s;

for( ; *p!=’\\0’ ; p++)

{ if((*p>=’0’ && *p<=’9’)&&(flag= =0)) {flag=1;q=p;}

if!((*p<’0’||*p>’9’)&&(flag= =1)) {t=0;

for(;qs=s*10+(*q-‘0’);

a[j]=s; j=j+1; flag=0; }

} }

六、指针与函数

C语言程序设计详解 82

一个函数包括一系列的指令,在内存中占据一片存储单元,它有一个起始地址,即函数的入口地址,可以通过这个地址找到该函数,这个地址称为函数的指针。

1、用函数指针调用函数 例35:求a,b的和。

main( )

{int a,b,c; ①定义 int (*p)( ) int add(int x,int y); 指向返回整型值的函数 scanf(“%d,%d”,&a,&b); ②赋值 p=add; c=add(a,b); 赋值只写函数名 printf(“%d’,c); ③调用 c=(*p)(a,b)

} 调用时根据需要写上实参。 int add(int x,int y) {return(x+y);}

2、指向函数的指针作函数参数

例36:求定积分:计算[0,1]之间函数1+x2、[0,2]之间函数1+x+x2+x3、[0,3.5]之间函数x/(1+x2)的定积分。

float f1(float x) {return(1+x*x);} float f2(float x)

{return(1+x+x*x+x*x*x);} float f3(float x)

{return(x/(1+x*x));}

float integral(float a,float b,float (*fun)( )) { int n=100,I;

float s,h=(b-a)/n;

s=((*fun)(a)+(*fun)(b))/2; for(I=1;Is=s+(*fun)(a+I*h); return(s*h); } main( ) {

printf(“%f”,integral(0,1,f1)); printf(“%f”,integral(0,2,f2)); printf(“%f”,integral(0,3.5,f3)); }

C语言程序设计详解 83

七、返回指针的函数

一个函数可以带加一个整型值,字符型值、实型值,也可以带回指针型的数据,即地址。

例37:编写一个strchr函数,它的作用是在一个字符串中找一个指定的字符,返回该字符的地址。

char *strchr(char *str,char ch) {while (*str++!=’\\0’)

if(*str==ch) return(str); return(0); }

八、指针数组和指向指针的指针 1、指针数组 char *s=”china”

char *name[5]={“Li Fun”,”Zhang li”,”li tian”,”su fang ”,”wang le”}; 例38:有三个字符串,要求按字母顺序输出。

Char *string[3]={“Data Structure”,”Computer Design”,”C Language”}; Char *p; Int I;

If(strcmp(string[0],string[1])>0)

{ p=sting[0];string[0]=string[1];string[1]=p;} if(strcmp(string[0],string[2])>0)

{p=string[0],string[0]=string[2];string[2]=p;} if(strcmp(string[1],string[2])>0)

{p=string[1];string[1]=string[2];string[2]=p;} for(I=0;I<3;I++)

printf(“%s\\n”,string[i]); 例39:设有以下程序段

char str[4][10]={“first”,”second”,”third”,”fourth”},*strp[4]; int n;

for(n=0;n<4;n++) strp[n]=str[n];

C语言程序设计详解 84

若k为int型变量且0<=k<4,则对字符串的不正确引用是

A) strp B) str[k] C) strp[k] D)*strp

答案:

例40:以下正确的说明语句是( )。 A)int *b[ ]={1,3,5,7,9};

B)int a[5],*num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]}; C)int a[ ]={1,3,5,7,9};int *num[5]={a[0],a[1],a[2],a[3],a[4]}; D)int a[3][4],(*num)[4] num[1]=&a[1][3]; 例41:设有以下定义 char *cc[2]={“1234”,”5678”}; 则正确的叙述是( )

A)cc数组的两个元素中各自存放了字符串“1234”和“5678”的首地址 B)cc数组的两个元素分别存放的是含有4个字符的一维字符数组的首地址 C)cc是指针变量,它指向含有两个数组元素的字符型一维数组 D)cc数组元素的值分别是“1234”和“5678” 答案:

例42:若有说明:char *language[ ]={“FOR”,”BA”,”PA”,”JA”};

则表达式*language[1]>*language[3]比较的是( )

language[2]的值是( )

答案:

例43:若有说明: char *language[ ]={“FOR”,”BA”,”PA”,”JA”};

则以下不正确的叙述是( )

A)Language+2表示字符串“PA”的首地址 B)*language[2]的值是字母P

C)language是一个字符型指针数组,它包含5个元素,每个元素都是一个指向字符串变量的指针

D)language是一个字符型指针数组,它包含5个元素,其初值分别是:“FOR”,”BA”,”PA”,”JA”

2、指向指针的指针 char **p,*p1,s;

C语言程序设计详解 85

表示指针变量p是指向一个字符指针变量。 例44:若有以下说明和语句

char *language[ ]={“FOR”,”BA”,”PA”,”JA”}; char **q;q=language+2

则语句printf(“%o”,*q);的执行结果是()。 答案:

2、指针数组作main函数的形参 (1)形式

main(int argc,char *argv[ ]) 注意:

①第一个形参是整型、第二个形参是指针数组。 ②形参名可以改变,但数据类型不能改。 (2)形参来源 有一源文件cfile.c,

main(int argc,char *argv[ ]) { ..........}

经编译连接后得到一目标文件名为cfile.exe,从键盘输入文件名: cfile computer clanguage

则argc为3,argv[0],argv[1],argv[2]分别指向串cfile、computer、clanguage 例45:main(int argc,char *argv[ ])

{while(argc>1)

{++argv;

puts(*argv); --argc;

}} 输出结果:

例46:以下正确的叙述是( )

A)C语言允许main函数带形参,且形参个数和形参名均由用户指定 B)C语言允许main函数带形参,形参名只能是argc和argv. C)当main函数带形参时,传给形参的值只能从命令行中得到。

D)若有说明,main(int argc,char *argv),则形参argc的值必须大于1。答案: 例47:main函数的正确形式是( ) A) main(int argc,char *argv) B) main(int abc,char **abv) C) main(int argc,char argv)

D) main(int c,char v[ ]) 答案:

C语言程序设计详解 86

第七章 结构体、共用体和枚举类型数据

一、为什要引入结构体类型

存在着大量要将不同类型的数据组合成一个有机的整体,这些组合在一个整体中的数据是互相联系的,例如:一个学生的学号、姓名、分数等。它们是同一个处理对象----居民的属性,但又不属于同一类型。 二、结构体类型

1、定义一个结构体类型的一般形式为:

struct person {long xh;

char name[20]; float score;

};

说明:

①一个结构体类型有其专有的标志,它由两个单词组成,第一个关键字struct,第二个单词按标识符命名规则指定

②结构体类型由若干个数据项组成,每一个数据项都属于一种已有定义的类型。它们并不是变量,而是一个结构体类型中的成员。

③结构体类型并非只能有一种,而可以有许多种,这是与基本类型不同的。 ④定义一个结构体类型,并不意味着系统将分配一段内存单元来存放各数据项成员,只是表示这个类型的结构。

⑤系统没有预先定义结构体类型,凡需使用结构体类型数据的,都必须在程序中自己定义

2、定义结构体类型变量的方法

①在定义了一个结构体类型之后,把变量定义为该类型 struct person {long xh;

char name[20]; float score;

};

C语言程序设计详解 87

struct person stud1 , stud2;

类型标识符 结构体变量名

②在定义一个结构体类型的同时定义一个或若干个结构体变量。 struct person {long xh;

char name[20]; float score;

} stud1 , stud2 ;

③直接定义结构体类型的变量 struct {long xh;

char name[20]; float score;

} stud1 , stud2 ; 说明:

①在定义了变量stud1和stud2后,它们就具有了结构体类型的特征 ②在定义一个结构体类型时可以利用已定义了的另一个结构体类型来定义其成员的类型

例:

struct date {int month;

int day; int year; }; struct person {long xh;

char name[20]; float score;

C语言程序设计详解 88

struct date birthday; };

例1:当说明一个结构体变量时系统分配给它的内存是 A)各成员所需内存总量的总和 B)结构中第一个成员所需内存量 C)成员中占内存量最大者所需的容量 D)结构中最后一个成员所需内存量 答案:

例2:设有以下说明语句 struct stu {int a; float b;

} stutype;

则下面叙述不正确的是()

A)struct是结构体类型的关键字 B)struct stu是用户定义的结构体类型 C)stutype是用户定义的结构体类型名 D)a和b都是结构体成员名 3、结构体变量的初始化

在初始化时,按照所定义的结构体类型的数据结构,依次写出各初始值,在编译时就将它们赋给此变量中各成员。

struct person {long xh;

char name[20]; float score;

} stud ={”10189”,“wang”,97.5}; 4、结构体变量的引用

①引用结构体变量中的一个成员 stud.xh

②可以将一个结构体变量作为一个整体赋组另一个具有相同类型的结构体

变量。

struct person {long xh;

char name[20]; float score;

};

Main( ) {

C语言程序设计详解 89

struct stud1 ={”10189”,“wang”,90.5};

struct stud2; stud2=stud1;

}

5、结构体变量的输入和输出

C语言不允许把一个结构体作为一个整体进行输入或输出操作。 例如:printf(“%d”,stud1) 和 要scanf(“%d”,&stud1); 如输出stud变量可以用语句

printf(“%ld,%s,%f\\n”,stud.xh,stud.name,stud.score); 如输入stud变量可以用语句

scanf(“%ld,%s,%f\\n”,&stud.xh,stud.name,&stud.score); 三、结构体数组

1、结构体数组的定义方法 struct person {long xh;

char name[20]; float score;

};

struct person stu[3];

2、结构体数组的初始化 struct person {long xh;

char name[20]; float score;

C语言程序设计详解 90

} struct person stu[3]={{ 8010, “wang”,89.5},{ 8011, “li”,65},{ 8012, “song”,75}};

3、结构体数组的引用

①引用某一元素中的一个成员。

Stu[1].num

②可将数组中一个元素赋值给另一个元素

struct person stu[3],s; stu[1]=s;

③不能把结构体数组元素整体输入、整体输出,只能以单个成员对象进行输入输出。

注意:在输入过程中为了能不出现过多的麻烦,用gets来录入相应的串,然后用以下函数转化为相应的类型。

Atoi( ) 将字符串转换为整数 Atof( )将字符串转换为实数 Atol( )将字符串转换为长整型 例3、下面程序的运行结果是() main( ) {

struct cmplx{int x; int y;

}c[2]={1,3,2,7};

printf(“%d”,c[0].y/c[0].x*c[1].x); }

例4、以下scanf函数调用语句中对结构体变量成员的不正确引用是( )。 Struct pupil

{char name[20]; int age; float score;

C语言程序设计详解 91

}pup[5],*p; p=pup;

A) scanf(“%s”,pup[0].name); B) scnaf(“%d”,&pup[0].age); C) scanf(“%f”,&(p->score)); D) scanf(“%d”,p->age)

答案:

四、结构体变量作为函数参数以及返回结构体类型值的函数 1、结构体变量作为函数参数 2、返回结构体类型值的函数 五、结构体变量与指针 1、指向结构体变量的指针

所谓结构体变量的指针就是这个结构体变量所占内存单元段的起始地址。 Struct person *p,stu; P=&stu;

引用成员方式:(*p).name p->name

->的优先级别最高,高于自加自减,所以p->num++相当于(p->num)++ 2、指向结构体数组的指针

3、指向结构体变量的指针作函数参数 六、共用体类型概念

所谓共用体数据类型是指将不同的数据项存放于同一段内存单元的一种构造数据类型。

Union exam {int a; float b; char c; } x,y;

七、共用体变量的引用

1、可以引用一个共用体变量中的某个成员项 x.a x.b

C语言程序设计详解 92

2、不能直接用共作体变量名进行输入输出

scanf(“%d”,&x); printf(“%d”,x);

3、允许在两个同类型的共用体变量之间赋值。

y=x;

例5、若有以下说明:则下面不正确的叙述是() union data {int I; char c; float f;

}un;

A)un所占的内存长度等于成员f的长度 B)un的地址和它的各成员地址都是同一地址 C)un可以作为函数参数

D)不能对un赋值,但可以在定义un时对它初始化 答案:

例6、以下程序的运行结果是( ) main( ) struct ex {struct ey {int x; int y;} int a; int b;

}e;

e.a=1; e.b=2; e.in.x=e.a*e.b; e.in.y=e.a+e.b; 答案:

八、枚举类型数据

C语言程序设计详解 93

所谓“枚举”类型,是指这种类型的变量的值只能是指定的若干个名字之一。 定义类型

enum color{red,yellow,blue,white,black}; 定义变量 enum color c; 引用

c=red; c=green;

九、用TYPEDEF定义类型

允许在程序中用typedef来定义新的类型名来代替已有的类型名, typedef只是起了一个新的类型名字,并未建立新的数据类型。

Typedef int integer Integer a,b;

十、动态存储分配----链表 1、动态存储分配和链表的概念

根据需要临时分配内存单元以存放有用的数据,当数据不用时又可以随时释放存储单元。

2、用包含指针项的结构体变量构成结点 struct person {long xh; float score;

struct person *next; };

struct person stud1,stud2,stud3,*head; stud1.num=89101;stud1.score=89; stud1.num=89102;stud1.score=90; stud1.num=89103;stud3.score=98; 例7、设有以下语句

struct st { int n;

struct st *next;

}

C语言程序设计详解 94

struct st a[3]={5,&a[1],7,&a[2],9,’\\0’},*p; p=&a[0];

则以下表达式中值为6的是( ) A)p++->m B)p->n++ C)(* p).n++ D)++p->n 3、用于动态存储分配的函数 ①malloc

void * malloc(unsigned int size)

它的作用是在内存开辟指定大小的存储空间,并将此存储空间的起始地址作为函数带回。函数值为指针(地址)这个指针是指向void类型的,如果想将这个指针赋给其它类型的指针变量,应当进行显式的转换。

②calloc

void *calloc(unsigned int num,unsigned int size)

它有两个形参num和size,其作用是分配num个大小为size字节的空间。 ③free

void free(void *ptr)

其作用是将指针变量ptr指向的存储空间释放。 ④realloc

void *recalloc(void *ptr ,unsigned int size) 用来使已分配的空间改变大小,即重新分配。 4、链表应用举例 P 274

7.8 7.9 7.10:建立一个链表,每个结点包含的成员为:职工号、工资。用malloc函数开辟新结点。要求链表包含5个结点,从键盘输入结点中的数据。然后把这些结点的数据打印出来。要求用函数creat来建立函数,用list函数来输出数据。这5个职工的号码为101,103,105,107,109。用insert函数来新增一个职工的数据,这个新结点,按职工号顺序插入。用delete函数来删除一个结点。

Struct work {long num;

float gz;

};

创建

C语言程序设计详解 95

struct work * Create(struct work * head)

{

struct work * this, * new;

new=(struct work *) malloc(sizeof(struct stru)); if (head= =NULL) head =new; else {

this=head;

while (this->next!=NULL) this=this->next; this->next=new; new->next=null

scanf(“%ld”,&new->num); scanf(“%f”.,&gz); } endif return(head); } 浏览

void list ( struct work * head) { struct work * this, * new;

if (head==null)

printf(“no data!”); else {

this=head;

do{

C语言程序设计详解 96

printf(“%ld,%f\\n”,this->num,this->gz); this=this->next;

}while(this!=NULL);

endif } }

插入

struct work *insert( struct work * head ,long x,float y ) { struct work * this ,*new,* fro;

new=(struct work*) malloc( sizeof(struct work)); new->num=x; new->gz=y; if (head= = NULL)

head=new;

else

{

this=head;

while((this!=NULL) &&(this->num>x)) {fro=this;

this=this->next; }

if(this= =head) {head=new;

new->next=this }

else

{fro->next=new; new->next=this; } endif }

删除

C语言程序设计详解 97

struc work * del(struct work *head, int x) {struct work *head, * this ,*fro; this=head;

while((this!=NULL) &&(this->num!=x)

{fro=this; thid=this- next; } if (this!=NULL) If(this= =head) {head=head->next;

free(this); } else {

fro->next=this->next; free(this); } endif endif

因篇幅问题不能全部显示,请点此查看更多更全内容

Top