• 第七章 函数


    函数

    关于模块化编程(C语言的程序模块称为函数),我们需要注意的几点。
      1,没有子函数的概念。函数之间都是并列的关系,不能把一个函数定义到另一个函数的函数体中。
      2,当定义在下面的函数,而上面代码已经调用了,此时需要函数原型的声明。如果函数定义在上面,而使用在下面,可以不用函数原型声明。
      3,函数的返回值类型就是告诉编译器函数运算完成后,返回值的数据类型,当调用函数时,就可以定义相应类型的变量来接收函数的返回值了。当函数被调用时,形参比照类型,开辟空间用来接收实参的值。函数内部定义的变量叫做局部变量。是保存程序中间运算结果的。
      4,每个函数都是独立的,在内存中,函数调时都会开辟一个栈帧,在一个函数体中,不能直接使用另外一个函数体中定义的变量,如果想要用到其它函数内定义的局部变量,只能用到参数传递。函数调用时产生栈帧,函数调用结束后,栈帧内存将释放(也就是所有的形参和局部变量分配的空间将全部释放)。
      5,按数目一致,类型相同,顺序相同这样的原则进行函数调用,进行实参和形参的结合,正确的结合是函数调用的关键。

    一、函数概述

       函数定义:函数头+函数体

            函数头: 说明函数的类型、名字、参数及参数的类型。如: int max( int x, int y )

            函数体:  由“{ }”括起,包括变量声明和执行部分

      分类: 标准库函数和用户定义的函数。

      说明:(1)一个C程序可由一个主函数和若干个其他函数组成

           (2) 程序执行时从main函数开始, 根据需要, main函数调用其他函数, 其他函数也可以互相调用。

         (3)同一个函数可以被一个或多个函数调用任意多次。最后由main函数结束程序的运行。

         (4)不能调用main函数

      举例:用上面的设计原则,重新实现pmp程序,大于35 输出你好成熟,小于35 ,输出你好年轻。


              #include <stdio.h>
              void welcome();//因为C语言是先声明再使用的语言,所以对函数原型先声明一下。
                 int ask();
              void pmp(int age);
              void main()
              {
                int age = 0;
                welcome();     //函数调用,一串字母后面跟着小括号,然后还一个分号,我可以基本判断出来它是函数调用。
                 age = ask();      //询问年龄,需要得到年纪值,那么我需要定义个一个变量,保留这个值。
                               //ask()也是一个函数调用,它是把ask()返回的值赋值给age。
                    pmp(age);         //小括号里面是实际参数(实参),函数调用。
              }


             void welcome() //因为welcome,就是一个欢迎而已,所以我定义一个无参数,无返回值这样的函数原型。
             {
                printf("欢迎来蚂蚁软件学习 ");
                printf("今天天气太好了。 ");
             }

             int ask()        //因为 ask(),实现问询年纪的功能,所以不需要提供参数,所以根据需求来讲,就应该设计成无参数。
                       //但需要问出来年纪值,所以函数可以设计一个带返回值的函数原型。
              {
                int age = 0;        //函数内部定义的变量叫做局部变量。是保存程序中间运算结果的。
                printf("您今年多大了? ");   //因为每个函数都是独立的,在内存中,函数调用后都会开辟一个栈帧,所以此处age
                scanf("%d",&age);                //和main 函数的age,是两个不同的存储单元,只是名字相同而已。
                return age                             //在一个函数体中,不能直接只用另外一个函数体中定义的变量,如果想要用到其它函数 
                                                                 //内定义的局部变量,需要用到参数传递。


                  //因为PMP函数,根据需求来讲,对于这个函数来讲,肯定需要一个年纪值,我才可以拍。所以,就需要设计
                  //一个形式参数了,返回值就是void,形式参数干什么用的呢?当函数被调用时,形参比照类型,开辟空间用来
                  //接收实参的值。
              void pmp(int age) 
              { 
                if(age > 35)                      //形参的这个AGE可以取任何名字都可以,他仅仅是形参分配空间的名字而已。
                {
                  printf("您好成熟啊");      //它属于被调用函数的变量。所以此处的AGE和main函数里面的AGE,是不同的内存块。
                }
                else               //这里仅仅名字相同而已。你也可以取不同的名字。
                {
                  printf("您好年轻啊");
                }

              }

    二、函数返回值

      格式: return ( 表达式 ); return 表达式 ;

      作用: (1)将表达式的值返回给调用函数 结束被调用函数的执行, 并把程序的控制返回到调用它的函数。

          (2)结束函数执行

      注意:(1)函数的返回值的类型应与函数的类型一致。如不一致, 以函数类型为准, 对返回值进行类型转换, 然后传送给调用函数。

           (2)一个函数可以有多个return语句,  但只可能执行其中一个。

    三 函数参数

      正确地进行结合是函数调用的关键。结合时应注意:  实参与形参的个数相等,  顺序一致, 类型应相同。

      1、实参与形参结合的原则是:

        当实参为常量、变量、表达式或数组元素时,对应的形参只能是变量名。

        当实参为数组名时, 所对应的形参必须是同类型的数组名或指针变量。

      2、数组名作为函数参数

         实参与形参之间的数据传递是地址传递。

        可用多维数组名作实参和形参。在被调用函数中对形参数组定义时, 可以指定每一维的长度,也可省略第一维的长度

                       

    四、函数原型

      用户自定义函数在调用前, 必须对该函数进行声明。函数声明就是函数原型 

          返回值类型:决定函数运行的结果 接收数据时  数据类型要一致

         函数名:功能

                   参数个数及类型

                所有的数学库中的函数  返回值类型都是double,也可以传入整型 用整型变量接收结果

    五 递归函数

      概念:函数的递归调用是指在一个函数调用过程中又直接或间接调用自己,

      语法:

         (1)控制递归的深度(一个if选择)约束条件可以有多个

         (2)通项(必然包括调用函数自身)

      注意:递归函数只有最后一次调用执行完才开始释放 因为栈是先进后出

          作用其实递归是为了解决一些不好写的逻辑,简化程序。(可以用递归解决的问题,用循环也可以  但是难度不在一个等级)

    六、作用域

      复合语句定义的变量  作用范围仅限于本复合语句 如其上层有同名的变量 互不影响  

      全局变量:也叫外部变量,是指定义再函数外的变量 通常定义再文件首部,作用范围指从定义的位置到文件末尾皆可使用 下方的函数内都可以使用  

      局部变量 函数内定义的变量称谓局部变量。仅限于本函数使用

      以上三种作用域都属于就近原则

    七 操作系统的内存分

      栈区:是存储函数相关的区域   2M 内存较小

        特性: 执行时分配,使用完即释放 由系统操控 结合面向过程来的先进后出

        关键字  auto(自动变量:相当于局部变量)  register(寄存器)

      堆区:是malloc函数分配的空间    较大 G来说

        特性: 由程序员手动分配,手动释放,空间大小可控 由程序员操控  一般用分配大量的空间或指定大小的空间时使用

      全局/静态区: 存放全局变量  静态变量

        特性:在程序编译后 运行前空间已经分配  程序运行结束后释放空间

        关键字: static 静态  extern 外部声明

      常量文本区/:(二进制代码)

        特性: 不可改

           数值常量和字符串常量分配到常量文本区,他的特点是不能修改。你如果修改如果编译时编译器识别出来了,就会编译不通过。如果编译器没有识别出来你在修改常量,那么程序运行时就会崩溃。常量是坚决不能修改的。他的内存也是始终存在的,等到程序结束后,由操作系统统一释放。

      程序代码区:保存代码逻辑。

     库函数学习

      (1)使用库函数: 1.包含库函数的头文件   2.函数的功能   3.函数的参数个数及类型   4.返回值类型

      (2)函数原型          返回值类型:决定函数运行的结果 接收数据时  数据类型要一致

                函数名:功能

                          参数个数及类型

            所有的数学库中的函数  返回值类型都是double,也可以传入整型 用整型变量接收结果

           (3)、标准库函数

      C标准库由在15个头文件中声明的函数、类型定义和宏组成,每个头文件都代表了一定范围的编程功能。

        合格:<stdio.h>、<ctype.h>、<stdlib.h>、<string.h>

        熟练:<assert.h>、<limits.h>、<stddef.h>、<time.h>、<rand.h>

        优秀:<float.h>、<math.h>、<error.h>、<locale.h>、<setjmp.h>、 <signal.h>、<stdarg.h>

    1.字符串处理函数 (https://www.cnblogs.com/si-lei/p/9459209.html)

      #include “string.h”

      strcat(字符数组1, 字符数组2) ;

      strcpy(字符数组1, 字符串2) ;

      strlen(字符串) ;

      strlwr(字符串) ;

      strupr(字符串) ;

      strcmp(字符串1, 字符串2) ;

    2、malloc函数

      作用:动态分配内存。堆中分配一个长度为size的连续空间,内存的大小由参数决定

      函数原型:#include<stdlib.h>

              void *malloc(num); //num

      说明:(1)函数的返回值是一个指向所分配内存起始地址的指针,类型为void *型。说得简单点就是,malloc函数的返回值是一个地址,这个地址

               就是动态分配的内存空间的起始地址。如果此函数未能成功地执行,如内存空间不足,则返回空指针NULL。

          (2)如何用malloc动态分配内存

           int *p = (int *)malloc(4);//请求系统分配4字节的内存空间,并返回第一字节的地址,然后付给指针变量 p。

      realloc()函数

        作用:(1)更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小。

              (2)把第一个参数指针指向的之前分配的内容复制到新配的内存中

        函数原型:#include<stdlib.h>

                             realloc(void *__ptr, size_t __size)  //两个参数:一个是包含地址的指针(该地址由之前的malloc()函数返回),另一个是要新分配的内存字节数。

         说明:(1)新内存大于原内存,则原内存所有内容复制到新内存,如果新内存小于原内存,只复制长度等于新内存空间的内容。

           (2)realloc()函数的第一个参数若为空指针,相当于分配第二个参数指定大小的新内存空间

           (3)如果是将分配的内存扩大,则有以下3种情况:
                      如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。 
                   如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。

                      如果申请失败,将返回NULL,此时,原来的指针仍然有效。

      calloc函数

        作用根据类型来分配空间

        函数原型:#include <stdio.h>

                void*  calloc(size_t num,size_t size); num为元素个数,size为每个元素的字节长度

        说明:在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。

        跟malloc的区别:calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。

     3、itoa()函数和atoi()

      itoa():将整型值转换为字符串

          函数原型,char * itoa(int a,char * output,int radix)
            第一个参数,表示要转换成字符串的那个数字。例如15
            第二个参数,表示转换后的字符串,
            第三个参数,表示按多少进制来转换。
            返回值,就是存放转换后的字符串内存的首地址。
            例如调用 itoa(15,output,16) 得到f
    i            itoa(15,output,8) 得到21字符串
                itoa(15,output,2) 得到1111字符串

      atoi():将字符串转换为整型值。

        函数原型:  int atoi(const char *str );  //str a要进行转换的字符串

        函数功能:把字符串转换成整型数。

        返回值:每个函数返回 int 值,此值由将输入字符作为数字解析而生成。 如果该输入无法转换为该类型的值,则atoi的返回值为 0

  • 相关阅读:
    牛客(28)数组中出现次数超过一半的数字
    牛客(27)字符串的排列
    2、Spring Cloud和dubbo简介
    1、微服务简介
    12、Spring Boot监控
    11、Spring Boot热部署
    10、Spring Boot分布式
    9、Spring Boot安全
    8、Spring Boot任务
    7、Spring Boot检索
  • 原文地址:https://www.cnblogs.com/hyt19911004/p/12392412.html
Copyright © 2020-2023  润新知