C/C++ 第九讲 函数(续) 9.1 返回指针值的函数
例:编一函数,将这字符串中ASCII码最大的字符的地址返回,主程序中输出最大数之后的所有数。
分析:
如何定义函数的类型?
“将这字符串中ASCII码最大的字符的地址返回”,函数应为指针类型。
char *getmax(char s[])
如何表示字符串中ASCII码最大的字符的地址?
用该数组元素地址 &s[imax]
或s+imax
表示,imax:该字符在数组中的位置。
e.g:
1 2 3 4 5 6 7 8 9 10 11 char *getmax (char s[]) { int i=1 ,imax=0 ; while (s[i]!='\0' ) { if (s[i]>s[imax]) imax=i; i++; } return s+imax; }
调用:
1 2 3 char *max; max=getmax (s); puts (max);
9.2 作用域与存储类别 作用域与生存期的概念
作用域(可见性):在何范围内可被访问;
生存期:在什么 时间内存在。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include "iostream" using namespace std;int digit (long x) { int k=0 ; while (x!=0 ); return k; } int main () { long x; cin>>x; cout<<digit (x)<<endl; system ("pause" ); return 0 ; }
根据作用域和生存期,变量可分为:
存储类型:
自动局部变量
存储类型auto,可缺省
作用域:定义点开始到所在的分程序结束。
生存期:所在分程序执行期间。
开始执行分程序就生成,执行结束就消亡。
初始化:缺省值为随机值。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include "iostream" using namespace std;int f (int x) { int k=0 ; while (x!=0 ); return k; } int main () { long x; cin>>x; cout<<digit (x)<<endl; system ("pause" ); return 0 ; }
自动局部变量示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include "iostream" using namespace std;int f (int x) { x++; int k=5 ; k++; return x+k; } int main () { int k=2 ; cout<<f (k)<<endl; cout<<f (k)<<endl; system ("pause" ); return 0 ; }
问题:
答:不会冲突。不同的函数内可使用相同名称的自动局部变量,它们占用不同的存储单元 ,只能在各自的函数内被使用,彼此互不干扰。
main函数中两次调用f函数,第二次调用时,f函数中的x,k和第一次调用时使用相同的内存单元吗?
答:若一个函数被多次调用,每一次函数调用时,系统都会为自动局部变量重新分配存储单元,并重新初始化。函数调用结束后,释放为自动局部变量分配的存储单元,函数中自动局部变量的值不会带到下一次调用中 。
静态局部变量
存储类别static
作用域:定义点开始到所在的分程序结束。
生存期:程序的整个执行周期。
初始化:可初始化,缺省值为0或’\0’
静态局部变量VS自动局部变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void test () { int i=0 ; static int j=0 ; i++;j++; cout<<"i=" <<i<<"j=" <<j<<endl; } int main () { for (int i=0 ;i<2 ;i++) test (); system ("pause" ); return 0 ; }
自动局部变量i,每次调用函数都重新为他分配存储单元并初始化。
静态局部变量j,只在第一次调用函数时分配存储单元并初始化。
静态局部变量特点:
只在第一次调用函数时为静态局部变量分配存储空间,函数调用结束不会释放为静态局部变量分配新的存储空间。
静态局部变量只初始化一次
若一个函数被调用多次,对静态局部变量而言,前一次调用的结果会带到下一次去。
问:
第一次调用test结束,返回main函数后,j的存储空间没有释放,在main函数能访问j吗?
答:在一个分程序中定义的静态局部变量,在其他分程序中,是生存期,不是作用域,不可访问。
全局变量
作用域:定义点开始到所在的文件结束。
生存期:程序的整个执行周期。
初始化:可初始化,缺省值为0或’\0’
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include "iostream" using namespace std;int m=10 ;void f1 (int n) { n=2 *n;m=m/3 ; } int n; void f2 () {n=5 ;m++;++;}int main () { int n=2 ; f1 (n);f2 (); cout<<m<<" " <<n<<endl; system ("pause" ); return 0 ; }
注意:
当全局变量与局部变量同名且作用域有重叠时,在局部变量的作用域内, 起作用的是局部变量 ,而全局变量被“屏蔽”掉。
全局变量可在多个函数内使用,前一次的计算结果会带到下一次使用中。
扩展全局变量的作用域
全局变量的作用域:定义点开始到所在的文件结束。
可用extern关键字 扩展全局变量作用域。
扩展到定义点以前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> using namespace std;void fun () { cout<<i; } int i=5 ;int main () { int j=20 ; cout<<j; fun (); system ("pause" ); return 0 ; }
作用域横向扩展
1个C/C++项目可包含多个源文件
在一个源文件中要引用另一个源文件中定义的全局变量,使用前须用extern声明符 对其进行扩展
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int max1,min1;void maxmin (int x[],int n) { max1=x[0 ];min1=x[0 ]; for (int i=0 ;i<n;i++) { if (x[i]>max1)max1=x[i]; if (x[i]<min1)min1=x[i]; } } #include …… extern int max1,min1;int main () { int a[10 ]={11 ,2 ,3 ,-4 ,5 ,6 ,7 ,8 ,0 ,20 }; maxmin (a,10 ); cout<<max1<<" " <<min1<<endl; system ("pause" ); return 0 ; }
9.3 递归函数 (考试只考概念,不考编程) 递归的概念 用自身的结构描述自身
例:递归的阶乘定义
n!=n*(n-1)!1
(n>0)
递归反映问题分解的思维。
递归函数 函数在函数体内直接或间接地调用自身,称递归函数。
例1:求n!
思路:达到终结条件,直接求解;未达终结条件,递归调用。
1 2 3 4 5 6 7 8 9 10 11 long fac (int n) { if (n==0 ) return 1 ; return (n*fac (n-1 )); } int main () { cout<<fac (3 )<<endl; system ("pause" ); return 0 ; }
例2:计算斐波那契数列
f(n)=f(n-1)+f(n-2)
1 2 3 4 5 6 7 int fib (int n) { if (n==0 n==1 ) return 1 ; else return (fib (n-1 )+fib (n-2 )); }
注意递归函数一定要有终结条件
递归与迭代 任何用递归解决的问题都可以用迭代非递归解决。
例1:求n!
1 2 3 s=1 ; for (i=1 ;i<=n;i++) s=s*i;
迭代算法效率高。
根据问题特征决定用迭代还是递归
递归使用 例:二分法查找 终结条件:
1 2 3 4 5 6 7 8 9 10 11 int Binary_Search (int low,int high,int key) { if (low>high) return -1 ; if (key==a[mid]) return mid; else if (key<a[mid]) return Binary_Search (low,mid-1 ); else return Binary_Search (mid+1 ,high); }
例:进制转换 1 2 3 4 5 6 7 8 9 void convert (int m,int n) { char b[17 ]="0123456789ABCDEF" ; if (m!=0 ) { convert (m/r,r); cout<<b[m%r]; } }
作业 1 编写递归函数int sum(int a[],int n),其功能是求长度为n的数组的累加和,在主函数中随机产生10个两位数,调用sum函数,求这10个数的和。
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 37 38 39 40 41 #include "iostream" #define N 256 #include <time.h> using namespace std;int sum1 (int a[], int n) { int sos=0 ; for (int i = 0 ; i < n; i++) sos += a[i]; return sos; } int sum2 (int a[], int n) { int sos (0 ) ; if (n > 0 ) sos = a[n - 1 ] + sum2 (a, n - 1 ); if (n == 0 ) return sos; } int main () { int n,i,s[N],sos1,sos2; for (i = 0 ; i < 10 ; i++) { s[i] = 10 + rand () % 89 ; } for (i = 0 ; i < 10 ; i++) { cout << s[i] << ' ' ; } cout << endl; sos1 = sum1 (s, 10 ); sos2 = sum2 (s, 10 ); cout << "10个数迭代求得之和为:" << sos1 << endl; cout << "10个数递归求得之和为:" << sos2 << endl; system ("pause" ); return 0 ; }
2 编写函数get_max,其功能是将字符串s中最大字符的地址返回,再编写一个主函数,调用该函数,将字符串s中从最大字符开始的子串中小写字母转换成大写字母,然后输出新字符串s。例如,假设s的内容为“qwertyou”,则从最大字符’y’开始的子串为“you”,处理后的s为“qwertYOU”。
函数形式为:char *get_max(char s[])
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 #include "iostream" #define N 256 using namespace std;char * get_max (char s[]) { int imax=0 ; for (int i=0 ;s[i]!='\0' ; i++) { if (s[i] > s[imax]) imax = i; } return &s[imax]; } int main () { int n,i; char * imax; char a[N]; gets_s (a); imax = get_max (a); for (i = 0 ;*(imax+i)!='\0' ; i++) *(imax + i) -= 32 ; puts (imax); system ("pause" ); return 0 ; }
类似的课上例:
【例5.9】search函数的功能是在一字符串中查找某一指定的字符,若找到,则返回字符串中这个字符的地址,否则返回NULL,主函数调用search函数,并输出查找到的那个字符后的子串。
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 #include <iostream> using namespace std;char *search (char s[],char ch) { int i=0 ; while ( ) if (s[i]!=ch) i++; else ; return NULL ; } int main () { char s[100 ],ch,*p; gets (s); cin>>ch; ; if (p!=NULL ) cout<<p<<endl; else cout<<"not found\n" ; system ("pause" ); return 0 ; }