C语言-6-9

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第6章数组
为了解决比较复杂的问题,本章介绍C语言提供的一种最简单的构造类型──数组。

6.1 1维数组的定义和引用
6.2 2维数组的定义和引用
6.3 字符数组与字符串
6.1 1维数组的定义和引用
6.1.1 1维数组的定义
6.1.2 1维数组元素的引用
6.1.3 1维数组元素的初始化
6.1.4 1维数组应用举例
6.1.1 1维数组的定义
[案例6.1] 从键盘上任意输入10个整数,要求按从小到大的顺序在屏幕上显示出来。

排序的方法有很多,本题采用冒泡法。

冒泡法的基本思想:通过相邻两个数之间的比较和交换,使排序码(数值)较小的数逐渐从底部移向顶部,排序码较大的数逐渐从顶部移向底部。

就像水底的气泡一样逐渐向上冒,故而得名。

由A[n]~A[1]组成的n个数据,进行冒泡排序的过程可以描述为:
(1)首先将相邻的A[n]与A[n-1]进行比较,如果A[n]的值小于A[n-1]的值,则交换两者的位置,使较小的上浮,较大的下沉;接着比较A[n-1]与A[n-2],同样使小的上浮,大的下沉。

依此类推,直到比较完A[2]和A[1]后,A[1]为具有最小排序码(数值)的元素,称第一趟排序结束。

(2)然后在A[n]~A[2]区间内,进行第二趟排序,使剩余元素中排序码最小的元素上浮到A[2];重复进行n-1趟后,整个排序过程结束。

/*案例代码文件名:AL6_1.C*/
/*功能:从键盘上任意输入n个整数,用冒泡法按从小到大地排序,并在屏幕上显示出来。

*/
#include "stdio.h"
#define NUM 10 /*定义符号常量(数据个数N)*/
main()
{ int data[NUM]; /*定义1个1维整型数组data*/
int i,j,temp; /*定义循环变量和临时变量*/
clrscr(); /*库函数clrscr():清屏*/
printf("Please input 10 numbers:\n");
for(i=0; i<NUM; i++)
scanf("%d", &data[i]);
/*冒泡法排序*/
for(i=0; i<NUM-1; i++) /*外循环:控制比较趟数*/
for(j=NUM-1; j>i; j--) /*内循环:进行每趟比较*/
if(data[j]<data[j-1]) /*如果data[j]大于data[j-1],交换两者的位置*/
{temp=data[j];
data[j]=data[j-1];
data[j-1]=temp;
};
/*输出排序后的数据*/
printf("\nthe result of sort:\n");
for(i=0; i<NUM; i++)
printf("%d ",data[i]);
getch(); /*等待键盘输入任一字符,目的使程序暂停*/
}
[程序演示]
数组同变量一样,也必须先定义、后使用。

1维数组是只有1个下标的数组,定义形式如下:
数据类型数组名[常量表达式][, 数组名2[常量表达式2]……];
(1)“数据类型”是指数组元素的数据类型。

(2)数组名,与变量名一样,必须遵循标识符命名规则。

(3)“常量表达式”必须用方括号括起来,指的是数组的元素个数(又称数组长度),它是一个整型值,其中可以包含常数和符号常量,但不能包含变量。

注意:C语言中不允许动态定义数组。

特别说明:在数组定义时,“常量表达式”外的方括号;以及元素引用时,“下标表达式”外的方括号,都是C语言语法规则所要求的,不是本书所约定的可选项的描述符号!
(4)数组元素的下标,是元素相对于数组起始地址的偏移量,所以从0开始顺序编号。

(5)数组名中存放的是一个地址常量,它代表整个数组的首地址。

同一数组中的所有元素,按其下标的顺序占用一段连续的存储单元。

6.1.2 数组元素的引用
引用数组中的任意一个元素的形式:
数组名[下标表达式]
1.“下标表达式”可以是任何非负整型数据,取值范围是0~(元素个数-1)。

特别强调:在运行C语言程序过程中,系统并不自动检验数组元素的下标是否越界。

因此在编写程序时,保证数组下标不越界是十分重要的。

2.1个数组元素,实质上就是1个变量,它具有和相同类型单个变量一样的属性,可以对它进行赋值和参与各种运算。

3.在C语言中,数组作为1个整体,不能参加数据运算,只能对单个的元素进行处理。

6.1.3 1维数组元素的初始化
初始化格式:
数据类型数组名[常量表达式]={初值表}
(1)如果对数组的全部元素赋以初值,定义时可以不指定数组长度(系统根据初值个数自动确定)。

如果被定义数组的长度,与初值个数不同,则数组长度不能省略。

(2)“初值表”中的初值个数,可以少于元素个数,即允许只给部分元素赋初值。

(3)根据存储类型的不同,数组有静态数组(static)和动态数组(auto)之分;根据定义的位置不同,数组有内部数组(在函数内部定义的数组)和外部数组(在函数外部定义的数组)之分。

6.1.4 1维数组应用举例
[案例6.2] 已知某课程的平时、实习、测验和期末成绩,求该课程的总评成绩。

其中平时、实习、测验和期末分别占10%、20%、20%、50%。

/*案例代码文件名:AL6_2.C*/
/*功能:从键盘上循环输入某课程的平时、实习、测验和期末成绩,按10%,20%,20%,50%的比例计算总评成绩,并在屏幕上显示出来。

按空格键继续循环,其他键终止循环。

*/ #include “stdio.h”
main()
{ int i=1,j;
char con_key=…\x20‟;/* …\x20‟ 空格键的ASCII码*/
float score[5],ratio[4]={0.1,0.2,0.2,0.5}; /*定义成绩、比例系数数组*/
while(con_key=='\x20')
while(con_key=='\x20')
{clrscr();
printf("输入第%2d个学生的成绩\n", i++);
printf("平时实习测验期末成绩\n");
score[4]=0; /* score[4]:存储总评成绩*/
for(j=0; j<4; j++)
{scanf("%f",&score[j]);
score[4] += score[j] * ratio[j];
}
printf("总评成绩为:%6.1f\n", score[4]);
printf("\n按空格键继续,其它键退出");
con_key=getch(); /*getch()函数等待从键盘上输入一个字符*/
}
}
[程序演示]
6.2 2维数组的定义和引用
6.2.1 2维数组的定义
6.2.2 2维数组元素的引用
6.2.3 2维数组元素的初始化
6.2.4 2维数组应用举例
6.2.1 2维数组的定义
[案例6.3] 给一个2*3的2维数组各元素赋值,并输出全部元素的值。

/*案例代码文件名:AL6_3.C*/
/*功能:从键盘上给2*3数组赋值,并在屏幕上显示出来。

*/
#define Row 2
#define Col 3
#include "stdio.h"
main()
{ int i, j, array[Row][Col]; /*定义1个2行3列的2维数组array*/
for(i=0; i<Row; i++) /*外循环:控制2维数组的行*/
for(j=0; j<Col; j++) /*内循环:控制2维数组的列*/
{printf("please input array[%2d][%2d]:",i,j);
scanf("%d",&array[i][j]); /*从键盘输入a[i][j]的值*/
}
printf("\n");
/*输出2维数组array*/
for(i=0;i<Row;i++)
{ for(j=0;j<Col;j++)
printf("%d\t",array[i][j]); /*将a[i][j]的值显示在屏幕上*/
printf("\n");
}
getch();
} [程序演示]
2维数组的定义方式如下:
数据类型数组名[行常量表达式][列常量表达式][, 数组名2[行常量表达式2][列常量表达式2]……];
1.数组元素在内存中的排列顺序为“按行存放”,即先顺序存放第一行的元素,再存放第二行,以此类推。

2. 设有一个m*n的数组x,则第i行第j列的元素x[i][j]在数组中的位置为:i*n+j(注意:行号、列号均从0开始计数)。

3.可以把2维数组看作是一种特殊的1维数组:它的元素又是一个1维数组。

例如,对x[3][2],可以把x看作是一个1维数组,它有3个元素:x[0]、x[1]、x[2],每个元素又是一个包含2个元素的1维数组,如图6-4所示。

即把x[0]、x[1]、x[2]看作是3个1维数组的名字。

6.2.2 2维数组元素的引用
引用2维数组元素的形式为:
数组名[行下标表达式][列下标表达式]
1.“行下标表达式”和“列下标表达式”,都应是整型表达式或符号常量。

2.“行下标表达式”和“列下标表达式”的值,都应在已定义数组大小的范围内。

假设有数组x[3][4],则可用的行下标范围为0~2,列下标范围为0~3。

3.对基本数据类型的变量所能进行的操作,也都适合于相同数据类型的2维数组元素。

6.2.3 2维数组元素的初始化
1.按行赋初值
数据类型数组名[行常量表达式][列常量表达式]={{第0行初值表},{第1行初值表},……,{最后1行初值表}};
赋值规则:将“第0行初值表”中的数据,依次赋给第0行中各元素;将“第1行初值表”中的数据,依次赋给第1行各元素;以此类推。

2.按2维数组在内存中的排列顺序给各元素赋初值
数据类型数组名[行常量表达式][列常量表达式]={初值表};
赋值规则:按2维数组在内存中的排列顺序,将初值表中的数据,依次赋给各元素。

如果对全部元素都赋初值,则“行数”可以省略。

注意:只能省略“行数”。

6.2.4 2维数组应用举例
[案例6.4] 有M个学生,学习N门课程,已知所有学生的各科成绩,编程:分别求每个学
生的平均成绩和每门课程的平均成绩。

/*案例代码文件名:AL6_4.C*/
/*功能:计算个人平均成绩与各科平均成绩,并在屏幕上显示出来。

*/
#define NUM_std 5 /*定义符号常量人数为5*/
#define NUM_course 4 /*定义符号常量课程为4*/
#include "stdio.h"
main()
{ int i,j;
static float score[NUM_std+1][NUM_course+1]={{78,85,83,65},
{88,91,89,93}, {72,65,54,75},
{86,88,75,60}, {69,60,50,72}};
for(i=0;i<NUM_std;i++)
{for(j=0;j<NUM_course;j++)
{ score[i][NUM_course] += score[i][j];/*求第i个人的总成绩*/
score[NUM_std][j] += score[i][j]; /*求第j门课的总成绩*/
}
score[i][NUM_course] /= NUM_course;/*求第i个人的平均成绩*/
}
for(j=0;j<NUM_course;j++)
score[NUM_std][j] /= NUM_std; /*求第j门课的平均成绩*/
clrscr();
/*输出表头*/
printf("学生编号课程1 课程2 课程3 课程4 个人平均\n");
/*输出每个学生的各科成绩和平均成绩*/
for(i=0;i<NUM_std;i++)
{ printf("学生%d\t",i+1);
for(j=0;j<NUM_course+1;j++)
printf("%6.1f\t",score[i][j]);
printf("\n");
}
/*输出1条短划线*/
for(j=0;j<8*(NUM_course+2);j++)
printf("-");
printf("\n课程平均");
/*输出每门课程的平均成绩*/
for(j=0;j<NUM_course;j++)
printf("%6.1f\t",score[NUM_std][j]);
printf("\n");
getch();
} [程序演示]
6.3 字符数组与字符串
6.3.1 字符数组的逐个字符操作
6.3.2 字符数组的整体操作
6.3.3 常用的字符串处理函数
6.3.1 字符数组的逐个字符操作
[案例6.5]从键盘输入一个字符串,回车键结束,并将字符串在屏幕上输出。

/*案例代码文件名:AL6_5.C*/
main()
{int i;
static char str[80];
clrscr();
for(i=0;i<80;i++)
{ str[i]=getch(); /*逐次给数组元素str[i]赋值,但不回显在屏幕上*/
printf("*"); /*以星号代替输入字符的个数*/
if(str[i]=='\x0d') break;/*若输入回车则终止循环*/
}
i=0;
while(str[i]!='\x0d')
printf("%c",str[i++]); /*逐次输出字符数组的各个元素*/
printf("\n");
getch(); /*程序暂停*/
} [程序演示]
1.字符数组的定义
1维字符数组,用于存储和处理1个字符串,其定义格式与1维数值数组一样。

2维字符数组,用于同时存储和处理多个字符串,其定义格式与2维数值数组一样。

2.字符数组的初始化
字符数组的初始化,可以通过为每个数组元素指定初值字符来实现。

3.字符数组的引用
字符数组的逐个字符引用,与引用数值数组元素类似。

(1)字符数组的输入
除了可以通过初始化使字符数组各元素得到初值外,也可以使用getchar()或scanf()函数输入字符。

例如:
char str[10];
……
for(i=0; i<10; i++)
{ scanf("%c", &str[i]);
fflush(stdin); /*清除键盘输入缓冲区*/
}
……
(2)字符数组的输出
字符数组的输出,可以用putchar()或printf()函数。

例如:
char str[10]="c language";
……
for(i=0; i<10; i++) printf("%c", str[i]);
printf("\n");
……
注意:逐个字符输入、输出时,要指出元素的下标,而且使用“%c”格式符。

另外,从键盘上输入字符时,无需输入字符的定界符──单引号;输出时,系统也不输出字符的定界符。

6.3.2 字符数组的整体操作
[案例6.6] 字符数组的整体输入与输出。

/*案例代码文件名:AL6_6.C*/
/*功能:将2维字符数组进行初始化,并在屏幕上输出*/
main()
{ int i;
char name[5][9]={"张三山", "李四季", "王五魁", "刘六顺", "赵七巧"};
for(i=0;i<5;i++)
printf("\n%s\t",name[i]); /*name[i]代表该行数组元素的首地址*/
getch();
} [程序演示]
1.字符串及其结束标志
所谓字符串,是指若干有效字符的序列。

C语言中的字符串,可以包括字母、数字、专用字符、转义字符等。

C语言规定:以…\0‟作为字符串结束标志(…\0‟代表ASCII码为0的字符,表示一个“空操作”,只起一个标志作用)。

因此可以对字符数组采用另一种方式进行操作了──字符数组的整体操作。

注意:由于系统在存储字符串常量时,会在串尾自动加上1个结束标志,所以无需人为地再加1个。

另外,由于结束标志也要在字符数组中占用一个元素的存储空间,因此在说明字符数组长度时,至少为字符串所需长度加1。

2.字符数组的整体初始化
字符串设置了结束标志以后,对字符数组的初始化,就可以用字符串常量来初始化字符数组。

3.字符数组的整体引用
(1)字符串的输入
除了可以通过初始化使字符数组各元素得到初值外,也可以使用scanf()函数输入字符串。

(2)字符串的输出
printf()函数,不仅可以逐个输出字符数组元素,还可以整体输出存放在字符数组中的字符串。

6.3.3 常用的字符串处理函数
字符串标准函数的原型在头文件string.h中。

1.输入字符串──gets()函数
(1)调用方式:gets(字符数组)
(2)函数功能:从标准输入设备(stdin)──键盘上,读取1个字符串(可以包含空格),并将其存储到字符数组中去。

(3)使用说明
1)gets()读取的字符串,其长度没有限制,编程者要保证字符数组有足够大的空间,存放输入的字符串。

2)该函数输入的字符串中允许包含空格,而scanf()函数不允许。

2.输出字符串──puts()函数
(1)调用方式:puts(字符数组)
(2)函数功能:把字符数组中所存放的字符串,输出到标准输出设备中去,并用…\n‟取代字符串的结束标志…\0‟。

所以用puts()函数输出字符串时,不要求另加换行符。

(3)使用说明
1)字符串中允许包含转义字符,输出时产生一个控制操作。

2)该函数一次只能输出一个字符串,而printf()函数也能用来输出字符串,且一次能输出多个。

3.字符串比较──strcmp()函数
(1)调用方式:strcmp(字符串1 ,字符串2)
其中“字符串”可以是串常量,也可以是1维字符数组。

(2)函数功能:比较两个字符串的大小。

如果:字符串1=字符串2,函数返回值等于0;
字符串1<字符串2,函数返回值负整数;
字符串1>字符串2,函数返回值正整数。

(3)使用说明
1)如果一个字符串是另一个字符串从头开始的子串,则母串为大。

2)不能使用关系运算符“==”来比较两个字符串,只能用strcmp() 函数来处理。

[案例6.7] gets函数和strcmp函数的应用。

/*案例代码文件名:AL6_7.C*/
/*功能:简单密码检测程序*/
#include "stdio.h"
main()
{char pass_str[80]; /*定义字符数组passstr*/
int i=0;
/*检验密码*/
while(1)
{clrscr();
printf("请输入密码\n");
gets(pass_str); /*输入密码*/
if(strcmp(pass_str,“password”)!=0) /*口令错*/
printf("口令错误,按任意键继续");
else
break; /*输入正确的密码,中止循环*/
getch();
i++;
if(i==3) exit(0); /*输入三次错误的密码,退出程序*/
}
/*输入正确密码所进入的程序段*/
}
[程序演示]
4.拷贝字符串──strcpy()函数
(1)调用方式:strcpy(字符数组, 字符串)
其中“字符串”可以是串常量,也可以是字符数组。

(2)函数功能:将“字符串”完整地复制到“字符数组”中,字符数组中原有内容被覆盖。

(3)使用说明
1)字符数组必须定义得足够大,以便容纳复制过来的字符串。

复制时,连同结束标志'\0'一起复制。

2)不能用赋值运算符“=”将一个字符串直接赋值给一个字符数组,只能用strcpy()函数来处理。

5.连接字符串──strcat()函数
(1)调用方式:strcat(字符数组, 字符串)
(2)函数功能:把“字符串”连接到“字符数组”中的字符串尾端,并存储于“字符数组”中。

“字符数组”中原来的结束标志,被“字符串”的第一个字符覆盖,而“字符串”在操作中未被修改。

(3)使用说明
1)由于没有边界检查,编程者要注意保证“字符数组”定义得足够大,以便容纳连接后的目标字符串;否则,会因长度不够而产生问题。

2)连接前两个字符串都有结束标志'\0',连接后“字符数组”中存储的字符串的结束标志'\0'被舍弃,只在目标串的最后保留一个'\0'。

6.求字符串长度──strlen()函数(len是length的缩写)
(1)调用方式:strlen(字符串)
(2)函数功能:求字符串(常量或字符数组)的实际长度(不包含结束标志)。

7.将字符串中大写字母转换成小写──strlwr()函数
(1)调用方式:strlwr(字符串)
(2)函数功能:将字符串中的大写字母转换成小写,其它字符(包括小写字母和非字母字符)不转换。

8.将字符串中小写字母转换成大写──strupr()函数
(1)调用方式:strupr(字符串)
(2)函数功能:将字符串中小写字母转换成大写,其它字符(包括大写字母和非字母字符)不转换。

第7章函数
C语言是通过函数来实现模块化程序设计的。

所以较大的C语言应用程序,往往是由多个函数组成的,每个函数分别对应各自的功能模块。

7.1 函数的定义与调用
7.2 函数的嵌套调用与递归调用
7.3 数组作为函数参数
7.4 内部变量与外部变量
7.5 内部函数与外部函数
7.6 变量的动态存储与静态存储
7.1 函数的定义与调用
7.1.1 函数的定义
7.1.2 函数的返回值与函数类型
7.1.3 对被调用函数的说明和函数原型
7.1.4 函数的调用
7.1.5 函数的形参与实参
7.1 .1 函数的定义
1.任何函数(包括主函数main())都是由函数说明和函数体两部分组成。

根据函数是否需要参数,可将函数分为无参函数和有参函数两种。

(1)无参函数的一般形式
函数类型函数名( void )
{ 说明语句部分;
可执行语句部分;
}
注意:在旧标准中,函数可以缺省参数表。

但在新标准中,函数不可缺省参数表;如果不需要参数,则用“void”表示,主函数main()例外。

(2)有参函数的一般形式
函数类型函数名( 数据类型参数[,数据类型参数2……] )
{ 说明语句部分;
可执行语句部分;
}
有参函数比无参函数多了一个参数表。

调用有参函数时,调用函数将赋予这些参数实际的值。

为了与调用函数提供的实际参数区别开,将函数定义中的参数表称为形式参数表,简称形参表。

[案例7.1] 定义一个函数,用于求两个数中的大数。

/*案例代码文件名:AL7_1.C*/
/*功能:定义一个求较大数的函数并在主函数中调用*/
int max(int n1, int n2) /*定义一个函数max()*/
{ return (n1>n2?n1:n2);
}
main()
{ int max(int n1, int n2);/*函数说明*/
int num1,num2;
printf("input two numbers:\n");
scanf("%d%d", &num1, &num2);
printf("max=%d\n", max(num1,num2));
getch(); /*使程序暂停,按任一键继续*/
}
[程序演示]
2.说明
(1)函数定义不允许嵌套。

在C语言中,所有函数(包括主函数main())都是平行的。

一个函数的定义,可以放在程序中的任意位置,主函数main()之前或之后。

但在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。

(2)空函数──既无参数、函数体又为空的函数。

其一般形式为:
[函数类型] 函数名(void)
{ }
(3)在老版本C语言中,参数类型说明允许放在函数说明部分的第2行单独指定。

7.1.2 函数的返回值与函数类型
C语言的函数兼有其它语言中的函数和过程两种功能,从这个角度看,又可把函数分为有返回值函数和无返回值函数两种。

1.函数返回值与return语句
有参函数的返回值,是通过函数中的return语句来获得的。

(1)return语句的一般格式:return ( 返回值表达式);
(2)return语句的功能:返回调用函数,并将“返回值表达式”的值带给调用函数。

注意:调用函数中无return语句,并不是不返回一个值,而是一个不确定的值。

为了明确表示不返回值,可以用“void”定义成“无(空)类型”。

2.函数类型
在定义函数时,对函数类型的说明,应与return语句中、返回值表达式的类型一致。

如果不一致,则以函数类型为准。

如果缺省函数类型,则系统一律按整型处理。

良好的程序设计习惯:为了使程序具有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型;即使函数类型为整型,也不使用系统的缺省处理。

7.1.3 对被调用函数的说明和函数原型
在ANSI C新标准中,采用函数原型方式,对被调用函数进行说明,其一般格式如下:
函数类型函数名(数据类型[ 参数名][, 数据类型[ 参数名2]…]);
C语言同时又规定,在以下2种情况下,可以省去对被调用函数的说明:(1)当被调用函数的函数定义出现在调用函数之前时。

因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、类型和顺序。

(2)如果在所有函数定义之前,在函数外部(例如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数的说明。

7.1.4 函数的调用
在程序中,是通过对函数的调用来执行函数体的,其过程与其它语言的子程序调用相似。

C语言中,函数调用的一般形式为:函数名([实际参数表])
切记:实参的个数、类型和顺序,应该与被调用函数所要求的参数个数、类型和顺序一致,才能正确地进行数据传递。

在C语言中,可以用以下几种方式调用函数:
(1)函数表达式。

函数作为表达式的一项,出现在表达式中,以函数返回值参与表达式的运算。

这种方式要求函数是有返回值的。

(2)函数语句。

C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。

(3)函数实参。

函数作为另一个函数调用的实际参数出现。

这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。

说明:
(1)调用函数时,函数名称必须与具有该功能的自定义函数名称完全一致。

(2)实参在类型上按顺序与形参,必须一一对应和匹配。

如果类型不匹配,C编译程序将按赋值兼容的规则进行转换。

如果实参和形参的类型不赋值兼容,通常并不给出出错信息,且程序仍然继续执行,只是得不到正确的结果。

(3)如果实参表中包括多个参数,对实参的求值顺序随系统而异。

有的系统按自左向右顺序求实参的值,有的系统则相反。

Turbo C和MS C是按自右向左的顺序进行的。

7.1.5 函数的形参与实参
函数的参数分为形参和实参两种,作用是实现数据传送。

形参出现在函数定义中,只能在该函数体内使用。

发生函数调用时,调用函数把实参的值复制1份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送。

[案例7.3]实参对形参的数据传递。

/*实参对形参的数据传递。

*/
/*案例代码文件名:AL7_3.C*/
void main()
{ void s(int n); /*说明函数*/
int n=100; /*定义实参n,并初始化*/
s(n); /*调用函数*/
printf("n_s=%d\n",n); /*输出调用后实参的值,便于进行比较*/
getch();
}
/* */
void s(int n)
{ int i;
printf("n_x=%d\n",n); /*输出改变前形参的值*/
for(i=n-1; i>=1; i--) n=n+i; /*改变形参的值*/
printf("n_x=%d\n",n); /*输出改变后形参的值*/
}
[程序演示]
说明:
(1)实参可以是常量、变量、表达式、函数等。

无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。

因此,应预先用赋值、输入等办法,使实参获得确定的值。

(2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元。

因此,形参只有在该函数内有效。

调用结束,返回调用函数后,则不能再使用该形参变量。

(3)实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。

(4)实参和形参占用不同的内存单元,即使同名也互不影响。

7.2 函数的嵌套调用和递归调用
7.2.1 函数的嵌套调用
函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其它函数。

这与其它语言的子程序嵌套调用的情形是类似的,其关系可表示如图7-1。

[案例7.4] 计算s=1k+2k+3k+……+N k
/*案例代码文件名:AL7_4.C*/
/*功能:函数的嵌套调用*/
#define K 4
#define N 5
long f1(int n,int k) /*计算n的k次方*/
{ long power=n;
int i;
for(i=1;i<k;i++) power *= n;
return power;
}
long f2(int n,int k) /*计算1到n的k次方之累加和*/
{ long sum=0;
int i;
for(i=1;i<=n;i++) sum += f1(i, k);
return sum;
}
main()
{ printf("Sum of %d powers of integers from 1 to %d = ",K,N);
printf("%d\n",f2(N,K));
getch();
}
[程序演示]
7.2.2 函数的递归调用
函数的递归调用是指,一个函数在它的函数体内,直接或间接地调用它自身。

C语言允许函数的递归调用。

在递归调用中,调用函数又是被调用函数,执行递归函数将反
复调用其自身。

每调用一次就进入新的一层。

为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。

常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。

[案例7.5] 用递归法计算n!。

/*案例代码文件名:AL7_5.C*/
/*功能:通过函数的递归调用计算阶乘*/
long power(int n)
{ long f;
if(n>1) f=power(n-1)*n;
else f=1;
return(f);
}
main()
{ int n;
long y;
printf("input a inteager number:\n");
scanf("%d",&n);
y=power(n);
printf("%d!=%ld\n",n,y);
getch();
} [程序演示]
7.3 数组作为函数参数
数组用作函数参数有两种形式:一种是把数组元素(又称下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。

7.3.1 数组元素作为函数参数
7.3.2 数组名作为函数的形参和实参
7.3.1 数组元素作为函数参数
数组元素就是下标变量,它与普通变量并无区别。

数组元素只能用作函数实参,其用法与普通变量完全相同:在发生函数调用时,把数组元素的值传送给形参,实现单向值传送。

[案例7.6] 写一函数,统计字符串中字母的个数。

/*案例代码文件名:AL7_6.C*/
/*功能:数组元素作为函数实参*/
int isalp(char c)
{ if (c>='a'&&c<='z'||c>='A'&&c<='Z')
return(1);
else return(0);
}
main()
{ int i,num=0;
char str[255];
printf("Input a string: ");
gets(str);。

相关文档
最新文档