刘汝佳/算法竞赛入门经典第四章函数和递归

函数

  1. main函数也是有返回值的,而且到目前为止,我们总是让它返回0.有人会说0在计算机里不是error吗,此处的return 0显然不是.我们知道在自定义的函数里return是返回给调用这个函数的东西,一般会将它赋给一个变量.那main函数这里的return给了谁呢?显然能调用主函数的东西并不一般,如操作系统,IDE,调试器,甚至自动评测系统.这个0代表的是程序的正常结束. 
  2. 程序4-3 孪生素数(改进版)
  3. #include <stdio.h>
  4. #include<math.h>
  5. #include<assert.h>
  6. int is_prime(int x)
  7. {
  8.     int i,m;
  9.     assert(x>=0);//当条件不成立时,程序将异常终止
  10.     if(x==1) return 0;
  11.     m=floor(sqrt(x)+0.5);//floor向下取整
  12.     for(i=2;i<=m;i++)
  13.     {
  14.         if(x%i==0) return 0;
  15.     }
  16.     return 1;
  17. }
  18. int main()
  19. {
  20.     int i,m;
  21.     scanf("%d",&m);
  22.     for(i=m-2;i>=3;i--)//i=m-2,孪生
  23.     {
  24.         if(is_prime(i)&&is_prime(i+2))
  25.         {
  26.             printf("%d %d\n",i,i+2);
  27.             break;//跳出循环
  28.         }
  29.     }
  30.     return 0;
  31. }
  32. 调用栈
  33. 调用栈描述的是函数之间的调用关系.它是由多个栈帧组成,每个栈帧对应一个未运行完的函数.栈帧中保存了该函数的返回地址和局部变量,因而不仅能在执行完毕后找到正确的返回地址,还能很自然的保证了不同函数间的局部变量互不相干----因为不同函数对应着不同的栈帧.
  34. 例如两个函数都有着int型的变量a,b,但是因为栈帧不同,所以改变其中一个函数的变量值,另一个不会发生改变.著名的swap函数(即交换两个变量的值)即适用于此例.谭浩强在c语言这本书中把这种现象表述为:"形参的改变不能影响实参".
  35. 大家都已经知道解决这个问题的有效办法是使用指针.在swap程序里,a,b都是局部变量,在程序执行完毕后就不存在了,但是a和b里面保存的地址却依然有效----它们是main函数中的局部变量a,b的地址.在main函数执行完毕之前,这两个地址依然有效.并且分别指向main函数的局部变量a和b.程序交换的是*a,*b,也就是main函数里的局部变量a,b

递归 

  1. 定义:就是"自己用到自己".,
  2. 如果在递归调用初期查看调用栈,你会发现每次递归调用都会多一个栈帧----和普通的函数调用没有什么不同.确实如此,如果使用了调用栈,c语言自然支持了递归.在c语言的函数中,调用自己和调用其他函数并没有任何区别,都是建立新栈帧,传递参数并修改"当前代码行".在函数执行完毕后删除栈帧,处理返回值并修改"当前代码行".
  3. 栈溢出:每次递归调用都需要往调用栈里增加一个栈帧,久而久之就越界了.那么栈的空间到底有多大呢?这和操作系统有关.linux为32MB,windows为16MB.
  4. 现在再回过头来理解把较大的数组放在main函数外.是因为局部变量也是放在堆栈段的.栈溢出不见得一定是递归调用太多(例子见我的博客---"什么是数据结构",里面的关于空间使用),也可能是局部变量太大.
  5.                                                                                                                       全书第一部分语言篇到此结束;第二部分算法篇将在分类--数据结构与算法完成后开始----未完持续-----

猜你喜欢

转载自blog.csdn.net/a22222259/article/details/87930714
今日推荐