第七章 函数   realloc()函数

函数

关于模块化编程(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、数组名作为函数参数

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

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

                   第七章  函数
  realloc()函数

四、函数原型

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

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

     函数名:功能

               参数个数及类型

            所有的数学库中的函数  返回值类型都是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) ;

第七章  函数
  realloc()函数

2、malloc函数

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

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

          void *malloc(num); //num

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

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

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

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

    作用:(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