一. 头文件中的#ifndef、#define与#endif语句解释
我们先来回顾一下上次我们自己写头文件,在头文件中来声明函数,再在新建的源文件中定义函数,最后在原来的头文件中调用自定义函数,如下代码:
代码1(add.h头文件中的内容):
#ifndef __ADD_H__
#define __ADD_H__
int Add(int x,int y);
#endif
代码2(add.c源文件中的内容):
int Add(int x, int y)
{
int z = x + y;
return z;
}
代码3(code.c源文件中的内容):
#include<stdio.h>
#include"add.h"
int main(void){
int a = 20;
int b = 30;
int sum = Add(a, b);
printf("sum=%d\n",sum);
getchar();
return 0;
}
除了代码1中的部分语句,其余代码我们都已经分析过了,那么代码1中的
#ifndef
#define
#endif
是什么意思呢?
其实当我们在写大的工程项目的时候我们写的头文件可能被多次重复调用,在C语言中只要输入了#include指令,那么编译器将会把所包含的头文件全部拷贝到程序源代码中,为了避免这种情况我们可以在头文件中使用#ifndef指令
#ifndef 标识符(这里是__ADD_H__)
ifndef的全称为:if not define 翻译过来也就是如果未定义,利用这个语句来检测程序源文件中是否重复包含了这个头文件
接上代码
#define 标识符(这里是__ADD_H__)
如果编译器检测到这是源文件中第一次调用这个头文件则会执行这个代码,进行定义,如果重复包含该头文件了则不会执行头文件中的内容,直接跳转到
#endif
#endif也就是结束语句,这样以后我们就可以防止头文件被重复的包含,造成不必要的麻烦了
二.函数的递归
1.什么是递归?
程序调用自身的编程技巧称为递归。递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量,递归的主要思考方式在于:将大事化小
2.递归的条件
存在限制条件,当条件满足的时候递归则不再继续
每次调用递归后需要越来越接近这个限制条件
我们来看一个最简单的递归程序:
#include<stdio.h>
int main(void){
printf("hello\n");
main();
return 0;
}
我们写了一个main()函数,然后在main()函数中调用自身,这时候我们运行程序就会进入一个死循环,不一会程序就会崩溃,编译器也会告警,如图所示:
告警提示框中报了这样一个错误:Stack Overflow,翻译过来就是栈溢出,这也是递归常见的一个错误,我们将内存大致分为三个区域,分别是:
栈区,堆区以及静态区,如图所示:
再回到我们代码,当程序进入main()函数中后首先调用printf()函数,之后内存会为程序在栈区开辟一块空间,之后会调用main()函数,再次调用printf()函数,而栈区是有大小限制的,当无数次调用后,栈区的空间就会干枯,这时候再向栈区申请空间就会导致栈溢出(Stack Overflow),如图所示:
同时,有一个网站的网址也为Stack Overflow,访问网站后我们可以在网站上询问他人一些编程问题,同时也可以帮助别人解决问题,网址:https://stackoverflow.com/
2023/8/15
王起舟