首页 第三章 函数和变量存储

第三章 函数和变量存储

举报
开通vip

第三章 函数和变量存储第三章:函数和函数调用 第三章:函数和函数调用 第三章:函数和函数调用 学习目标 · 使用函数的优点 · C语言函数的基本概念 · 掌握C语言中常用的内置函数 · 理解函数原型和返回值 · 熟练掌握自定义函数的定义和调用 · 熟悉带参数函数的调用 · 变量的作用域 为什么要使用函数 ...

第三章 函数和变量存储
第三章:函数和函数调用 第三章:函数和函数调用 第三章:函数和函数调用 学习目标 · 使用函数的优点 · C语言函数的基本概念 · 掌握C语言中常用的内置函数 · 理解函数原型和返回值 · 熟练掌握自定义函数的定义和调用 · 熟悉带参数函数的调用 · 变量的作用域 为什么要使用函数 大家在前面知道了变量、 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 达式和程序的概念,试想一个程序如果有1000行,我们如果要理解这段代码,就必须从头到尾阅读所有的代码,而我们这样做的目的有可能只是为了改动其中很少的部分,有没有更好的组织代码的方式,让我们可以很快的读懂代码呢?再作以下假设,如果这段代码要重复十次,我们是否要让它重复10遍呢?所有的这些问 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 ,通过函数就可以迎刃而解了。我们总结一下,引入函数,主要是这样几个目的: · 把程序按语义分成几个部分,提高程序的可读性 对于比较长的代码,我们一般都会把它按功能分为几个部分,这样作可以大大提高程序的可读性(这有点类似与我们看一篇文章,如果我们能够知道其中一段文字的大意,就算不看这段文字细节,也不会影响我们理解整篇文章),所以,通过函数,我们不需要关注程序的所有细节,我们就可以理解整个程序的功能,如果,需要改动其中的某些部分,也很快就可以找到改动的地方。 · 独立的部分可以重复使用 如果程序中有多处地方使用了相同的代码,那么,我们就可以把这部分的代码独立出来,这样对这段代码,我们就只要写一次了,而在多处重复的地方使用就可以了,这简化了整个程序,同时带来的另一个好处是:如果要改动的话,我们也只要改动一个地方就可以了,而不需要在程序中改动多处。 · 通过现成的函数,降低程序开发的难度 语言功能的强大,是因为提供了很多现成的函数供我们直接使用,比如输出函数就是一个典型的例子,如果,你要自己去实现在屏幕上输出文字,那将是一个很复杂的过程,因为这涉及到了硬件,一般人肯定做不了,但通过函数,我们可以很容易实现(使用printf)。 函数的基本概念: · 什么是函数 函数其实就是一段代码,为了能够辨认这段代码,我们给这段代码取一个名字,叫做函数名。C源程序就是由函数组成的。虽然在前面介绍的程序中都只有一个主函数main(),但实际程序往往由多个函数组成。函数是C源程序的基本模块,通过对函数模块的调用可以实现特定的功能。用户可把自己的算法编成一个个相对独立的函数模块,然后用调用的 方法 快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载 来使用。可以说C程序的全部工作都是由各式各样的函数完成的,所以也把C语言称为函数式语言。由于采用了函数模块式的结构,C语言易于实现结构化程序设计。使程序的层次结构清晰,便于程序的编写、阅读、调试。 · 函数的分类 在C语言中可从不同的角度对函数分类 · 从函数定义的角度看,函数可分为库函数和用户定义函数两种: 1) 库函数 由C系统(开发环境)提供,用户无须定义,也不必在程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。C语言提供了极为丰富的库函数(300多个),比如我们常用到的printf 、 scanf都叫做库函数。 2) 用户自定义函数 由用户按需要写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。在实现系统的时候,我们会定义大量的函数。 · 从函数参数的角度,又可把函数分为无参函数和有参函数两种。 1)无参函数 函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。此类函数通常用来完成一组指定的功能,可以返回或不返回函数值。 2)有参函数 也称为带参函数。在函数定义及函数说明时都有参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,实际参数(简称为实参)。进行函数调用时,主调函数将把实参的值传送给形参,供被调函数使用。 · C语言提供了极为丰富的库函数, 这些库函数又可从功能角度作以下分类。 1)字符类型分类函数 用于对字符按ASCII码分类:字母,数字,控制字符,分隔符,大小写字母等。 2)转换函数 用于字符或字符串的转换;在字符量和各类数字量 (整型, 实型等)之间进行转换;在大、小写之间进行转换。 3)目录路径函数 用于文件目录和路径操作。 4)诊断函数 用于内部错误检测。 5)图形函数 用于屏幕管理和各种图形功能。 6)输入输出函数 用于完成输入输出功能。 7)接口函数 用于与DOS,BIOS和硬件的接口。 8)字符串函数 用于字符串操作和处理。 9)内存管理函数 用于内存管理。 10)数学函数 用于数学函数计算。 11)日期和时间函数 用于日期,时间转换操作。 12)进程控制函数 用于进程管理和控制。 13)其它函数 用于其它各种功能。 以上各类函数不仅数量多,而且有的还需要硬件知识才会使用,因此要想全部掌握则需要一个较长的学习过程。应首先掌握一些最基本、最常用的函数,再逐步深入。由于篇幅关系,本章只介绍一部分库函数, 其余部分读者可根据需要查阅有关手册。 还应该指出的是,在C语言中,所有的函数定义,包括主函数main在内,都是平行的。也就是说,在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。但是函数之间允许相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数还可以自己调用自己,称为递归调用。main函数是主函数,它可以调用其它函数,而不允许被其它函数调用。因此,C程序的执行总是从main函数开始,完成对其它函数的调用后再返回到main函数,最后由main函数结束整个程序。一个C源程序必须有,也只能有一个主函数main · 函数定义语法和调用 函数定义语法: 函数返回类型 函数名(函数参数[,函数参数]) { //函数代码 } 例:函数语法定义。参见图 从上面可以看出: 函数分为两个部分: 函数头和函数体 函数头包括:函数返回类型,函数名,函数参数列表 函数体:从’{’开始到’}’结束部分,叫做函数体 函数要注意三个概念:函数声明、函数定义(实现)和函数调用. · 函数声明:只包含函数头,以分号结束,函数声明和变量声明的作用是一样的,变量我们必须先声明后使用,函数也是一样的,使用函数(调用函数)的时候,编译器必须要看到函数的声明或者定义。 如:int max(int a,int b); · 函数定义(实现):包含函数头和函数体,它的作用就是通过代码实现具体函数的功能 如:int max(int a,int b){} · 函数调用(使用):在程序中是通过对函数的调用来执行函数体的,包括函数名,参数应该是具体的值,可以使用变量接受该函数的返回值 如:int t = max ( 10,20); 掌握C语言中常用的内置函数 C语言的内置函数很多,在这里我们将介绍一些常用的函数:见表 类 别 函数名称 简 介 式化输出 printf(),fprintf(), sprintf(), vprintf(), vfprintf(), vsprintf() 格式化输出到屏幕,格式化输出到文件,格式化输出到字符串 格式化输入 fscanf(), scanf(), sscanf() 分别从文件,控制台,字符串中读入数据 字符相关函数 fgetc(), fgets(), fputc(), fputs(), getc(), gets(), putc(),puts(), putchar(), ungetc() 从文件或控制台读入字符串,把字符串写入文件或控制台 isalnum(c),isalpha(c),iscntrl(c), isdigit(c), tolower(c), toupper(c) 判断或者转换字符 文件操作 fopen(), freopen(), fflush(), fclose(), remove(), rename(), tmpfile(), tmpnam(), setvbuf(),setbuf() fseek(), ftell(), rewind(), fgetpos(), fsetpos() 对文件的操作: 包括打开文件、关闭文件、移动文件指针,得到设定位置 数学函数 sin(), cos(), tan(), asin(), acos(), atan(), atan2(), sinh(), cosh(), tanh(), exp() log(), log10(), pow(), sqrt(), ceil(), floor(), fabs(), ldexp(), frexp(), modf(), fmod() 数学函数:包括三角函数,平方,开方,等 日期与时间函数 clock(), time(), difftime(), mktime(), asctime(), ctime(), strftime() 取系统的时间,以及对时间进行转换 实用函数 atof(), atoi(), atol(), strtod(), strtoul(), rand(), srand(), calloc(), malloc(), realloc(), free(), abort(), exit(), atexit(), system(), getenv(), bsearch(), qsort(), abs(), labs(), div(), ldiv() 数据类型转换,随机数,内存操作内存,进程相关函数以及排序/查找函数 诊断 assert() 诊断函数 字符串函数 strcpy(),strncpy(), strcat(), strncat(), strcmp(), strncmp(), strchar(), strrchr(), strspn(), strcspn(), strpbrk(), strstr(), strlen(), strerror(), strtok() 处理字符串的拷贝、拼接,比较等操作,以及求字符串的长度 错误处理函数 clearerr(), feof(), ferror(), perror() 各种错误处理 目录路径函数 chdir chdrive getdiskfree getdrive getdrivers mkdir rmdir searchenv 改变/得到当前驱动器、改变/得到当前目录、得到磁盘的剩余空间、建立/删除目录、在指定目录查找文件 理解函数返回值 函数的值是指函数被调用之后, 执行函数体中的程序段所取得的并返回给主调函数的值。如调用正弦函数取得正弦值,调用前面例子中max函数取得的两个数的最大数。对函数的值(或称函数返回值)有以下一些说明: 函数的值只能通过return语句返回主调函数。return 语句的一般形式为: return 表达式; 或者为:return (表达式); 该语句的功能是计算表达式的值,并返回给主调函数。 · 在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行, 因此只能返回一个函数值。 · 函数值的类型和函数定义中函数的类型应保持一致。 如果两者不一致,则以函数类型为准,自动进行类型转换。 · 如函数值为整型,在函数定义时可以省去类型说明。 · 不返回函数值的函数,可以明确定义为"空类型", 类型说明符为 "void"。 如函数s并不向主函数返函数值,可定义为:void s(int n){……}一旦函数被定义为空类型后,就不能在主调函数中使用被调函数的函数值了。例如,在定义s为空类型后,在主函数中写下述语句sum=s(n);就是错误的。为了使程序有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型。函数说明在主调函数中调用某函数之前应对该被调函数进行说明(函数声明)。在主调函数中对被调函数作说明的目的是使编译系统知道被调函数返回值的类型,以便在主调函数中按此种类型对返回值作相应的处理。对被调函数的说明的一般格式为: 类型说明符 被调函数名(类型 形参,类型 形参…); 或为: 类型说明符 被调函数名(类型,类型…);   括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进行检错,以防止可能出现的错误。C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。 · 如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理。 · 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数再作说明而直接调用。例如函数add的定义放在main函数之前,因此可在main函数中省去对 add函数的函数说明int add(int a,int b)。 · 如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。 函数声明实例: char str(int a); main() { char c = str(65); ....... } char str(int a) { …… } 其中第一对str函数预先作了说明。 因此在以后各函数中无须对str和f函数再作说明就可直接调用。 · 无参函数的定义和调用: 定义格式: 类型说明符 函数名() { 类型说明 语句 }   说明:其中类型说明符和函数名称为函数头。类型说明符指明了本函数的类型,函数的类型实际上是函数返回值的类型。函数名是由用户定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少,{}中的内容称为函数体。在函数体中也有类型说明,这是对函数体内部所用到的变量的类型说明。在很多情况下都不要求无参函数有返回值, 此时函数类型符可以写为void。我们可以这样定义一个无参函数: 例:定义一个无参函数,显示一个消息 void ShowMsg() { printf ("ITJOB!\n"); }  这里,Hello 函数是一个无参函数,当被其它函数调用时,输出ITJOB!字符串。 调用格式: void main() { ShowMsg(); //调用ShowMsg函数 } · 有参函数的定义和调用 定义格式: 类型说明符 函数名(形式参数表) { 类型说明 语句 }   有参函数比无参函数多了形式参数表。在形参表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值。 形参既然是变量,当然必须给以类型说明。 例:定义一个函数, 用于求两个数中的大数 int add(int a,int b) { int ret ; ret = a + b; return ret; } 第一行说明add函数是一个整型函数,其返回的函数值是一个整数。形参为a,b。a,b的具体值是由主调函数在调用时传送过来的。在{}中的函数体内,定义了返回变量return ret,它表示把 ret 的结果返回给add函数的调用者。 调用格式: void main() { int c ; c = add(10,20); } 以上是带参函数的调用格式,其中10和20是实参(实际参数),实参可以是常数,变量或其它构造类型数据及表达式。 各实参之间用逗号分隔,调用函数的时候,会按顺序把实参传给形参,也就是把10传给a,20传给b。 形参和实参一定要匹配,也就是参数类型、个数要匹配,比如int add(int,int)表示实参应该要两个整数值,以下的调用都是错误的: add(10.0,20.0)、add(10,20,30) 如果函数作为另一个函数调用的实际参数出现(函数实参)。 这种情况是把该函数的返回值作为实参进行传送,要求该函数必须有返回值。例如: printf("%d",add(10,20)); 就是把 add 调用的返回值又作为printf函数的实参来使用的。 · 函数的参数 前面已经介绍过,函数的参数分为形参和实参两种。在本小节中,进一步介绍形参、实参的特点和两者的关系。形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。 形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。函数的形参和实参具有以下特点: · 形参变量只有在被调用时才分配内存单元,在调用结束时,立刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。 · 参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。 · 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生"类型不匹配"的错误。 · 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。 例:把字符转换为大写 void toUpper(char c ) { if( c >= 97 && c <= 123) c = c - 32; printf("ch=%c\n",c); } void main() { char c; printf("input char\n"); scanf("%c",&c); toUpper(c); printf("ch=%c\n",c); } 本程序中定义了一个函数toUpper,该函数的功能是把小写字母转换为大写。在主函数中输入c值,并作为实参,在调用时传送给toUpper函数的形参量c(注意,本例的形参变量和实参变量的标识符都为c,但这是两个不同的量,各自的作用域不同)。在主函数中用printf语句输出一次c值,这个c值是实参c的值。在函数toUpper中也用printf语句输出了一次c值,这个c值是形参最后取得的c。从运行情况看,输入c值为'd'。即实参c的值为'd'。把此值传给函数toUpper时,形参c的初值也为'd',在执行函数过程中,形参c的值变为'D'。 返回主函数之后,输出实参n的值仍为'd'。可见实参的值不随形参的变化而变化。 变量的作用域 在讨论函数的形参变量时曾经提到,形参变量只在被调用期间才分配内存单元,调用结束立即释放。这一点表明形参变量只有在函数内才是有效的,离开该函数就不能再使用了。这种变量有效性的范围称变量的作用域。不仅对于形参变量,C语言中所有的变量都有自己的作用域。变量说明的方式不同,其作用域也不同。C语言中的变量,按作用域范围可分为两种, 即局部变量和全局变量。 · 局部变量 局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。 例:局部变量 int f1(int a) /*函数f1*/ { int b,c; // a b c 是函数f1的局部变量 } void main() { int a,x; // main局部变量 f1(a); } 在函数f1内定义了三个变量,a为形参,b,c为一般变量。在 f1的范围内a,b,c有效,或者说a,b,c变量的作用域限于f1内。a,x的作用域限于main函数内。关于局部变量的作用域还要说明以下几点: · 函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其它函数中定义的变量。因为主函数也是一个函数,它与其它函数是平行关系。 · 形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。 · 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。比如上面f1和main中的变量a · 在复合语句中也可定义变量,其作用域只在复合语句范围内。 复合语句变量,见图。 本程序在main中定义了i,j,k三个变量,其中k未赋初值。 而在复合语句内又定义了一个变量k,并赋初值为8。应该注意这两个k不是同一个变量。在复合语句外由main定义的k起作用,而在复合语句内则由在复合语句内定义的k起作用。因此程序第4行的k为main所定义,其值应为5。第7行输出k值,该行在复合语句内,由复合语句内定义的k起作用,其初值为8,故输出值为8,第9行输出i,k值。i是在整个程序中有效的,第7行对i赋值为3,故以输出也为3。而第9行已在复合语句之外,输出的k应为main所定义的k,此k值由第4 行已获得为5,故输出也为5。 · 全局变量 全局变量也称为外部变量,它是在函数外部定义的变量。 它不属于哪一个函数,它属于一个源程序文件。其作用域是整个源程序。在函数中使用全局变量,一般应作全局变量说明。 只有在函数内经过说明的全局变量才能使用。全局变量的说明符为extern。 但在一个函数之前定义的全局变量,在该函数内使用可不再加以说明。 例:想想全局变量x,y作用域 和全局变量a,b作用域 int a,b; /*外部变量*/ void f1() /*函数f1*/ { } float x,y; /*外部变量*/ int fz() /*函数fz*/ { } main() /*主函数*/ { } 从上例可以看出a、b、x、y 都是在函数外部定义的外部变量,都是全局变量。但x,y 定义在函数f1之后,而在f1内又无对x,y的说明,所以它们在f1内无效。 a,b定义在源程序最前面,因此在f1,f2及main内不加说明也可使用。 [例]输入正方体的长宽高l,w,h。求体积及三个面x*y,x*z,y*z的面积。 int s1,s2,s3; int vs( int a,int b,int c) { int v; v=a*b*c; s1=a*b; s2=b*c; s3=a*c; return v; } void main() { int v,l,w,h; printf("\ninput length,width and height\n"); scanf("%d%d%d",&l,&w,&h); v=vs(l,w,h); printf("v=%d s1=%d s2=%d s3=%d\n",v,s1,s2,s3); } 本程序中定义了三个外部变量s1,s2,s3,用来存放三个面积,其作用域为整个程序。函数vs用来求正方体体积和三个面积,函数的返回值为体积v。由主函数完成长宽高的输入及结果输出。由于C语言规定函数返回值只有一个, 当需要增加函数的返回数据时,用外部变量是一种很好的方式。本例中,如不使用外部变量,在主函数中就不可能取得v,s1,s2,s3四个值。而采用了外部变量,在函数vs中求得的s1,s2,s3值在main 中仍然有效。因此外部变量是实现函数之间数据通讯的有效手段。对于全局变量还有以下几点说明: · 对于局部变量的定义和说明,可以不加区分。而对于外部变量则不然,外部变量的定义和外部变量的说明并不是一回事。外部变量定义必须在所有的函数之外,且只能定义一次。其一般形式为: [extern] 类型说明符 变量名,变量名 … 其中方括号内的extern可以省去不写。 例如: int a,b; 等效于: extern int a,b; 而外部变量说明出现在要使用该外部变量的各个函数内, 在整个程序内,可能出现多次,外部变量说明的一般形式为: extern 类型说明符 变量名,变量名,…;外部变量在定义时就已分配了内存单元,外部变量定义可以有初始值,外部变量说明不能再赋初始值, 只是表明在函数内要使用某外部变量。 · 外部变量可加强函数模块之间的数据联系,但是又使函数要依赖这些变量,因而使得函数的独立性降低。从模块化程序设计的观点来看这是不利的,因此在不必要时尽量不要使用全局变量。 · 在同一源文件中,允许全局变量和局部变量同名。在局部变量的作用域内,全局变量不起作用。 [例] int vs(int k,int w) { extern int h; int v; v = k*w*h; return v; } main() { extern int w,h; int k = 5; printf("v=%d", vs(k,w)); int k=3,w=4,h=5; } 本例程序中,外部变量在最后定义, 因此在前面函数中对要用的外部变量必须进行说明。外部变量l,w和vs函数的形参k,w同名。外部变量都赋了初始值,main函数中也对k作了初始化赋值。执行程序时,在printf语句中调用vs函数,实参l的值应为main中定义的l值,等于5,外部变量k在main内不起作用;实参w的值为外部变量w的值为4,进入vs后这两个值传送给形参k和w,在vs函数返回的v值是k,v,h的乘积,k,w是局部变量(分别为5和4),h是外部变量值(等于5),所以最后的结果就是100。 · 变量的存储类型 各种变量的作用域不同,就其本质来说是因变量的存储类型不同。所谓存储类型是指变量占用内存空间的方式,也称为存储方式。 变量的存储方式可分为"静态存储"和"动态存储"两种。 静态存储变量通常是在变量定义时就分定存储单元并一直保持不变,直至整个程序结束。动态存储变量是在程序执行过程中,使用它时才分配存储单元, 使用完毕立即释放。典型的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配,调用函数完毕立即释放。如果一个函数被多次调用,则反复地分配、释放形参变量的存储单元。从以上分析可知,静态存储变量是一直存在的,而动态存储变量则时而存在时而消失。我们又把这种由于变量存储方式不同而产生的特性称变量的生存期。生存期表示了变量存在的时间。生存期和作用域是从时间和空间这两个不同的角度来描述变量的特性,这两者既有联系,又有区别。一个变量究竟属于哪一种存储方式, 并不能仅从其作用域来判断,还应有明确的存储类型说明。 在C语言中,对变量的存储类型说明有以下四种: auto     自动变量 register   寄存器变量 extern     外部变量 static     静态变量 自动变量和寄存器变量属于动态存储方式,外部变量和静态变量属于静态存储方式。在介绍了变量的存储类型之后,可以知道对一个变量的说明不仅应说明其数据类型,还应说明其存储类型。因此变量说明的完整形式应为: 存储类型说明符 数据类型说明符 变量名,变量名…; 例如: static int a,b;           说明a,b为静态类型变量 auto char c1,c2;          说明c1,c2为自动字符变量 static int a[5]={1,2,3,4,5};    说明a为静整型数组 extern int x,y;           说明x,y为外部整型变量 下面分别介绍以上四种存储类型: · 自动变量的类型说明符为auto。 这种存储类型是C语言程序中使用最广泛的一种类型。C语言规定,函数内凡未加存储类型说明的变量均视为自动变量,也就是说自动变量可省去说明符auto。在前面各章的程序中所定义的变量凡未加存储类型说明符的都是自动变量。 例如: { int i,j,k; char c; } 等价于: { auto int i,j,k; auto char c; } 自动变量具有以下特点: 1) 自动变量的作用域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效。 例如: int kv(int a) { auto int x,y; { auto char c; } /*c的作用域*/ …… }/*a,x,y的作用域*/ 2) 自动变量属于动态存储方式,只有在使用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。因此函数调用结束之后,自动变量的值不能保留。在复合语句中定义的自动变量,在退出复合语句后也不能再使用,否则将引起错误。 例如:自动存储变量实例 void main() { auto int a; printf("\ninput a number:\n"); scanf("%d",&a); if(a>0) { auto int s,p; s=a+a; p=a*a; } printf("s=%d p=%d\n",s,p); } s,p是在复合语句内定义的自动变量,只能在该复合语句内有效。而程序的第9行却是退出复合语句之后用printf语句输出s,p的值,这显然会引起错误。 3) 由于自动变量的作用域和生存期都局限于定义它的个体内(函数或复合语句内), 因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。 [例] 自动变量同名的示例 void main() { auto int a,s=100,p=100; printf("\ninput a number:\n"); scanf("%d",&a); if(a>0) { auto int s,p; s=a+a; p=a*a; printf("s=%d p=%d\n",s,p); } printf("s=%d p=%d\n",s,p); } 本程序在main函数中和复合语句内两次定义了变量s,p为自动变量。按照C语言的规定,在复合语句内,应由复合语句中定义的s,p起作用,故s的值应为a+a,p的值为a*a。退出复合语句后的s,p 应为main所定义的s,p,其值在初始化时给定,均为100。从输出结果可以分析出两个s和两个p虽变量名相同,但却是两个不同的变量。 4) 对构造类型的自动变量如数组等,不可作初始化赋值。 · 外部变量的类型说明符为extern。 在前面介绍全局变量时已介绍过外部变量。这里再补充说明外部变量的几个特点: · 外部变量和全局变量是对同一类变量的两种不同角度的提法。全局变是是从它的作用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。 当一个源程序由若干个源文件组成时,在一个源文件中定义的外部变量在其它的源文件中也有效。 例如:有一个源程序由源文件F1.C和F2.C组成 F1.C int a,b; /*外部变量定义*/ char c; /*外部变量定义*/ main() { …… } F2.C extern int a,b; /*外部变量说明*/ extern char c; /*外部变量说明*/ func (int x,y) { …… } 在F1.C和F2.C两个文件中都要使用a,b,c三个变量。在F1.C文件中把a,b,c都定义为外部变量。在F2.C文件中用extern把三个变量说明为外部变量,表示这些变量已在其它文件中定义,并把这些变量的类型和变量名,编译系统不再为它们分配内存空间。对构造类型的外部变量,如数组等可以在说明时作初始化赋值,若不赋初值,则系统自动定义它们的初值为0。 · 静态变量 静态变量的类型说明符是static。静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量,例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。 对于自动变量,前面已经介绍它属于动态存储方式。但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。 由此看来,一个变量可由static进行再说明,并改变其原有的存储方式。 · 静态局部变量 在局部变量的说明前再加上static说明符就构成静态局部变量。 例如: static int a,b; static float array[5]={1,2,3,4,5}; 静态局部变量属于静态存储方式,它具有以下特点: <1> 静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序。 <2> 静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。 <3> 允许对构造类静态局部量赋初值。在数组一章中,介绍数组初始化时已作过说明。若未赋以初值,则由系统自动赋以0值。 <4> 对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。 根据静态局部变量的特点, 可以看出它是一种生存期为整个源程序的量。虽然离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。 因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。 · 静态全局变量 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。 · 寄存器变量 上述各类变量都存放在存储器内, 因此当对一个变量频繁读写时,必须要反复访问内存储器,从而花费大量的存取时间。 为此,C语言提供了另一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,这样可提高效率。寄存器变量的说明符是register。 对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。 [例]:求 1 到 200 的和 main() { register i,s=0; for(i=1;i<=200;i++) s=s+i; printf("s=%d\n",s); } 本程序循环200次,i和s都将频繁使用,因此可定义为寄存器变量。 对寄存器变量还要说明以下几点: 1) 只有局部自动变量和形式参数才可以定义为寄存器变量。因为寄存器变量属于动态存储方式。凡需要采用静态存储方式的量不能定义为寄存器变量。 2) 在Turbo C,MS C等微机上使用的C语言中,实际上是把寄存器变量当成自动变量处理的。因此速度并不能提高。而在程序中允许使用寄存器变量只是为了与 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 C保持一致。 3) 即使能真正使用寄存器变量的机器,由于CPU 中寄存器的个数是有限的,因此使用寄存器变量的个数也是有限的。 · 函数的默认参数 · 内联函数 · 内部函数和外部函数 函数一旦定义后就可被其它函数调用。 但当一个源程序由多个源文件组成时,在一个源文件中定义的函数能否被其它源文件中的函数调用呢?为此,C语言又把函数分为两类: · 内部函数 如果在一个源文件中定义的函数只能被本文件中的函数调用,而不能被同一源程序其它文件中的函数调用, 这种函数称为内部函数。定义内部函数的一般形式是: static 类型说明符 函数名(形参表) 例如: static int f(int a,int b) 内部函数也称为静态函数。但此处静态static 的含义已不是指存储方式,而是指对函数的调用范围只局限于本文件。 因此在不同的源文件中定义同名的静态函数不会引起混淆。 · 外部函数 外部函数在整个源程序中都有效,其定义的一般形式为: extern 类型说明符 函数名(形参表) 例如: extern int f(int a,int b) 如在函数定义中没有说明extern或static则隐含为extern。在一个源文件的函数中调用其它源文件中定义的外部函数时,应 用extern说明被调函数为外部函数。 例如:外部函数定义 F1.C (源文件一) main() { extern int f1(int i); /*外部函数说明,表示f1函 数在其它源文件中*/ } F2.C (源文件二) extern int f1(int i); /*外部函数定义*/ { } 内容总结 根据不同的分类标准,可以将函数进行分类: · 库函数:由C系统提供的函数; · 用户定义函数:由用户自己定义的函数; · 有返回值的函数向调用者返回函数值,应说明函数类型( 即返回值的类型 ); · 无返回值的函数:不返回函数值,说明为空(void)类型; · 有参函数:主调函数向被调函数传送数据; · 无参函数:主调函数与被调函数间无数据传送; · 内部函数:只能在本源文件中使用的函数; · 外部函数:可在整个源程序中使用的函数。 函数定义的一般形式 类型说明符 函数名([形参表]) 方括号内为可选项。函数调用的一般形式 函数名([实参表])。函数的参数分为形参和实参两种,形参出现在函数定义中,实参出现在函数调用中,发生函数调用时,将把实参的值传送给形参。函数的值是指函数的返回值,它是在函数中由return语句返回的。变量的作用域是指变量在程序中的有效范围, 分为局部变量和全局变量。变量的生存期, 自动变量 auto、register变量,extern 变量,static 变量。内部函数:在一个源文件中定义的函数只能被本文件中的函数调用,而不能被同一源程序其它文件中的函数调用, 这种函数称为内部函数。定义内部函数的一般形式是: static 类型说明符 函数名(形参表)和外部函数:在整个源程序中都有效,其定义的一般形式为: extern 类型说明符 函数名(形参表) 独立实践 · 实践1 题目:写一个函数,判断两个数之间有多少个素数,并输出所有素数 · 实践2 题目:利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来 · 实践3 题目:使用静态局部变量计算一个整数的阶乘(不要使用递归),理解静态局部变量的记忆功能。 · 实践4 题目:编写四个Swap()函数(void Swap1(int a,int b),void Swap2(int *,int *),void Swap3(int &a,int &b),int swap4(int *,int *)),看看他们能否实现两个数的交换,如果不能请说明理由。 · 实践5 题目:编写一个函数,以数组为形式参数,实现所有数组元素的求和并输出,在函数定义的时候在函数体中使用sizeof运算符计算该形参数组的大小。理解数组作为形参的特殊性。 14 13
本文档为【第三章 函数和变量存储】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_225887
暂无简介~
格式:doc
大小:150KB
软件:Word
页数:0
分类:互联网
上传时间:2018-09-09
浏览量:13