• 程序设计入门-C语言基础知识-翁恺-第五周:函数-详细笔记(五)


    第五周:函数

    5.1 函数

    什么是函数?

    • 函数是一块代码,接受零个或多个参数,做一件事情,并返回零个或一个值。
    • 函数声明语法
      返回值 函数名(参数列表){
      函数体
      }
    • 我们前面列子中经常使用的printf和scanf都是函数

    调用函数

    • 函数(参数值);
    • ()小括号起到了表示函数调用的重要作用,及时没有参数也需要()
    • 如果有参数,则需要给出正确的数量和顺序
    • 这些值会被按照顺序依次来初始化函数中的参数
    • 调用函数时给的参数叫做实际参数,在函数体内接受到的参数叫形式参数
    • 函数知道每一次是哪里调用它,会返回到正确的地方
    • 可以传递给函数的值是表达式的结果,这包括:
      • 字面量
      • 变量
      • 函数的返回值
      • 计算的结果
    • 调用函数时给的值与参数的类型不匹配是C语言传统上最大的漏洞
    • 编译器总是悄悄替你把类型转换好,但是这很可能不是你所期望的
    • 后续的语言,C++/Java在这方面很严格

    从函数中返回值

    • return停止函数的执行,并返回一个值
    • return;
    • return 表达式;
    • 一个函数中可以有多个return语句
    • 不推荐给一个函数多个return不符合单一出口原则,多个return我们再做修改时需要去找所有的出口

    没有返回值的函数

    • void 函数名(参数表)
    • 不能使用呆值的return,也可以没有return
    • 调用的时候不能做返回值的赋值
    • tips:如果是有返回值的函数,则必须使用带值的return

    5-2 使用函数

    • 把函数的原型声明写在main函数前是因为c的编译器自上而下顺序分析你的代码
    • 函数可以先做原型声明,再定义;
    • 函数的声明和定义必须一致

    函数原型

    • 函数头,以分号";"结束,就构成了函数原型
    • 函数原型的目的是告诉编译器这个函数长什么样子
      • 名称
      • 参数(数量及类型)
      • 返回类型
    • 旧的标准习惯把函数原型写在调用它的函数里面,现在一般写在调用它函数的前面。
    • 原型里可以不写参数的名字,但是一般仍然要写上,便于阅读。

    参数的传递

    • c语言的函数的参数的传递是对值的传递
    • 每个函数有自己的变了空间,参数也位于这个独立的空间中,和其他函数没有关系
    • 过去,对于函数参数表中的参数,叫做“形式参数”,调用函数时给的值,叫做“实际参数”
    • 由于容易让初学者误会实际参数就是实际在函数中进行计算的参数,误会调用函数的时候把变量而不是值传进去了,所以我们不建议继续用这种种古老的方式称呼它们。
    • 调用参数的时候,我们就叫把值传递进去了,而在函数内部我们就称为参数。

    本地变量

    • 函数的每次运行,就产生了衣蛾独立的变量空间,在这个空间中的变量,是函数这次运行所独有的,称为本地变量。
    • 作用域:在(代码的)什么范围内可以访问这个变量(这个变量可以)起作用
    • 对于本地变量,这两个问题的答案是统一的——大括号内(块)

    本地变量的规则

    • 本地变量时定义在块内的
      • 块可以是函数的块内
      • 也可以是语句的块内
      • 甚至可以随便拉一大括号定义变量
    • 程序运行进入这个快之前,这个变量不存在,离开这个快,这个变量也消失了
    • 在块外定义的变量在块内仍然有效
    • 在块里面定义了和外面同名的变量则掩盖了外面的
    • 不能在同一块内定义同名的变量
    • 本地变量不会被默认初始化
    • 参数在进入函数的时候就被初始化了

    没有参数时

    • 在函数没有参数时一定要使用void填充参数,比如: void f(void);
    • 因为如果不写void就等于告诉编译器,不确定需要什么参数,当调用函数时如果有参数,编译器会默认以为函数的参数的类型都是int ,而且在定义时如果参数不一致编译器也不会报错,因此当定义时变量为double而声明为int调用的结果就不是我们预期的了。
    • 同样如果函数没有声明,编译器会默认认为这个函数是一个 int类型返回值并且有两个int类型参数的函数,为了程序便于阅读,所有的函数在使用前都需要原型声明,再定义。

    逗号运算符

    • 调用函数时的逗号和逗号运算符怎么区分?
    • 调用函数时的圆括号里的逗号是标点分隔符,不是运算符
      • f(a,b) 标点分割符,分割多个参数
      • f((a,b)) 算术运算符
    • (a,b) 逗号运算符自左向右运算,先计算左边表达式的值,再计算右边表达式的值,最后的结果返回右边表达式的值。比如 (a=3+2,a-5)的结果是 0

    函数里面的函数

    • c语言不允许函数的嵌套定义

    奇怪的写法

    • int i,j,sum(int a,int b); 虽然c语言允许这么做,但是不推荐这种写法,不易于阅读。
    • return (i); 返回一个i的值,同样不推荐,理由同上。

    关于main

    • int mian()也是一个函数
    • 要不要写成int main(void)? 可以写成void,并且在main函数执行前程序还有些准备的工作,当执行好这些准备工作后才会调用main函数
    • return的0有人看吗?
      • Windows: if errorlevel 1...
      • Unix Bash: echo $?
      • Csh: echo $status
      • return的值在各个系统都是可以得到的,有人会根据返回值来判断程序是否出错等,因此return 0 是有意义的。

    5.3 课后习题

    1 .题目内容: 题目内容:
    每个非素数(合数)都可以写成几个素数(也可称为质数)相乘的形式,这几个素数就都叫
    做这个合数的质因数。比如,6 可以被分解为 2x3,而 24 可以被分解为 2x2x2x3。
    现在,你的程序要读入一个[2,100000]范围内的整数,然后输出它的质因数分解式;当
    读到的就是素数时,输出它本身。
    输入格式:
    一个整数,范围在[2,100000]内。
    输出格式:
    形如:
    n=axbxcxd

    n=n
    所有的符号之间都没有空格,x 是小写字母 x。
    输入样例:
    18
    输出样例:
    18=2x3x3

    题目分析:

    • 我们前面写过判断素数的功能,可以把他封装成一个函数。
    • 这里用用户输入的有两种情况,输入的是一个素数或者合数。
    • 素数十分好处理,我们直接输出这个数本身即可。
    • 如果是合数怎么算出这个合数的质因数呢?我们有三个未知的问题,一是不知道这个合数有多少个质因数,并且也不知道这些质因数的值和组合方式。
    • 我们可以采取笨一点的办法,
      1. 用这个合数num和最小素数2做取余,如果结果不为0,则表示除不尽继续用下一个素数3做整除,一直到能整除为止,算出一个结果。
      2. 将结果赋值给num,如果num还是合数回到第1步,否则我们就已经把最初的素数num拆分成n个相乘的素数了,也就是这个合数的质因数。
    • 因此我们还需要一个取第x个素数的值一个函数,x>0

    程序实现:

    
    #ifndef getPrimeFactor_h
    
    #define getPrimeFactor_h
    #include <stdio.h>
    int isPrime(int number);
    void getPrimeFactor(void);
    int getPrimeNumber(int index);
    #endif
    
    
    
    #include "getPrimeFactor.h"
    
    int isPrime(int number)
    {
     int isPrimeNumber = 1;
     int middle = 0;
    
     if (number == 1)
     {
      isPrimeNumber = 0;
     }
     else
     {
      int i = 2;
      middle = number / 2;
      for (; i <= middle; i++)
      {
       if (number % i == 0)
       {
        isPrimeNumber = 0;
        break;
       }
      }
     }
    
     return isPrimeNumber;
    }
    
    int getPrimeNumber(int index)
    {
     int isPrimeNumber = 1;
     int middle = 0;
     int primeNumber = 2;
     int i, j;
     int currentIndex = 0;
    
     for (j = 2; j < 100000; j++)
     {
      //重置素数状态
      isPrimeNumber=1;
      middle = j / 2;
      for (i = 2; i <= middle; i++)
      {
       if (j % i == 0)
       {
        isPrimeNumber = 0;
        break;
       }
      }
      if (isPrimeNumber)
      {
       primeNumber = j;
       currentIndex++;
      }
      if (index == currentIndex)
      {
       break;
      }
     }
     return primeNumber;
    }
    
    void getPrimeFactor(void)
    {
     int number = 0;
     int currentPrimeNum = 2; //当前素数
     int primeIndex = 1;	//当前素数的序号,从1开始1,2,3...
    
     printf("请输入一个范围在[2,100000]的整数");
     scanf("%d", &number);
    
     if (isPrime(number))
     {
      printf("%d=%d", number, number);
     }
     else
     {
      printf("%d=", number);
      do
      {
       while (number % currentPrimeNum != 0 && currentPrimeNum < number)
       {
        primeIndex++;
        currentPrimeNum = getPrimeNumber(primeIndex);
       }
       number /= currentPrimeNum;
       printf("%dx", currentPrimeNum);
       //当number值改变重置状态
       currentPrimeNum = 2;
       primeIndex = 1;
      } while (!isPrime(number));
      printf("%d", number);
     }
    }
    
    
    #include <stdio.h>
    #include "getPrimeFactor.h"
    
    int main(int argc, char *argv[])
    {
     getPrimeFactor();
     return 0; 
    }
    

    测试样例:

    请输入一个范围在[2,100000]的整数18
    18=2x3x3
    --------------------------------
    Process exited after 1.221 seconds with return value 0
    请输入一个范围在[2,100000]的整数100
    100=2x2x5x5
    --------------------------------
    Process exited after 1.691 seconds with return value 0
    请输入一个范围在[2,100000]的整数108
    108=2x2x3x3x3
    --------------------------------
    Process exited after 2.766 seconds with return value 0
    
    

    2.题目内容:
    一个正整数的因子是所有可以整除它的正整数。而一个数如果恰好等于除它本身外的因子之
    和,这个数就称为完数。例如 6=1+2+3(6 的因子是 1,2,3)。
    现在,你要写一个程序,读入两个正整数 n 和 m(1<=n<m<1000),输出[n,m]范围内
    所有的完数。
    提示:可以写一个函数来判断某个数是否是完数。
    输入格式:
    两个正整数,以空格分隔。
    输出格式:
    其间所有的完数,以空格分隔,最后一个数字后面没有空格。如果没有,则输出一个空行。
    输入样例:
    1 10
    输出样例:
    6

    题目分析:

    • 我们需要输出n到m范围内所有的完数。
    • 如何判断一个数n是否是完数呢?我们用n做取余运算,从1开始取余n/2,这期间所有取余为0的数就是这个数的因子,然后我们再对他们对累加,如果累加的和恰好等于n本身那么这个数就是一个完数。

    程序实现:

    #ifndef getPerfectNumberRange_h
    
    #define getPerfectNumberRange_h
    #include <stdio.h>
    void getPerfectNumberRange(void);
    int getIsPerfectNumber(int number);
    #endif
    
    
    
    #include "getPerfectNumberRange.h"
    
    int getIsPerfectNumber(int number)
    {
    
        int sum = 0;
        int isPerfectNumber = 0;
        for (int i = 1; i <= number / 2; i++)
        {
    
            if (number % i == 0)
            {
                sum += i;
            }
        }
    
        if (sum == number)
        {
            isPerfectNumber = 1;
        }
    
        return isPerfectNumber;
    }
    
    void getPerfectNumberRange(void)
    {
    
        int n, m;
        int isHaveAnyPerfectNumber = 0;
        printf("请输入两个正整数n和m,(1<=n<m<1000)");
        scanf("%d %d", &n, &m);
    
        for (int i = n; i <= m; i++)
        {
    
            if (getIsPerfectNumber(i))
            {
                printf("%d", i);
    
                if (isHaveAnyPerfectNumber == 0)
                {
                    isHaveAnyPerfectNumber = 1;
                }
    
                if (i < m)
                {
                    printf(" ");
                }
            }
    
           
        }
    
        if (isHaveAnyPerfectNumber == 0)
        {
            printf("
    ");
        }
    }
    
    
    
    
    #include <stdio.h>
    #include "getPerfectNumberRange.h"
    
    int main(int argc, char *argv[])
    {
     getPerfectNumberRange();
     return 0; 
    }
    
    

    测试样例:

    请输入两个正整数n和m,(1<=n<m<1000)1 100
    6 28
    --------------------------------
    Process exited after 1.984 seconds with return value 0
    
    请输入两个正整数n和m,(1<=n<m<1000)1 5
    
    
    --------------------------------
    Process exited after 4.39 seconds with return value 0
    
  • 相关阅读:
    HTTP协议
    javascript常用数组排序及二分查找
    垃圾回收与内存管理
    js的数据存储机制和数据类型
    js中的深复制与浅复制
    斐波那契数列的实现
    认识python中的浅复制与深复制
    微信浏览器中弹窗高度适配
    “ 时,分,秒” 活动倒计时
    互联网协议
  • 原文地址:https://www.cnblogs.com/simple-blog/p/9508712.html
Copyright © 2020-2023  润新知