C语言
[toc]
5.函数概述与引用
一个c语言程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对于较大的程序, 一般不希望把所有的内容全放在一个文件中, 而是分别放在若干个源文件中, 由若干个源程序组成一个c程序。
一个源程序文件由一个或多个函数以及其他有关内容(如指令, 数据声明与定义等)组成。
1 一个源程序文件是一个编译单位, 在程序编译时是以源程序文件为单位进行编译,而不是以函数为单位进行编译。
c程序的执行是从main函数开始的
所有函数都是平行的, 也就是说在定义时是分别进行的, 互相独立的。函数间能互相调用,但是不能调用main函数, main函数是由操作系统调用的。
在定义函数时要指定函数的类型
使用库函数时应该在本文件开头用#include指令将调用有关库函数时所需要用到的信息”包含“到本文件中来。
函数的声明和定义只差一个分号;
5.1函数形式
(1).有参数函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> int max (int x, int y) { if (x > y){ return (x); } else { return (y); } } int main () { int max (int x, int y) ; int a, b, c; printf ("put in int:" ); scanf ("%d, %d, " ,&a, &b); c = max(a, b); printf ("max is %d\n" , c); return 0 ; }
(2.1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> int max4 (int a, int b, int c, int d) { int max2 (int , int ) ; int m; m= max2(a, b); m = max2(m, c); m= max2(m,d); return (m); } int max2 (int a, int b) { if (a>=b) return a; else return b; } int main () { int max4 (int , int , int , int ) ; int a, b, c,d,max; printf ("please enter 4 interger numbers" ); scanf ("%d%d%d%d" , &a,&b,&c,&d); max = max4(a, b, c, d); printf ("max=%d\n" , max); }
(2).无参数函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # include <stdio.h> void print_star () { printf ("**********\n" ); } void print_message () { printf ("How do you do!\n" ); } int main () { void print_star () ; void print_message () ; print_star(); print_message(); return 0 ; }
5.2函数的递归调用
在调用函数的过程中直接或间接地调用该函数本身
函数不需要返回值时,则不需要return语句,此时函数的类型应该为void类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # include <stdio.h> int age (int n) { int c=0 ; if (n==1 ) c =10 ; else c = age(n -1 )+2 ; return (c); } int main () { int age (int ) ; printf ("NO.5,age:%d\n" , age(5 )); return 0 ; }
(2)求递归n!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # include <stdio.h> int fac (int n ) { int f; if (n<0 ) printf ("n<0,data error!" ); else if (n==0 ||n==1 ) f=1 ; else f=fac(n-1 )*n; return (f); } int main () { int fac (int n) ; int n; int y; printf ("input an integer number:" ); scanf ("%d" ,&n); y = fac(n); printf ("%d!=%d\n" ,n,y); return 0 ; }
(3)汉诺塔
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 # include <stdio.h> void move (char x, char y) { printf ("%c-->%c\n" , x, y); } void hanoi (int n, char one, char two, char three) { void move (char x, char y) ; if (n==1 ) move(one, three); else { hanoi(n-1 ,one,three,two); move(one,three); hanoi(n-1 ,two,one,three); } } int main () { void hanoi (int n, char one, char two, char three) ; int m; printf ("input the diskes:" ); scanf ("%d" ,&m); printf ("the step to move %d diskes\n" ,m); hanoi(m,'A' ,'B' ,'C' ); return 0 ; }
5.3数组作为函数参数
数组元素可以用作函数实参,但是不可用作形参(形参是在被调用时临时分配储存单元的)
数据传递是从实参到形参,单向传递
数组名可做实参和形参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 # include <stdio.h> int max (int x,int y) { return (x>y? x:y); } int main () { int max (int x,int y) ; int a[10 ],m,n,i; printf ("enter 10 integer number:" ); for (i=0 ;i<10 ;i++) scanf ("%d" , &a[i]); printf ("\n" ); for (i=1 ,m=a[0 ],n=0 ;i<10 ;i++) { if (max(m,a[i]>m)){ m= max(m,a[i]); n=i; } } printf ("The largest number is%d\nit is the %dth number.\n" ,m,n+1 ); return 0 ; }
(2)一维数组score内放十个数据,求平均值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> float average (float array [10 ]) { int i; float aver,sum=array [0 ]; for (i=1 ;i<10 ;i++) sum = sum+array [i]; aver=sum/10 ; return (aver); } int main () { float average (float array [10 ]) ; float score[10 ],aver; int i; printf ("input 10 scores:\n" ); for (i=0 ;i<10 ;i++) scanf ("%f" ,&score[i]); printf ("\n" ); aver = average(score); printf ("average score is %5.2f\n" ,aver); return 0 ; }
(3)3x4矩阵,求所有元素中的最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int main () { int max_value (int array [][4 ]) ; int a[3 ][4 ]={{1 ,3 ,4 ,5 },{4 ,8 ,11 ,6 },{13 ,53 ,3 ,15 }}; printf ("max value is %d\n" , max_value(a)); return 0 ; } int max_value (int array [][4 ]) { int i,j,max; max=array [0 ][0 ]; for (i=0 ;i<3 ;i++) for (j=0 ;j<4 ;j++) if (array [i][j]>max) max=array [i][j]; return max; }
5.4变量储存方式和生存期
从变量的作用域来看:变量可分为全局变量和局部变量
从另一个角度来看,变量值存在的时间来观察——生存期
1.储存空间分为:
(1)程序区
(2)静态存储区:
在程序开始执行时给全局变量分配储存区,程序执行完毕就释放,
对于局部变量来说:它使变量由动态储存方式改变为静态储存方式
对于全局变量来说:使得变量局部化(仅限于本文件中)。
(3)动态储存区:
以下这些数据,在函数的调用时,分配动态储存空间,即函数结束时释放这些空间。
函数形式参数,在调用函数时给形参分配储存空间
函数中定义的没有用关键字static声明的变量,即自动变量
函数调用时的现场保护和返回地址
1 每个函数中的局部变量的生存期并不等于整个程序的执行周期,他只是程序执行周期的一个部分
2.数据类型和储存类型
(1)局部变量的储存类别
自动变量(auto变量):函数中不专门声明为static储存类别,都是动态地分配储存空间
静态局部变量(static):局部变量的值在调用结束后不消失二继续保持原值,即其占用的储存单元不释放。多次调用,相当于会覆盖掉自身局部变量的值。
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> int main () { int f (int ) ; int a=2 ,i; for (i=0 ;i<3 ;i++){ printf ("%d\n" ,f(a)); printf ("%d\n" ,f(a)); printf ("%d\n" ,f(a)); return 0 ; } } int f (int a) { auto int b=0 ; static int c=3 ; b=b+1 ; c=c+1 ; return a+b+c; }
求阶乘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> int main () { int fac (int n) ; int i; for (i=1 ;i<=5 ;i++){ printf ("%d!=%d\n" ,i,fac(i)); } return 0 ; } int fac (int n) { static int f=1 ; f=f*n; return f; }
3.寄存器变量(register变量)
使用频繁的变量将放在寄存器中,读取寄存器的速度要大于内存
1 但优化的编译系统能够识别使用频繁的变量,从而自动将这些变量放在寄存器中。
(2)全局变量的存储类别:
存放在静态存储中,生存期是固定的,存在与程序的整个运行过程,,但作用域是从什么位置到那个位置。有以下几种情况:
1.在一个文件内扩展外部变量的作用域
如果外部变量不在文件的开头定义,则其有效的作用范围只限定于定义处到文件结束。在定义点之前的函数不能引用该2外部变量。如果要用,则在引用之前用关键字extern对改变量作“外部变量声明”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int main () { int max () ; extern int A,B,C; printf ("input number:" ); scanf ("%d%d%d" ,&A,&B,&C); printf ("max is %d\n" ,max()); return 0 ; } int A,B,C;int max () { int m; m=A>B?A:B; if (C>m)m=C; return m; }
提倡将外部变量的定义放在引用它的函数之前。
2.将外部变量的作用域扩展到其他文件
一个c程序可以由一个或多个源程序文件组成。当两个或以上的文件都要用到同一个外部变量时,不能分别在两个文件中各自定义一个变量,这时需要使用extern对其做外部声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> int A;int main () { int power (int ) ; int b=3 ,c,d,m; printf ("enter the number a and its power m:\n" ); scanf ("%d,%d" ,&A,&m); c= A*b; printf ("%d*%d=%d\n" ,A,b,c); d= power(m); printf ("%d**%d=%d\n" ,A,m,d); return 0 ; } #include <stdio.h> extern A;int power (int n) { int i,y=1 ; for (i=1 ;i<=n;i++){ y*=A; } return y; }
3.将外部变量的作用域限制在文本中
使用static则可以将外部变量的作用域限制在本文件内。
这种只能用于本文件的外部变量称为静态外部变量。
小结:
1.声明变量时是在定义变量的基础上加上关键字,而不是单独使用。
2.对于一个数据的定义,需要指定两种属性:数据类型和存储类型
3.对于变量大的属性可以从两个方面:一是变量的作用域,二是变量存在时间的长短。前者从空间的角度,后者从时间的角度。
5.5关于变量的声明和定义
将建立储存空间的声明称为定义
把不需要建立储存空间的声明称为声明
函数中除了用extern声明的以外都是定义
5.6外部函数和内部函数
1.内部函数:
如果一个函数只能被本文件中其他函数所调用,它称为内部函数
static 类型名 函数名(形参表)
2.外部函数:
如果在定义函数时,在函数首部的最左端加关键字extern,则此函数是外部函数,可供其他函数调用。
但是c语言规定,如果在定义函数是省略extern,则默认为外部函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> int main () { extern void enter (char str[]) ; extern void delete (char str[],char ch) ; extern void print (char str[]) ; char c,str[50 ]; enter(str); scanf ("%c" ,&c); delete(str,c); print(str); return 0 ; } #include <stdio.h> void enter (char str[50 ]) { gets(str); } #include <stdio.h> void delete (char str[],char ch) { int i,j; for (i=j=0 ;str[i]!='\0' ;i++) if (str[i]!=ch) str[j++]=str[i]; str[j]='\0' ; } #include <stdio.h> void print (char str[]) { printf ("%s\n" ,str); }
6.指针
6.1数据如何储存,读取
存取一个数据,除了需要位置信息外,还需要该数据的类型信息。
即C语言中的地址包括位置信息和它所指向的数据的类型,或者说带:类型的地址。如:&a:“整形变量a的地址”
直接访问:直接按变量名进行访问的方法.
间接访问:将变量i的地址存放在另一个变量中,然后通过该变量来找到变量i的地址。
6.2指针变量
存放地址的是指针变量
*如何定义指针变量:类型名 指针变量名
*表示该变量是指针变量。
在赋值时,值是给指针变量名的,而不是,*指针变量名
例:
1 2 3 4 int a,b;int *point_1 = &a,*point_2 = &b;
1 2 3 4 5 6 int a,b;int *point_1,*point_2;point_1 = &a; point_2 = &b;
指针变量中只能存放地址
6.2.1引用指针变量
引用指针变量的值:printf(“%o”,p);
引用指针变量指向的变量:如果已经执行“p=&a;”,即变量指针p指向了整型变量a
& 取地址运算符。
*指针运算符,星号p代表指针变量p指向的对象;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> int main () { int *p1,*p2,*p,a,b; printf ("input 2 number:" ); scanf ("%d%d" ,&a,&b); p1 =&a; p2=&b; if (a<b) {p=p1;p1=p2;p2=p;} printf ("a=%d,b=%d\n" ,a,b); printf ("max=%d,min=%d\n" ,*p1,*p2); return 0 ; }
6.2.2指针变量作为函数参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <stdio.h> int main () { void swap (int *p1,int *p2) ; int a,b; int *point1,*point2; printf ("input a and b:" ); scanf ("%d%d" ,&a,&b); point1=&a; point2=&b; printf ("%o\n%o\n" ,point1,point2); if (a<b) swap(point1,point2); printf ("%d%d" ,a,b); printf ("%o\n%o\n" ,point1,point2); printf ("max=%d,min=%d\n" ,a,b); return 0 ; } void swap (int *p1,int *p2) { int temp; temp=*p1; *p1=*p2; *p2=temp; }
6.3通过指针引用数组
数组中每个元素都需要在内存中战用储存单元。
所谓数组元素的指针就是数组元素的地址。
1 2 3 4 5 int a[10 ]={10 个值};int *p;p=&a[0 ];
6.3.1指针的运算
在指针已指向一个数组元素时,可以做以下运算
加一个整数,(用+或者+=),如p+1;
减一个整数,(-或-=),如p-1;
自加运算,p++,++p;
自减运算,p–,–p;
两个指针相减,如p1-p2(只有都指向同一数组时才有意义)
通过数组名计算数组元素的地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { int a[10 ]; int i; printf ("input 10 int number:\n" ); for (i=0 ;i<10 ;i++) scanf ("%d" ,&a[i]); for (i=0 ;i<10 ;i++) printf ("%d" ,*(a+i)); printf ("\n" ); return 0 ; }
用指针变量指向数组元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> int main () { int a[10 ]; int *p,i; printf ("input 10 int number:\n" ); for (i=0 ;i<10 ;i++) scanf ("%d" ,&a[i]); for (p=a;p<(a+10 );p++) printf ("%d" ,*p); printf ("\n" ); return 0 ; }
错例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { int i,*p,a[5 ]; p=a; printf ("input 5 number:" ); for (i=0 ;i<5 ;i++) scanf ("%d" ,p++); for (i = 0 ; i <5 ;i++,p++) printf ("%d" ,*p); printf ("\n" ); return 0 ; }
6.3.2数组名作函数参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <stdio.h> int main () { void inv (int *,int n) ; int i,a[10 ]={1 ,3 ,4 ,5 ,1 ,5 ,7 ,8 ,4 ,2 }; printf ("the original array:\n" ); for (i=0 ;i<10 ;i++) printf ("%d" ,a[i]); printf ("\n" ); inv(a,10 ); printf ("the array has been:\n" ); for (i=0 ;i<10 ;i++){ printf ("%d" ,a[i]); } printf ("\n" ); return 0 ; } void inv (int *x,int n) { int *p,temp,*i,*j,m=(n-1 )/2 ; i=x; j=x+n-1 ; p=x+m; for (;i<=p;i++,j--) { temp=*i;*i=*j;*j=temp; } return ; }