7.1上节课的OJ作业讲解(指针本质及其场景的使用)
test1:
跟之前一样,先输入一个变量:
然后写一个change子函数:
如果定义一个指针变量,没有初始化,就是一个空的藏宝图。
只是写上int *p;
函数的声明和定义将在本节将有清晰的讲解
test2:
注意必须在scanf和gets中添加一个scanf函数,用于清除读取的字符串后面系统自动添加的“\n”.
接着就可以申请空间了。
malloc(size)本来是void类型(即是无类型)所以需要在前面加上强制类型转换char *
所以再加上指针:
7.2函数的声明与定义——嵌套调用
函数之间的调用关系:
main函数不能被其他函数调用,由主函数调用其他函数,其他函数也可以互相调用。同一函数可以被一个或多个函数调用任意次。
如图所示:
ep/1.1
函数嵌套调用
函数的定义(声明)
必须在main函数前面,需先定义后实现。
函数的实现
函数没有声明的话。默认为int类型
在里面新建一个C/C++的源文件
再新建一个C/C++头文件
在头文件中添加 #include<stdio.h>
那么在main.c中直接引用就可以了。
尖括号是在标准库下找头文件,双引号是在当前目录下找我们自己的头文件。
非常重要的快捷键:
crtl+鼠标左键 点击对应的函数,就可以跳转到对应函数查看源码。
因为函数在func.h中作了函数声明,所以无论函数因为调用顺序而发生的错误不会出现。
最后展示一下最后的代码:
(1)func.h
(2)func.c
(3)main.c
其中print_message函数就实现了函数的嵌套调用
C语言的编译和执行具有以下特点:
(1)一个C程序由其他或多个程序模块组成,每个程序模块作为一个源程序文件。
所以呢,对于较大的程序,通常将程序内容分别放在若干源文件中,再由若干源程序文件组成1个C程序,这样便于分别编写,分别编译,进而提高调试效率(复试有用)。
(因为在工作中是由很多个程序员协同开发的)
(2)一个源程序文件由一个或多个函数及其他有关内容(如命令行,数据定义等)组成。
一个源程序文件是一个编译单位,在程序编译时是以程序文件为单位而不是以函数为单位编译的。
main.c和fun.c分别单独编译,在链接成为可执行文件,main中调用的函数printstar和print_message才会通过链接去找到函数定义的位置。
(3)C程序的执行是从main函数开始的,如果在main函数中调用其他函数,那么在调用后会返回到main函数中,在main函数中结束整个程序的运行。
(4)函数间可以互相调用,但不能调用main函数,main函数是由系统调用的。
上述例子中的main函数调用print_message函数,而print_message函数中又调用printstar函数,我们把这种调用称之为嵌套调用。
不能嵌套定义,如下图。
函数的声明和定义的差异如下:
(1)函数的定义是指对函数功能的确立,包括指定函数名(print_star),函数值类型(int),形参(i)及其类型(int),函数体(大括号里面包含的内容)等,他是一个完整,独立的函数单位。
(2)函数的声明的作用是把函数的名字,函数类型及形参的类型,个数和顺序通知编译系统,以便在调用该函数时编译系统能正确识别函数并检查调用是否合法。
什么叫隐式声明呢?
函数如果不显式的声明返回值的类型,那么它默认返回整型。
2.函数的分类和调用
从用户的角度来看
(1)标准函数:即库函数,这是由系统提供的,用户不必自己定义的函数,可以直接使用他们,如:printf函数,scanf函数。不同的C系统提供的库函数的数量和功能会由一些不同,但基本函数相同。
(2)从用户自己的定义的函数:以解决用户的专门需要
从函数的形式来看,分为两种:
1.无参函数:一般用来执行指定的一组操作。在调用无参函数时,主调函数不向被调用的函数传递数据。
2.有参函数:主调函数在调用被调用函数的时候,通过参数向被调用函数传递数据/
7.3函数的递归调用
我们把函数自身调用自身的函数,称为递归函数。递归函数一定要有结束条件,否则会发生死循环!
比如说我们写一个求阶乘的题目。
1.递归的核心是找公式:
2.编写递归结束条件
f(n)=n*f(n-1)
以前我们可以用for循环求解:
如果使用递归函数:
所以递归最重要的还是找最后的结果与前一步或者或者是前面的关系。
这一节的代码题:
当n=1或n=2
执行下面的递归函数会发生错误。
因为就有step(0)
正好当n=1时,有一种走法
当n=2时,有两种走法。
结束条件结果直接return n;
7.4 局部变量和全局变量
1.全局变量接续——形参——实参解析
在不同函数之间传递数据时,可以使用的方法如下:
(1)参数:通过形式参数和实际参数
(2)返回值:用return语句返回计算结果
(3)全局变量:外部变量
下面来看一个全局变量的例子
node:
main函数里的 i=5是局部变量。
如果将它改为 int i=5,那么全局变量和局部变量重名。
那么将采取就近原则,即实际获取和修改的值是局部变量的值。
执行结果:
形参可以看成局部变量(那么输出就变为了3,不再是10了)
局部变量指数在离自己最近的大括号内有用
所以for循环内的k变量无法在括号外使用。
执行结果:
关于形参与实参的一些说明:
(1)定义函数中指定的形参,如果函数没有调用,那么他们并不占用内存中的存储单元,只有在发生函数调用数时,函数中的print中的形参才会被分配内存单元。调用结束后,形参多占的内存单元也会被释放。
(2)实参可以是常量,变量或表达式。但是要求他们有确定的值。
比如说:print(i+3)在调用时将实参的(i+3)赋给形参,如:print(int a, int b)
(3)在被定义的函数中,必须指定形参的类型。实参和形参的个数应当相等,类型匹配,按顺序对应进行数据传递。
(4)实参和形参的数据传递应当是单向“值传递”,只能由实参传给实参,而不能由形参传给实参。在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元释放,实参单元仍保留并维持原值。
(5)形参相当于局部变量,因此不能再定义局部变量和形参相同,否则会造成编译不通。
2.外部变量
函数之外定义的变量也称为外部变量。外部变量可以为本文件中的其他函数公用,但他的有效范围并不是全部,而是从定义变量的位置开始到本源文件结束,所以也称作全程变量。
关于全程变量须注意一下几点:
(1)全局变量在程序执行过程中都占用内存单元,而不是仅在需要时才开辟单元。
(2)使用全局变量会降低程序的清晰性。在各个函数执行时都可能改变外部变量的值。程序容易出错。(初试尽量不使用)
(3)C语言要求把程序中的函数做成一个封闭体,除可以通过”实参——形参“的渠道与外界发生值传递外,没有其他渠道。
函数在栈里面。
外部变量也称作全程变量,存储在数据段里面,一直占用内存空间。