您的位置:首页 > 编程语言 > C语言/C++

C语言回顾(五、函数,递归,Hanoi汉诺塔,整数转字符串)——iOS开发基础

2015-06-21 15:27 429 查看
说明:

在学习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]的地址,首地址!!!

[thead]
[/thead]
void func(int a[10])void func(int a[])void func(int *a)
(1)第一种写法:虽然定义函数时,声明数组的大小为10,但实际上,指定其大小不起任何作用,因为C语言编译系统并不检查形参数组大小,只是将实参数组的首元素的地址传给形参数组名。

(2)用数组元素作实参时,向形参传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址。

(3)多维数组做实参和形参,可以指定每一维的大小,也可以省略第1维的大小说明,但是第2维以及其他高维的大小说明不能省!因为多维数组在内存中按行存放,必须指定列数。

7、全局变量和局部变量

[thead]
[/thead]
变量作用域生存周期
全局变量全局全局
局部变量局部局部
静态局部局部全局
(1)全局变量定义在函数外部,增加函数间数据练习的渠道,一般全局变量的第一个字母用大写表示区分于局部变量,习惯非规定。局部变量定义在函数内部

(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、变量存储类型

[thead]
[/thead]
存储泪别作用域生存周期
auto/register局部局部
静态局部局部全局
静态外局全局(仅本文件)全局
外部变量全局全局
C语言有四种存储类别:自动的(auto),静态的(static),寄存器的(register),外部的(extern)

(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: