版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第5章数组5.1一维数组二维数组5.2字符数组和字符串5.3本章内容导读本章主要介绍一维数组和二维数组的定义、初始化和数组元素的引用方法,同时介绍字符数组和字符串的处理方法。通过学习本章,读者应掌握以下内容:掌握一维数组、二维数组、字符数组的定义、初始化和数组元素的引用方法;掌握字符串的存储和处理方法;掌握常用的处理字符、字符串的库函数的使用方法。数组是一种数据结构,处于这种结构中的变量具有相同的性质,并按一定的顺序排列。数组的定义:
数据类型数组名[数组长度];
a[0]0145a[1]a[2]a[3]a[4]a[5]23a数组元素(下标变量)数组中的每个分量,用下标来表示其所处位置,各分量排列有序且数据类型相同。数组元素的表示:数组名[下标]
数组名表示数组存储区域的首地址,数组的首地址也就是第一个元素的地址,是一个地址常量,不能向它赋值。例如:a或&a[0]下标用来表示该数组元素在数组中相对位置,是整型常量,最小值为0,最大值为数组长度-1。例如a[3]中的下标35.1一维数组定义
一维数组是只有一个下标的数组,数组同变量一样,也必须先定义后使用。例如inta[6];
数据类型符数组名1[长度1],数组名2[长度2],…;说明(1)“数据类型符”是指数组元素的数据类型,数据类型可以是任何基本类型。(2)数组名,与变量名一样,必须遵循标识符命名规则。(3)数组长度是用常量表达式来表示数组元素的个数,它是一个整型值,其中可以包含常数和符号常量,但不能出现变量。(4)数组名中存放的是一个地址常量,它代表整个数组的首地址。同一数组中的所有元素,按其下标的顺序占用一段连续的存储单元。(5)数组元素的下标,是元素相对于数组首地址或起始地址的偏移量,所以从0开始顺序编号。(6)一个数组定义语句中可以只定义一个数组,也可以定义多个数组,还可以同时定义数组和变量。
1、一维数组的定义5.1一维数组引用形式数组名[下标表达式]说明(1)“下标表达式”可以是一个整型常量、整型变量或整型表达式,取值范围是0至(元素个数-1)。
注意:在运行C语言程序时,系统不自动检验数组元素的下标是否越界。因此在编写程序时,保证数组下标不越界十分重要。(2)一个数组元素,实质上是一个变量,它具有和相同类型单个变量一样的属性,可以进行赋值和参与各种运算。(3)C语言中,数组作为一个整体,不能参加数据运算,只能对单个的元素进行处理。2、一维数组元素的引用5.1一维数组格式数据类型符数组名[长度]={初值表},…;说明(1)如果对数组的全部元素赋以初值,定义时可以不指定数组长度(系统根据初值个数自动确定)。如果被定义数组的长度,与初值个数不同,则数组长度不能省略。(2)“初值表”中的初值个数,可以少于元素个数,即允许只给部分元素赋初值。若只对数组的前若干个元素赋初值,则没有给出初值的元素均有默认的初值。对于数值型数组默认的初值为0;对于字符型数组,默认的初值为空字符'\0'(ASCII码值为0)。3、一维数组的初始化5.1一维数组给一维数组的全部元素赋初值给一维数组的部分元素赋初值初值的个数不能超过一维数组元素的个数给一维数组的全部元素赋初值时允许省略数组长度的说明注意:①数组长度可省略,赋初值时系统自动分配。②花括号中的常量个数小于数组长度,相应赋值后,其余赋0。③若数组长度小于初值个数,则编译错误。
inta[]={0,1,2,3,4,5,6,7,8,9};inta[10]={0,1,2,3,4,5,6,7,8,9};inta[10]={0,1,2,3,4};inta[4]={1,2,3,4,5};【例5-1】利用冒泡排序法对一维数组的n个整数从小到大排序。基本思想:通过相邻两个数之间的比较和交换,使数值较小的数据逐渐从底部移向顶部,数值较大的数逐渐从顶部移向底部。就像水底的气泡一样逐渐向上冒,故而得名。排序过程:设有n个数据,存放到a[1]到a[n]的n个数组元素中。(1)从a[1]到a[n],依次把两个相邻元素两两比较,即a[1]与a[2]比,a[2]与a[3]比,…,a[n-1]与a[n]比;(2)每次两相邻元素比较后,若前一个元素值比后一个元素值大,则交换两元素值;否则,不交换。(3)重复上述算法,把a[1]到a[n]中的最大值换到a[n],再把a[1]到a[n-1]中最大值换到a[n-1],……最后把a[1]到a[2]中最大值换到a[2]中,即完成排序。#include<stdio.h>intmain(void){int
i,j,k,n,temp,a[200];
printf("Inputnumbers:\n");
scanf("%d",&n);/*从键盘输入待排序的数据个数n<200*/for(k=1;k<=n;k++)
scanf("%d",&a[k]);/*利用for循环依次从键盘输入待排序的数据*/for(i=1;i<=n-1;i++)/*外层循环,变量i控制排序总共进行n-1轮*/for(j=n;j>=i+1;j--)/*内层循环,变量j控制每轮进行比较的次数是n-i*/if(a[j]<a[j-1]){temp=a[j];a[j]=a[j-1];a[j-1]=temp;}/*相邻两个元素比较,若前大后小则交换*/for(k=1;k<=n;k++)
printf("%d",a[k]);/*利用for循环依次输出排序结果*/return0;}【例5-2】利用选择排序法对一维数组的n个整数从小到大排序。基本思路:在每一轮比较中不是每当a[i]<a[j]时就交换,而是用一个变量k记下其中值较小的元素的下标值,在a[i]与a[i+1]到a[n]全部进行比较后,只将a[i]与a[i+1]到a[n]中值最小的那个元素进行交换,为此每一轮只需将a[i]与a[k]的值交换即可。#include<stdio.h>intmain(void){
int
i,j,temp,k,n,a[200];
printf("Inputnumbers:\n");
scanf("%d",&n);/*从键盘输入待排序的数据个数n<200*/for(i=0;i<n;i++)
scanf("%d",&a[i]);/*利用for循环依次从键盘输入待排序的数据*/for(i=0;i<n-1;i++)/*外层循环,变量i控制排序总共进行n-1轮*/{k=i;for(j=i+1;j<n;j++)/*内层循环,变量j控制每轮进行比较的次数*/if(a[j]<a[k])k=j;/*k记录每轮比较中的最小数的下标*/if(k!=i){temp=a[i];a[i]=a[k];a[k]=temp;}/*将第i轮的最小数与a[i]交换*/}
printf("thesortednumbers:\n");for(i=0;i<n;i++)printf("%d",a[i]);/*利用for循环依次输出排序结果*/return0;}定义格式
数据类型符数组名[行长度][列长度];例:inta[3][4];
a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]014523a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[0][0]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a[1][2]67101189a[0]a[1]a[2]第0行第1行第2行存储结构:以行为主序方式存放。二维数组长度=行长度*列长度
逻辑结构
第0列第1列第2列第3列5.2二维数组1、二维数组的定义引用形式数组名[行下标][列下标]
行号列号说明(1)“行下标”和“列下标”可以是整型常量、整型变量、整型表达式或符号常量。(2)“行下标”和“列下标”的值,都应在已定义数组大小的范围内。例如数组x[3][4],则可用的行下标范围为0~2,列下标范围为0~3。2、二维数组元素的引用5.2二维数组直述型:将所有常量写在一个花括号内,各个常量之间用逗号分开,按数组元素存储的顺序对各元素赋初值。inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};分列型:用花括号嵌套,即每一组一维数组的初值数据再用一对花括号括起。注意:若对全部元素都赋初值,第一维长度可省略,但第二维长度不能省。inta[3][4]={{1},{5},{9}};inta[][4]={1,2,3,4,5,6,7,8,9,10,11,12};3、二维数组的初始化5.2二维数组【例5-3】输入一个3*3的数组,将其行和列互换。#include<stdio.h>intmain(void){
int
i,j,b[3][3];staticinta[3][3]={{1,2,3},{4,5,6},{7,8,9}};for(i=0;i<=2;i++)for(j=0;j<=2;j++)b[j][i]=a[i][j];for(i=0;i<=2;i++){for(j=0;j<=2;j++)
printf("%d",b[i][j]);
printf("\n");}return0;}47258369【例5-4】求矩阵A与B乘积C。#include<stdio.h>intmain(void){int
i,j,k,m=2,n=3,p=2;staticinta[2][3]={{6,8,7},{3,4,5}};staticintb[3][2]={{1,2},{2,1},{-1,0}};staticintc[2][2]={{0,0},{0,0}};for(i=0;i<m;i++)for(j=0;j<p;j++){c[i][j]=0;for(k=0;k<n;k++)c[i][j]=c[i][j]+a[i][k]*b[k][j];}for(i=0;i<m;i++){for(j=0;j<p;j++)
printf("%d",c[i][j]);
printf("\n");}return0;}1520610一维字符数组的定义
char数组名[数组长度]={初值表};charc[10];二维字符数组的定义char数组名[行长度][列长度]={{初值表},{初值表},…,{初值表}};5.3字符数组和字符串1、字符数组的定义和初始化用字符常量对字符数组进行初始化charstr[8]={'p','r','o','g','r','a','m','\0'};charstr[8]={112,114,111,103,114,97,109,0};用字符的ASCII码值对字符数组进行初始化用字符串对字符数组进行初始化charstr[]="program";charstr[]={"program"};
注意:只能在定义时赋初值,不能在语句中直接将一个字符串赋给一个字符数组,可用strcpy()实现将一个字符串赋给另一个字符数组。
int
qus[19];qus[]="What'syourname?";1、字符数组的定义和初始化5.3字符数组和字符串字符数组的输入除了可以通过初始化使字符数组各元素获得初值外,也可使用getchar()或scanf()函数输入字符。例如charstr[10];
for(i=0;i<10;i++)
scanf("%c",&str[i]);2、字符数组的输入和输出5.3字符数组和字符串字符数组的输出字符数组的输出,可以用putchar()或printf()函数。例如charstr[10]="clanguage";
for(i=0;i<10;i++)printf("%c",str[i]);
printf("\n");
注意:逐个字符输入、输出时需要给出元素的下标,而且使用%c格式符。另外,从键盘上输入字符时,无需输入字符的定界符──单引号;输出时,系统也不输出字符的定界符。2、字符数组的输入和输出5.3字符数组和字符串逐个字符的输入和输出scanf("%c",&ch);printf("%c",ch);ch=getchar();putchar(ch);
3、字符串5.3字符数组和字符串【例5-5】逐个字符输入输出。#include<stdio.h>intmain(void){inti;charstr[10];for(i=0;i<9;i++)scanf("%c",&str[i]);
str[i]='\0';for(i=0;i<9;i++)printf("%c",str[i]);return0;}123456789123456789str[i]=getchar();putchar(str[i]);字符串的整体输入和输出scanf("%s",字符数组名);注意:输入时自动加'\0'。printf("%s",字符数组名);charc[]={"China"};printf("%s",c);输出:Chinacharc[]={"China"};printf("%s",c[0]);charstr[13];scanf("%s",str);输入:Howareyou<CR>charstr[13];scanf("%s",&str);charstr1[5],str2[5],str3[5];scanf("%s%s%s",str1,str2,str3);输入:Howareyou<CR>整行输入和输出gets(str);注意:读入由键盘输入的字符(包括空格),直至换行符为止(换行符不存入)。puts(str);注意:把字符串的内容显示在屏幕上。charstr[]={"China\nBeijing"};puts(str);输出:ChinaBeijing3、字符串5.3字符数组和字符串在使用以下字符串处理的库函数时应在源程序中包含头文件“string.h”。字符串输入函数gets()调用格式
gets(字符数组名)功能:从标准输入设备即键盘上读取一个字符串(可以包含空格,仅以回车换行符作为结束标志),并将其存储到指定的字符数组中。说明(1)gets()函数读取的字符串的长度没有限制,编程者应保证字符数组有足够大的空间,存放输入的字符串。(2)gets()函数和使用%s格式的scanf()函数都可以从键盘输入字符串,但两者是有区别的。对于scanf()函数,回车换行符和空格符都看成是输入字符串的结束标志;对于gets()函数输入的字符串中允许包含空格,只有回车换行符才看作是输入字符串的结束标志。4、字符串处理的常用库函数5.3字符数组和字符串字符串输出函数puts()调用格式puts(字符数组名)功能:把字符数组中所存放的字符串,输出到标准输出设备中去,并用'\n'取代字符串的结束标志'\0'。所以用puts()函数输出字符串时,不要求另加换行符。说明(1)字符串中允许包含转义字符,输出时产生一个控制操作。(2)puts()函数和使用%s格式的printf()函数都可以输出字符串,但两者是有区别的。对于printf()函数,不输出字符串结束标志符;对于puts()函数,字符串结束标志符转换为回车换行符输出。此外,puts()函数一次只能输出一个字符串,而printf()函数用来输出字符串时一次可以输出多个。4、字符串处理的常用库函数5.3字符数组和字符串字符串比函数strcmp()调用格式
strcmp(字符串1,字符串2)参数:“字符串1”和“字符串2”可以是字符串常量,也可以是已经存放字符串的字符数组名。功能:比较两个字符串的大小。
如果字符串1=字符串2,函数返回值是0;
如果字符串1<字符串2,函数返回值是负整数;
如果字符串1>字符串2,函数返回值是正整数。说明(1)如果一个字符串是另一个字符串从头开始的子串,则母串为大。(2)不能使用关系运算符==比较两个字符串,只能用strcmp()函数处理。4、字符串处理的常用库函数5.3字符数组和字符串strcmp(str1,str2);strcmp("China","Korea");strcmp(str1,"Beijing");字符串复制函数strcpy()调用格式
strcpy(字符数组名,字符串[,整型表达式])参数:字符数组”是已经定义的字符数组名;“字符串”可以是字符串常量,也可以是已经存放字符串的字符数组名;“整型表达式”可以是任何整型表达式,这一参数也可以省略。功能:将“字符串”的前“整型表达式”个字符组成新的字符串复制到“字符数组”中。若省略“整型表达式”,则将“字符串”完整地复制到“字符数组”中,字符数组的原有内容被覆盖。说明(1)字符数组必须定义得足够大,以便容纳复制过来的字符串。复制时,连同结束标志'0'一起复制。(2)不能用赋值运算符=将一个字符串直接赋值给一个字符数组,只能用strcpy()函数处理。4、字符串处理的常用库函数5.3字符数组和字符串charstr1[10],str2[]={"China"};strcpy(str1,str2);字符串连接函数strcat()调用格式strcat(字符数组名,字符串)功能:把“字符串”连接到“字符数组”中字符串的尾端(最后一个有效字符的后面),组成新的字符串并存储到“字符数组”。“字符数组”中原来的结束标志,被“字符串”的第一个字符覆盖,而“字符串”在操作中未被修改。返回值:字符数组的首地址。说明(1)由于没有边界检查,编程者要注意“字符数组”定义得足够大,以便容纳连接后的目标字符串;否则会因长度不够而产生问题。(2)连接前两个字符串都有结束标志'0',连接后“字符数组”中存储的字符串的结束标志'0'被舍弃,只在目标串的最后保留一个'0'。4、字符串处理的常用库函数5.3字符数组和字符串charstr1[30]={"People'sRepublicof"};charstr2[]={"China"};printf("%s",strcat(str1,str2));输出:People'sRepublicofChina测字符串长度函数strlen()调用格式strlen(字符串)功能:求字符串(常量或字符数组)的实际长度(不包含结束标志)。字符串大写字母转换成小写函数strlwr()调用格式strlwr(字符串)功能:将字符串中的大写字母转换成小写,其它字符(包括小写字母和非字母字符)不转换。字符串小写字母转换成大写函数strupr()调用格式strupr(字符串)功能:将字符串中小写字母转换成大写,其它字符(包括大写字母和非字母字符)不转换。charstr[10]={"China"};printf("%d",strlen(str));输出:5【例5-6】从键盘输入一个字符串,回车键结束,并将字符串在屏幕上输出。#include<stdio.h>intmain(void){
inti;staticcharstr[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(); /*程序暂停*/return0;}
ThankYou!第6章函数6.1函数的概念和模块化程序设计函数声明6.2函数的参数和数据传递方式6.36.4变量的存储类型和作用域6.5函数的嵌套调用和递归调用6.6常用库函数本章内容导读本章主要介绍函数的定义和调用方法,函数之间数据传递方式以及常用的库函数,函数的嵌套调用和递归调用以及模块化程序设计。通过学习本章,读者应掌握以下内容:了解模块化程序设计方法;掌握用户自定义函数的定义和调用方法;掌握函数声明的作用;掌握函数调用时的数据传递方式;了解变量生存期和作用域的概念;了解递归函数的概念和一般设计方法。函数是一段相对独立、功能完整的程序。一个C语言程序是由一个或多个函数组成,每个函数分别对应一个功能模块。特点(1)一个C程序由一个或多个函数组成,其中必须有且只能有一个main函数(称为主函数)。(2)C程序的执行从主函数开始,如果在主函数中调用其他函数,调用后返回到主函数,并在主函数中结束整个程序的运行。(3)主函数可以调用其他函数,但其他函数不能调用主函数。主函数由操作系统调用,其他函数之间可以互相调用。(4)函数之间没有从属关系,互相独立,不能嵌套定义。1、函数的概念6.1函数的概念和模块化程序设计从函数定义的角度划分库函数(又称标准库函数):由C语言的函数库提供,即C语言自身已经定义好的函数,在包含相应头文件后用户可以直接使用;用户函数(又称自定义函数):是用户根据需要自行定义的完成某一特定功能的一段程序。从函数有无参数的角度划分有参函数:定义函数时有参数的称为有参函数;无参函数:定义函数时无参数的称为无参函数。1、函数的概念6.1函数的概念和模块化程序设计从函数有无返回值的角度划分有返回值函数:调用后返回一个值;无返回值函数:调用后不返回值。从函数作用范围的角度划分C语言允许将一个源程序分放在不同的程序文件中,采用分块编译、连接生成一个目标程序,其中每个程序文件称为一个“编译单元”。每个编译单元可以包含若干个函数。外部函数:可以被任何编译单元调用的;内部函数:只能在本编译单元中被调用。1、函数的概念6.1函数的概念和模块化程序设计函数定义的一般形式数据类型符函数名(形式参数表){数据定义语句部分;执行语句部分;}函数首部(函数头)函数体
例:两个数之和的函数。doubleadd(doublex,doubley){doublez;z=x+y;returnz;}函数体:{}中的内容,包括说明语句和执行语句。空函数:函数体为空的函数,例{},便于扩充和细化程序。说明(1)任何函数(包括主函数)都是由函数首部和函数体两部分组成。(2)函数首部末尾不能加分号。(3)“函数名”是一个标识符,在同一个编译单元中函数不能重名。(4)C语言中,所有函数(包括主函数)都是平行的。一个函数的定义,可以放在程序中的任意位置,主函数之前或之后。但是在一个函数的函数体内不能再定义另一个函数,即不允许函数的嵌套定义。2、函数的定义6.1函数的概念和模块化程序设计
无参函数定义格式
数据类型符或void函数名(void){数据定义语句部分;执行语句部分;}
有参函数定义格式
数据类型符或void函数名(形式参数表){定义语句部分;执行语句部分;}2、函数的定义6.1函数的概念和模块化程序设计
无返回值函数定义格式
void函数名(形式参数表或void)
{数据定义语句部分;执行语句部分;
}
有返回值函数定义格式数据类型符函数名(形式参数表或void)
{定义语句部分;执行语句部分;}2、函数的定义6.1函数的概念和模块化程序设计C程序是通过对函数的调用来执行函数体。被调函数应该先定义,后调用。格式
函数名([实际参数表]);调用方式
(1)以函数语句的方式
函数名(实际参数表);(2)以函数表达式的方式
变量=带函数的表达式;(3)以函数实参的方式func1(x,y,z);c=max(a,b);printf("thelargenumberis%f",add(x,y));3、函数的调用6.1函数的概念和模块化程序设计【例6-1】编写一个程序求解从m个元素选n个元素的组合数程序。计算公式:分析:用函数f(x)求x!;cmn=f(m)/f(n)/f(m-n);longf(x)intx;{longy;for(y=1;x>0;--x)y=y*x;return(y);}#include<stdio.h>intmain(void){int
m,n;longcmn,temp;longf();
printf("Entermandn:");
scanf("%d%d",&m,&n);
cmn=f(m);temp=f(n);
cmn=cmn/temp;
cmn=cmn/f(m-n);
printf("Thecombination:%ld\n",cmn);return0;}Entermandn:43Thecombination:4函数的形式参数和实际参数形式参数(简称形参):是在函数定义中设置的,用来接收从主调函数传来的对应实参的数据。实际参数(简称实参):是调用函数时的实际参数,实参可以是常量、变量或表达式,也可以是函数的返回值,无论哪种形式必须有确定的值。注意(1)形参在调用时才被分配内存空间,调用结束后释放。(2)实参可以是常量、变量或表达式,但要求有确定值。(3)实参在数量、类型和顺序上与形参必须一一对应和匹配。如果参数的数量不一致,则会出现编译错误;如果参数的顺序不一致,则传递到被调函数中的数据不合逻辑;如果参数的类型不一致,则按照形参类型对实参进行自动转换,如果是不能进行转换的类型,则出现编译错误。(4)实参向形参的单向传递,“值传递”,即只由实参传给形参,而不能由形参传回给实参。3、函数的调用6.1函数的概念和模块化程序设计返回值类型函数返回值的类型即函数类型,是指返回给主调函数的结果的类型,应根据具体函数的功能确定。如果函数不返回任何值,则函数返回值类型定义为“void”,称为“空类型”。有参函数的返回值,是通过函数中的return语句获得。return语句功能:返回调用函数,并将“返回值表达式”的值带给调用函数。使用方式(1)无返回值的函数return;(2)有返回值的函数return(返回值表达式);或return返回值表达式;4、函数的返回6.1函数的概念和模块化程序设计说明(1)一个函数中可以有多个return语句
(2)若无return语句,则执行到函数体末尾后,并不是不返回一个值,而是返回一个不确定的值。
(3)若无值返回,则函数应定义为void类型。
(4)return语句中表达式的类型与函数类型一致。若不一致,以函数值类型为准。4、函数的返回6.1函数的概念和模块化程序设计(1)暂停执行函数调用所在的语句,转向执行被调函数。(2)为函数的所有形参分配内存,再计算所有实参的值,依次赋予对应的形参。若是无参函数,则不执行这一操作。(3)进入函数体,先执行数据定义语句部分,为函数体中定义的变量、数组等分配内存。(4)执行函数体中的执行语句部分。如果是无返回值的函数,则执行到返回语句;如果返回语句被省略,则执行到函数体的右花括号;如果是有返回值的函数,则执行到返回语句时,计算表达式的值作为函数的返回值。(5)收回分配给函数体中定义的变量、数组、形参等的内存单元。(6)返回到主调函数继续执行。如果函数调用的形式是“语句”,则执行其后面的语句;如果函数调用的形式是“表达式”,则继续执行表达式所在的语句。5、函数的调用过程6.1函数的概念和模块化程序设计C语言中,一个大的程序由许多源程序文件(又称程序模块,通常是一些相关函数的集合)组成,而源程序文件由预编译和许多函数组成。C语言程序源文件(程序模块)结构包含文件,例如#include<stdio.h>宏定义,例如#definePI3.14159条件编译,例如#if…#else…#endif函数声明,例如定义函数的原型全局变量说明,例如函数外定义的变量函数定义源文件包含文件宏定义条件编译函数预说明全局变量说明函数模块定义函数模块定义……大程序6、模块化程序设计方法6.1函数的概念和模块化程序设计在调用函数之前应当对调用的函数进行声明,让编译程序预先了解函数的有关信息。格式[存储类型][数据类型符]函数名(形参类型[形参名1][,形参类型[形参名2],…]);说明(1)函数声明是一条语句,末尾加分号;而函数首部不是语句,末尾不加分号。(2)函数声明与函数定义是不同的。函数定义是编写一段程序,除了指定函数名、返回值类型、形参名、形参类型外,还有函数体;而函数声明只是把函数名、返回值类型、形参名、形参类型等通知编译程序,以便在调用该函数时系统据此对照检查,它没有函数体。例如,intmax(int
x,inty){……}的函数原型是intmax(int,int);6.2函数的声明若主调函数与被调函数不在同一编译单元中,则在定义函数的编译单元中必须将该函数定义为外部函数,同时在主调函数的函数体中或主调函数所在编译单元的开头将被调函数进行声明:extern数据类型符函数名(形式参数表);;若主函数与被调函数在同一编译单元中,则可以不说明其函数原型。同时C语言又规定,若被调函数的函数定义出现在主调函数之前,则在主调函数中可以省略对被调函数的声明。因为在调用之前,编译程序已经知道了被调函数的函数类型、参数个数、类型和顺序等信息。除了上述两种情况,都需要对被调函数进行声明。
6.2函数的声明被调用函数若为系统函数(库函数):除了少数库函数(如scanf()、printf())外,都要求在本文件开头用包含命令包含被调函数的信息。用户函数函数声明的几种形式
数据类型符函数名(形参类型形参名1,形参类型形参名2,……);
数据类型符函数名(形参类型1,形参类型2,……);
数据类型符函数名();intmax(inta,intb);intmax(int,int);intmax();6.2函数的声明说明(1)函数原型告诉编译程序函数返回的数据类型、函数所要接收的参数个数、参数类型和参数顺序,编译程序利用函数原型校验函数调用是否正确。(2)函数原型中可以只说明形参类型和形参个数,而无需说明形参名。例如,对函数intmax(int
x,inty){……}的声明以下两种形式均可:
int
max(int,int);
int
max(int
x,int
y);(3)函数原型、函数定义、函数调用要保持一致。和函数原型不匹配的函数调用会导致语法错误;函数原型和函数定义不一致,也会产生错误。6.2函数的声明说明(4)函数原型可以在主调函数中声明;也可以在所有函数的外部(如文件声明处)进行声明。这种情况下,在该声明之后定义的所有函数均可以调用该函数,而不必再声明。(5)如果程序中没有包含函数原型,则编译程序会用第一次出现的该函数(函数定义或函数原型)来构造函数原型。6.2函数的声明函数之间数据传递方式值传递地址传递返回值全局变量传递前两种方式是利用定义函数时设置的形参和调用函数时给出的实参来传递数据的。
6.3函数的参数和数据传递方式
值传递方式是在形参和实参之间传递数据的一种方式。传递方式传递的是参数值。判断的唯一方法是看函数定义时的形参是不是变量形式如果形参是变量,则是值传递方式。1、值传递方式6.3函数的参数和数据传递方式数组作为函数参数的两种形式
数组元素作为函数实参数组元素只能用作函数实参,其用法与普通变量完全相同,即在发生函数调用时,把数组元素的值传送给形参,实现单向值传送。数组元素作为实参时,只要数组的类型和函数形参的类型一致即可,并不要求函数的形参也是下标变量。换言之,对数组元素的处理是按普通变量对待的。普通变量或下标变量作为函数参数时,形参变量和实参变量由编译程序分配不同的内存单元。在函数调用时进行值传送,把实参变量的值赋予形参变量。
2、数组作为函数参数的数据传递方式6.3函数的参数和数据传递方式数组名作为函数参数(形参和实参)数组名作函数参数时,既可以作形参,也可以作实参。数组名作函数参数时,要求形参和相对应的实参都必须是类型相同的数组(或指向数组的指针变量),都必须有明确的数组说明。如果形参是数组名,则传递方式称为“地址传递方式”
2、数组作为函数参数的数据传递方式6.3函数的参数和数据传递方式当一维数组名做形参时可以指定数组的长度,也可以不指定数组的长度,而只在数组名后面跟一对空的方括号。当多维数组名做实参和形参时,形参数组可以省略第一维的长度说明,但第二维及以上的长度说明不能省略。
不是在形参和实参之间进行数据传递,而是通过函数调用直接返回一个值到主调函数。因此,这种方式通常用于从被调函数向主调函数回传值。注意(1)函数首部中需要有“数据类型符”,说明该函数返回值的数据类型。(2)函数体中需要有语句“return(表达式);”,其中的表达式即是函数的返回值。3、利用返回值的数据传递方式6.3函数的参数和数据传递方式变量存储类型自动型(auto)寄存器型(register)外部型(extern)静态型(static)变量存储方式静态存储方式在编译时由系统分配固定的存储空间,直到程序运行结束后才释放所占用的存储空间。动态存储方式在程序运行时根据需要动态地分配和释放存储空间。自动型和寄存型器变量属于动态存储方式,外部型和静态型变量属于静态存储方式。1、变量的存储类型6.4变量的存储类型和作用域自动型变量
定义格式
[auto]数据类型变量表;
说明
(1)自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。(2)定义时如果没有初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。(3)由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。建议:系统不会混淆,并不意味着人也不会混淆,所以尽量少用同名自动型变量!1、变量的存储类型6.4变量的存储类型和作用域静态型变量定义格式
static数据类型变量表;
说明(1)静态内部变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。换言之,在程序执行期间,静态内部变量始终存在,但其它函数是不能引用它们的。(2)定义但不初始化,则自动赋以0(整型和实型)或‘\0’(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值。(3)何时使用静态内部变量:需要保留函数上一次调用结束时的值。变量只被引用而不改变其值。1、变量的存储类型6.4变量的存储类型和作用域寄存器型变量一般情况下,变量的值都是存储在内存。为提高执行效率,C语言允许将局部变量的值存放到寄存器,这种变量称为寄存器变量。
定义格式register数据类型变量表;
说明(1)只有局部变量才能定义为寄存器变量,全局变量不行。(2)对寄存器变量的实际处理,随系统而异。例如,微机上的MSC和TC将寄存器变量实际当作自动变量处理。(3)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。1、变量的存储类型6.4变量的存储类型和作用域外部型变量定义格式
extern数据类型外部变量表;
说明:外部型变量是专门用于在多个编译单元之间传递数据的。当编译单元A需要使用在编译单元B中定义的变量,则编译单元A需要将该变量声明为外部型变量,以便C编译系统在编译单元A之外的其它编译单元中寻找该变量的定义,而在编译单元B中需要定义该变量的存储类型和数据类型。关键字extern与auto、static和register的用法不同,后三个关键字是在定义变量时加关键字,而extern是对已经定义的全局变量进行声明。注意:函数内的extern变量说明,表示引用本源文件中的外部变量;函数外(通常在文件开头)的extern变量说明,表示引用其它文件中的外部变量。1、变量的存储类型6.4变量的存储类型和作用域变量的生存期从系统为变量分配内存单元(或寄存器)开始到系统收回内存单元(或寄存器)的期间称为“变量的生存期”。在变量的生存期以外使用该变量会导致编译错误。变量的作用域C语言中所有的变量都有其作用域。变量说明的位置不同,其作用域也不同。2、变量的生存期和作用域6.4变量的存储类型和作用域intf1(inta)/*函数f1*/{
int
b,c;
……} /*a、b、c作用域:仅限于函数f1()中*/
intf2(intx)/*函数f2*/{
int
y,z;
……} /*x、y、z作用域:仅限于函数f2()中*/intmain(void){
int
m,n;
……} /*m、n作用域:仅限于函数main()中*/说明(1)主函数中定义的内部变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。(2)形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部变量。(3)允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。(4)在复合语句中也可定义变量,其作用域只在复合语句范围内。2、变量的生存期和作用域6.4变量的存储类型和作用域全局变量
定义:生存期覆盖了定义点到整个程序结束的变量。局部变量定义:生存期只覆盖了某个函数(或复合语句)的变量。对于局部变量,声明存储类型的作用是指定变量的存储位置(静态存储区或动态存储区)和生存期;对于全局变量,声明存储类型的作用是扩展或限制变量的作用域。2、变量的生存期和作用域6.4变量的存储类型和作用域内部变量
定义:在一个函数(或复合语句)内部定义的变量。作用域:该函数(或复合语句)范围内有效,即只在包含变量定义的函数(或复合语句)内部,才能使用该变量,在此函数(或复合语句)之外则不能使用。说明(1)主函数中定义的内部变量,只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它高级语言不同。(2)形参变量也是内部变量,仅限于函数内使用。(3)允许在不同函数中使用重名的变量,它们代表不同的对象,分配不同的内存单元,互不干扰,也不会发生混淆。2、变量的生存期和作用域6.4变量的存储类型和作用域说明(4)复合语句中也可定义变量,所定义的变量是内部变量,其作用域只在该复合语句范围内。例如,
if(i>j) {
int
k; k=i;i=j;j=k;k有效 }
2、变量的生存期和作用域6.4变量的存储类型和作用域外部变量定义:在函数外部定义的变量。作用域:从定义位置开始到本文件结束为止。它不属于任何一个函数,可被作用域内的所有函数直接引用。说明(1)外部变量可以加强函数模块之间的数据联系,但又使这些函数依赖这些外部变量,因而使得这些函数的独立性降低。从模块化程序设计的观点来看这是不利的,因此不是非用不可时,不建议使用外部变量。(2)在同一源程序文件中,允许外部变量和内部变量重名。如果外部变量和内部变量重名,则在内部变量的作用域内,外部变量将被屏蔽而不起作用。2、变量的生存期和作用域6.4变量的存储类型和作用域说明(3)外部变量的作用域是从定义点到本文件结束。如果定义点之前的函数需要使用这些外部变量时,需要在函数内对被使用的外部变量进行说明。外部变量说明的一般形式为:extern数据类型外部变量1[,外部变量2……];注意:外部变量的定义和外部变量的说明不同。外部变量的定义,必须在所有的函数之外,且只能定义一次。而外部变量的说明,出现在需要使用该全局变量的函数内,而且可以出现多次。2、变量的生存期和作用域6.4变量的存储类型和作用域静态局部变量和静态外部变量同属静态存储方式,区别在于:(1)定义的位置不同。静态局部变量在函数内定义,静态外部变量在函数外定义。(2)作用域不同。静态局部变量属于内部变量,其作用域仅限于定义它的函数内;虽然生存期为整个源程序,但其它函数是不能使用它的。静态外部变量在函数外定义,其作用域为定义它的源文件内;生存期为整个源程序,但其它源文件中的函数也是不能使用它的。(3)初始化处理不同。静态局部变量,仅在第1次调用它所在的函数时被初始化,当再次调用定义它的函数时,不再初始化,而是保留上1次调用结束时的值。而静态外部变量是在函数外定义的,不存在静态内部变量的“重复”初始化问题,其当前值由最近1次给它赋值的操作决定。
2、变量的生存期和作用域6.4变量的存储类型和作用域务必牢记:把局部变量改变为静态内部变量后,改变了它的存储方式,即改变了它的生存期。把外部变量改变为静态外部变量后,改变了它的作用域,限制了它的使用范围。因此,关键字“static”在不同的地方所起的作用是不同的。2、变量的生存期和作用域6.4变量的存储类型和作用域不是在形参和实参之间传递数据,而是利用在主调函数和被调函数中都有效的全局变量,在主调函数和被调函数之间共享数据。如前所述,全局变量是生存期覆盖了定义点到整个程序结束的变量。具体地,全局变量有两种,一是在任何函数之外定义的全局变量,其作用域覆盖了定义点到整个程序结束之间的所有函数,这种全局变量叫做“外部变量”;二是在函数体内部定义为static型的变量,该变量在从函数返回后,仍保留所分配的内存(活着),但是不能使用,其作用域仍是该函数体内。这种全局变量叫做“内部变量”。因此,在函数之间利用全局变量传递数据,只能使用“外部变量”。3、利用全局变量的数据传递方式6.4变量的存储类型和作用域递归函数:又称自调用函数,简洁但不一定高效。三个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 教资科二模拟试题及答案
- 2026年风电与校园能源系统优化方案
- 2025-2026学年四川省阿坝藏族羌族自治州三年级数学下学期期末质量跟踪监视试题(含解析)
- 医疗器械冷链运输贮存指南
- 2025-2026学年四川省广元市元坝区四下数学期中学业水平测试模拟试题(含答案解析)
- 2026中国校园洗衣APP用户粘性提升与盈利模式创新报告
- 2026中国游戏电竞硬件设备核心部件材料供应研究及消费电子产业发展策略
- 2026智慧城市安防体系建设需求变化与创新解决方案白皮书
- 2025-2026学年唐山市迁安市数学四下期中复习检测试题(含答案)
- 2026挪威航运物流行业供需现状分析及投资价值规划分析报告
- 2026-2030中国高纯氧化钇行业发展态势及投资动态预测报告
- 安全继电器工作原理培训课件
- 2026年4月自考00539中国古代文学史(二)试题及答案含评分参考
- 气象灾害科普类
- 人防地下室技术交底
- 2025版中国绝经管理与绝经激素治疗指南课件
- 2025海南省生态环境监测中心招聘事业编制人员(十三)(公共基础知识)测试题带答案解析
- 2025年10月自考00699材料加工和成型工艺试题及答案
- 2025中国国新资产管理有限公司相关岗位招聘4人备考题库附答案
- 中医疫病学课件
- 2025年水务公司招聘考试题库
评论
0/150
提交评论