C语言回顾(五、函数,递归,Hanoi汉诺塔,整数转字符串)——iOS开发基础
2015-06-21 15:27
429 查看
说明:
在学习UI高级知识之前,将利用最近十来天的时间回顾一下C语言,主要按照《C程序设计(谭浩强版)》来回顾。
整理一些知识点(不是细节,知识个人觉得较重要或易忘的)以及挑一些课后题目或经典习题编写代码练习。
第7章 用函数实现模块化程序设计
1、模块化程序设计思想!要善于利用函数,减少重复编写程序段的工作量,实现模块化!
2、函数调用过程:以下列程序返回大值为例说明
output:
(1)定义函数指定形参未调用时,不占内存。只有发生调用时,函数maxNum的形参被临时分配内存单元;
(2)将实参对应的值传递给形参;x得到值2,y得到值3;
(3)执行函数时,由于形参已有值,因此利用形参进行运算;
(4)通过return将函数值带回到主调函数;
(5)调用结束,形参单元被释放。(形参值改变不会改变实参值,两者是两个不同的存储单元)
注意:形参与实参的值传递是单向传递,只能实参传形参。
3、函数类型决定返回值类型。如果函数值的类型和return的值类型不一致,则以函数类型为准。对于数值类型数据,可以自动进行类型转换。空类型函数不得出现return。
4、声明:如果自定义函数位置在调用它的函数后面(同一个文件中),应该在主调函数中对被调用的函数作声明。也可以在所有函数之前,#include之后进行声明,那么在各函数中就不用再作声明了。
声明形式:在2的程序中已有说明。
作用:把函数名、形参的个数和类型等信息告知编译系统,以便遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。
5、嵌套调用:较简单,不复述
递归调用:调用函数的过程中又直接或间接地调用该函数本身
练习部分有阶乘和Hanoi塔问题
6、数组作为形参的时候,是作为指针变量!!!
以下三种写法是等效的:a的作用是传递a[0]的地址,首地址!!!
[thead]
(1)第一种写法:虽然定义函数时,声明数组的大小为10,但实际上,指定其大小不起任何作用,因为C语言编译系统并不检查形参数组大小,只是将实参数组的首元素的地址传给形参数组名。
(2)用数组元素作实参时,向形参传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址。
(3)多维数组做实参和形参,可以指定每一维的大小,也可以省略第1维的大小说明,但是第2维以及其他高维的大小说明不能省!因为多维数组在内存中按行存放,必须指定列数。
7、全局变量和局部变量
[thead]
(1)全局变量定义在函数外部,增加函数间数据练习的渠道,一般全局变量的第一个字母用大写表示区分于局部变量,习惯非规定。局部变量定义在函数内部
(2)静态局部变量:初始化只作用一次
(3)生存周期:从开始申请内存到释放内存
(4)在不必要的时候不要使用全局变量:整个过程都占用存储单元;降低了函数的通用性和可靠性,当函数移到另一个文件还要考虑移植外部变量;降低程序的清晰性。要限制全局变量的使用!
(5)同名问题:同一个源文件中,全局变量与局部变量同名,那么在局部变量的作用范围内,局部变量有效,全局变量被“屏蔽”,不起作用。
example说明同名问题:
output:
8、变量存储类型
[thead]
C语言有四种存储类别:自动的(auto),静态的(static),寄存器的(register),外部的(extern)
(1)如果定义局部变量时不赋初值,对于静态局部变量,编译时自动赋初值0(对数值型变量)或空字符’\0’(对字符变量)。而auto变量,值不确定,因为每次调用结束存储单元被释放,下次会重新分配,而新的存储单元内容未知。
(2)register:如果变量使用频繁(例如一个函数10000次循环,每次都要用该变量),那么可以设定为register类型存在CPU的寄存器中,因为寄存器的读取速度远高于对内存的读取速度,执行效率较高。
不过register声明变量必要性不大,因为目前优化的编译系统能够识别使用频繁地变量,自动放在寄存器中,不需要程序设计者指定。
(3)extern
a、在一个文件内扩展外部变量的作用域
本来A的作用范围是定义处到文件结束,上述做法可以在定义点前的函数内引用该外部变量。(用处较少,一般建议把外部变量放在所有函数之前,避免多一个extern声明)。
b、将外部变量作用于扩展到其他文件
如果两个文件都用到同一外部变量,不能两个都定义,程序连接时会出现“重复定义”的错误。正确的做法如上述,系统在编译连接时会知道该变量是“外部连接”,从别处找已定义的该变量,并扩展作用域。
用此方法要特别注意,因为在执行一个文件的操作时可能改变该全局变量的值,会影响到另一个文件中全局变量的值,影响函数的执行结果
c、把外部变量的作用于限制在本文件中
上述做法是不可行的,static声明后只能用于本文件,即使用extern声明也没用。(这是static对全局变量的作用,对局部变量static就是不释放,一直存在,分配在静态存储空间)
9、内部函数:
只能被本文件调用
外部函数:
可供其他文件调用。C语言规定,在定义函数时省略extern,则默认为外部函数。
10、练习:利用递归的思想求 n!
output:
11、练习:Hanoi(汉诺塔)问题:给出塔数,移动步骤。
算法分析:将n个盘子从A座移到C座分解步骤
(1)将A上n-1个盘子借助C移到B
(2)将A座剩下的一个盘子移到C座
(3)将n-1个盘从B座借助于A移到C做
好好理解里面的递归思想,可以从盘子数小的汉诺塔自己移动理解
output:
n个盘子最少要移动(2^n-1)次。
12、用递归法将一个整数n转换成字符串。例如输入483,应输出字符串“483”。n的位数不确定,可以使任意位数的整数。
output:
在学习UI高级知识之前,将利用最近十来天的时间回顾一下C语言,主要按照《C程序设计(谭浩强版)》来回顾。
整理一些知识点(不是细节,知识个人觉得较重要或易忘的)以及挑一些课后题目或经典习题编写代码练习。
第7章 用函数实现模块化程序设计
1、模块化程序设计思想!要善于利用函数,减少重复编写程序段的工作量,实现模块化!
2、函数调用过程:以下列程序返回大值为例说明
#include <stdio.h> int main(int argc, const char * argv[]) { // int maxNum(int x, int y); int maxNum(int,int); //两种不同的函数声明方式,第4点有用 int a = 2,b = 3; int c; c = maxNum(a, b); printf("%d And %d max = %d\n",a,b,c); return 0; } int maxNum(int x,int y) { return x>y?x:y; }
output:
2 And 3 max = 3
(1)定义函数指定形参未调用时,不占内存。只有发生调用时,函数maxNum的形参被临时分配内存单元;
(2)将实参对应的值传递给形参;x得到值2,y得到值3;
(3)执行函数时,由于形参已有值,因此利用形参进行运算;
(4)通过return将函数值带回到主调函数;
(5)调用结束,形参单元被释放。(形参值改变不会改变实参值,两者是两个不同的存储单元)
注意:形参与实参的值传递是单向传递,只能实参传形参。
3、函数类型决定返回值类型。如果函数值的类型和return的值类型不一致,则以函数类型为准。对于数值类型数据,可以自动进行类型转换。空类型函数不得出现return。
4、声明:如果自定义函数位置在调用它的函数后面(同一个文件中),应该在主调函数中对被调用的函数作声明。也可以在所有函数之前,#include之后进行声明,那么在各函数中就不用再作声明了。
声明形式:在2的程序中已有说明。
作用:把函数名、形参的个数和类型等信息告知编译系统,以便遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。
5、嵌套调用:较简单,不复述
递归调用:调用函数的过程中又直接或间接地调用该函数本身
练习部分有阶乘和Hanoi塔问题
6、数组作为形参的时候,是作为指针变量!!!
以下三种写法是等效的:a的作用是传递a[0]的地址,首地址!!!
void func(int a[10]) | void func(int a[]) | void func(int *a) |
---|
(2)用数组元素作实参时,向形参传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址。
(3)多维数组做实参和形参,可以指定每一维的大小,也可以省略第1维的大小说明,但是第2维以及其他高维的大小说明不能省!因为多维数组在内存中按行存放,必须指定列数。
7、全局变量和局部变量
变量 | 作用域 | 生存周期 |
---|---|---|
全局变量 | 全局 | 全局 |
局部变量 | 局部 | 局部 |
静态局部 | 局部 | 全局 |
(2)静态局部变量:初始化只作用一次
(3)生存周期:从开始申请内存到释放内存
(4)在不必要的时候不要使用全局变量:整个过程都占用存储单元;降低了函数的通用性和可靠性,当函数移到另一个文件还要考虑移植外部变量;降低程序的清晰性。要限制全局变量的使用!
(5)同名问题:同一个源文件中,全局变量与局部变量同名,那么在局部变量的作用范围内,局部变量有效,全局变量被“屏蔽”,不起作用。
example说明同名问题:
#include <stdio.h> int a = 3,b = 5; int main(int argc, const char * argv[]) { int maxNum(int x,int y); int a = 8; printf("%d And %d max:%d",a,b,maxNum(a, b)); return 0; } int maxNum(int x,int y) { return x>y?x:y; }
output:
8 And 5 max:8
8、变量存储类型
存储泪别 | 作用域 | 生存周期 |
---|---|---|
auto/register | 局部 | 局部 |
静态局部 | 局部 | 全局 |
静态外局 | 全局(仅本文件) | 全局 |
外部变量 | 全局 | 全局 |
(1)如果定义局部变量时不赋初值,对于静态局部变量,编译时自动赋初值0(对数值型变量)或空字符’\0’(对字符变量)。而auto变量,值不确定,因为每次调用结束存储单元被释放,下次会重新分配,而新的存储单元内容未知。
(2)register:如果变量使用频繁(例如一个函数10000次循环,每次都要用该变量),那么可以设定为register类型存在CPU的寄存器中,因为寄存器的读取速度远高于对内存的读取速度,执行效率较高。
不过register声明变量必要性不大,因为目前优化的编译系统能够识别使用频繁地变量,自动放在寄存器中,不需要程序设计者指定。
(3)extern
a、在一个文件内扩展外部变量的作用域
main() { extern int A; } int A; int func() { return 0; }
本来A的作用范围是定义处到文件结束,上述做法可以在定义点前的函数内引用该外部变量。(用处较少,一般建议把外部变量放在所有函数之前,避免多一个extern声明)。
b、将外部变量作用于扩展到其他文件
file1.c int A; main() { } file2.c extern A; void func() { }
如果两个文件都用到同一外部变量,不能两个都定义,程序连接时会出现“重复定义”的错误。正确的做法如上述,系统在编译连接时会知道该变量是“外部连接”,从别处找已定义的该变量,并扩展作用域。
用此方法要特别注意,因为在执行一个文件的操作时可能改变该全局变量的值,会影响到另一个文件中全局变量的值,影响函数的执行结果
c、把外部变量的作用于限制在本文件中
file1.c static int A; main() { } file2.c extern A; //出错! void func() { }
上述做法是不可行的,static声明后只能用于本文件,即使用extern声明也没用。(这是static对全局变量的作用,对局部变量static就是不释放,一直存在,分配在静态存储空间)
9、内部函数:
static int func(int a)
只能被本文件调用
外部函数:
extern int func(int a)
可供其他文件调用。C语言规定,在定义函数时省略extern,则默认为外部函数。
10、练习:利用递归的思想求 n!
#include <stdio.h> int factorial(unsigned int n) { int f = 1; if (n == 0 || n == 1) { return 1; } else { f = factorial(n-1)*n; } return f; } int main(int argc, const char * argv[]) { printf("%5d",factorial(0)); printf("%5d",factorial(1)); printf("%5d",factorial(5)); return 0; }
output:
1 1 120
11、练习:Hanoi(汉诺塔)问题:给出塔数,移动步骤。
算法分析:将n个盘子从A座移到C座分解步骤
(1)将A上n-1个盘子借助C移到B
(2)将A座剩下的一个盘子移到C座
(3)将n-1个盘从B座借助于A移到C做
好好理解里面的递归思想,可以从盘子数小的汉诺塔自己移动理解
#include <stdio.h> void hanoi(int n,char plateA,char plateB,char plateC) { // n个盘子从plateA借助plateB移动到plateC if (n < 1) { printf("Please input number > 0 !"); } if (n == 1) { printf("move %c to %c\n",plateA,plateC); } else { hanoi(n-1, plateA, plateC, plateB); printf("move %c to %c\n",plateA,plateC); hanoi(n-1, plateB, plateA, plateC); } } int main(int argc, const char * argv[]) { int n; printf("Please input plates number:"); scanf("%d",&n); hanoi(n,'A','B', 'C'); return 0; }
output:
Please input plates number:3 move A to C move A to B move C to B move A to C move B to A move B to C move A to C
n个盘子最少要移动(2^n-1)次。
12、用递归法将一个整数n转换成字符串。例如输入483,应输出字符串“483”。n的位数不确定,可以使任意位数的整数。
#include <stdio.h> void convert(int n) { int i; if (n < 0) { putchar('-'); n = -n; } if ((n/10) != 0) { i = n/10; convert(i); } putchar(n%10 +'0'); } int main(int argc, const char * argv[]) { convert(-248); return 0; }
output:
-248
相关文章推荐
- c++学习-虚函数
- 在C语言中的字符串
- 黑马程序员——C语言基础知识整理——printf函数与scanf函数
- 第14周项目4-处理C++源代码的程序
- 第十四周 【项目2-用文件保存的学生名单】若干名学生的学号 姓名和C++课、高数和英语成绩
- C++的4种类型转换关键字及其特点
- 注释转换 ——C注释转换为标准C++注释
- 从大学开始学C++到现在的一些感悟
- c++基础编程 之 string
- 【读书笔记:C++ primer plus 第六版 中文版】第4章 复合类型
- 双边滤波原理与C++实现
- c++学习-继承
- 第十五周oj刷题——Problem A: 长方柱类【C++ 类定义】
- 第十五周oj刷题——Problem B: 矩形类定义【C++】
- 第十五周oj刷题—— Problem C: 矩形类中运算符重载【C++】
- 第十五周oj刷题——Problem D: C++习题 对象数组输入与输出
- C/C++中关键字static的用法及作用
- 第十五周oj刷题——Problem E: C++习题 对象数组求最大值
- Uva1586
- 教你21天学会C++ (有图有真相)