站长推荐入口自动跳转,建网站 主流软件,小程序店铺怎么开,跨越网站建设科技有限公司大家好啊#xff0c;我是小象٩(๑ω๑)۶ 我的博客#xff1a;Xiao Xiangζั͡ޓއއ 很高兴见到大家#xff0c;希望能够和大家一起交流学习#xff0c;共同进步。 这一节我们主要来学习单个函数的声明与定义#xff0c;static和extern… 这里写目录标题 一、单个函数… 大家好啊我是小象٩(๑òωó๑)۶ 我的博客Xiao Xiangζั͡ޓއއ 很高兴见到大家希望能够和大家一起交流学习共同进步。 这一节我们主要来学习单个函数的声明与定义static和extern… 这里写目录标题 一、单个函数的声明与定义1.1 单个文件1.2 多个文件 二、static和extern2.1 作用域和生命周期2.2 static2.3 static修饰局部变量2.4 static修饰全局变量extern声明外部符号2.5 static修饰函数 三、结尾 一、单个函数的声明与定义
1.1 单个文件
一般我们在使用函数的时候直接将函数写出来就使用了。 咱们举之前练习过的一个例子来看比如写一个函数判断一年是否是闰年。
#includestdio.h
int pan_duan_run_nian(int x)
{if ((x % 4 0) (x % 100 ! 0) || (x % 400 0))return 1;elsereturn 0;
}int main()
{int year 0;scanf(%d, year);int a pan_duan_run_nian(year);if (a 1){printf(%d为闰年, year);}else{printf(%d不是闰年);}return 0;
}在这个代码中这一部分代表的是**函数的定义** 关于函数的定义 在C语言中函数定义是编程中的一个核心概念它允许你将代码组织成可重用和可维护的模块。函数定义的作用主要包括以下几个方面 1、代码重用通过定义函数你可以避免在多个地方重复编写相同的代码。当你需要在程序中多次执行某个任务时只需调用定义好的函数即可从而提高了代码的重用性。 2、模块化编程 函数将程序划分为多个逻辑模块每个模块负责完成特定的任务。这种结构化的编程方式使得程序更易于理解和维护。 3、提高可读性将复杂的程序逻辑分解为多个函数每个函数都有明确的目的这可以提高代码的可读性。阅读和理解一个由多个简单函数组成的程序比阅读一个包含大量复杂逻辑的单体程序要容易得多。 4、便于调试 模块化编程使得在程序出现问题时更容易定位错误。你可以单独测试每个函数确定哪个函数存在错误从而减少了调试的复杂性。 5、增强代码的可维护性 当需要修改程序时只需修改相关的函数而不需要在整个程序中搜索和修改代码。这大大简化了维护过程降低了维护成本。 6、促进代码协作在大型项目中多个开发人员可以独立地编写和测试各自的函数。通过定义清晰的函数接口开发人员可以协同工作确保代码的正确性和一致性。 7、实现递归后面会学 函数定义允许函数自身调用自身递归这是解决某些类型问题如排序、搜索等的有效方法。 #includestdio.h
int pan_duan_run_nian(int x)
{if ((x % 4 0) (x % 100 ! 0) || (x % 400 0))return 1;elsereturn 0;
}而这一部分代表着**函数的调用**
int a pan_duan_run_nian(year);然后如果我们把函数的定义放在函数调用的后面像这样
int main()
{int year 0;scanf(%d, year);int a pan_duan_run_nian(year);if (a 1){printf(%d为闰年, year);}else{printf(%d不是闰年);}return 0;
}#includestdio.h
int pan_duan_run_nian(int x)
{if ((x % 4 0) (x % 100 ! 0) || (x % 400 0))return 1;elsereturn 0;
}这个代码在VS2022上编译会出现下面的警告信息 这是因为C语言编译器对源代码进行编译的时候第一行往下扫描的当遇到pan_duan_run_nian函数调用的时候并没有发现前面有pan_duan_run_nian的定义就报出了上述的警告。 把怎么解决这个问题呢就是函数调用之前先声明一下pan_duan_run_nian这个函数声明函数只要交代清楚函数名函数的返回类型和函数的参数。 如pan_duan_run_nian(int x)这就是函数声明在C语言中函数声明Function Declaration 是 告诉编译器有关函数的存在、其返回类型、函数名以及参数类型和数量的声明 。函数声明通常位于函数定义之前或在其他文件中以便编译器在函数调用之前知道函数的签名即函数的接口。函数声明中参数只保留类型省略掉名字也是可以的。 函数声明的作用 1、提前通知编译器编译器在编译代码时需要知道函数的签名以便在函数调用时进行类型检查。函数声明提供了这一信息使得编译器可以在函数实际定义之前进行编译。 2、避免链接错误在多个文件的项目中函数声明允许编译器在编译单独的源文件时知道其他文件中定义的函数的存在。这样链接器Linker可以在链接阶段找到这些函数的实际定义。 3、提高代码可读性函数声明提供了函数的接口信息有助于其他程序员理解如何使用该函数。 所以我们给上面的函数加上声明就会变成下面这样
pan_duan_run_nian(int x);#includestdio.h
int main()
{int year 0;scanf(%d, year);int a pan_duan_run_nian(year);if (a 1){printf(%d为闰年, year);}else{printf(%d不是闰年);}return 0;
}int pan_duan_run_nian(int x)
{if ((x % 4 0) (x % 100 ! 0) || (x % 400 0))return 1;elsereturn 0;
}结果便正常了 函数的调用一定要满足先声明后使用 函数的定义也是一种特殊的声明所以如果函数定义放在调用之前也是可以的。
1.2 多个文件
一般在企业中我们写代码时候代码可能比较多不会将所有的代码都放在⼀个文件中我们往往会根据程序的功能将代码拆分放在多个文件中也就是模块化处理。 注意虽然一个工程会有多个文件但main函数只能有一个 ⼀般情况下函数的声明、类型的声明放在头文件.h中函数的实现是放在源文件.c文件中。
我们来举个例子我们用test.c来调用其它模块代码进行测试我们用leap.h和leap.c分别来对于函数的声明和函数的定义
像这样分别创建test.c和leap.c源文件leap.h头文件 我们来举一个加法的例子 我们先来看函数测试的雏形
#includestdio.h
#includeleap.h //你的头文件是leap.h
int main()
{int a 0;int b 0;scanf(%d %d, a, b);int c add(a, b);printf(%d, c);return 0;
}我们把它放在test.c中 这里我们要注意要把leap.h头文件也包含进去#includeleap.h
接着我们看函数的声明
int add(int x, int y);//函数的声明我们把它放在leap.h头文件中
最后是函数的定义
int add(int x, int y)//函数的定义
{int d x y;return d;
}我们把它放在leap.c的源文件中
这样我们就写完了运行看看结果 没有问题
二、static和extern
static 和 extern 都是C语言中的关键字。
2.1 作用域和生命周期
**作用域scope**是程序设计概念通常来说一段程序代码中所用到的名字并不总是有效可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。 局部变量的作用域是变量所在的局部范围。全局变量的作用域是整个工程项目。 生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段。 局部变量的生命周期是进入作用域变量创建生命周期开始出作用域生命周期结束。全局变量的生命周期是整个程序的生命周期就是程序从开始运行到结束。 2.2 static
在C语言中static关键字有多种用途其中之一是用于修饰函数。当static关键字用于函数声明时它改变了函数的链接属性linkage。 static函数的特点 1、内部链接Internal Linkage 当一个函数被声明为static时它的链接属性变为内部链接。这意味着该函数只能在声明它的源文件.c文件内部被访问。其他源文件无法直接调用这个函数即使这些文件包含了该函数的声明。 这有助于封装和隐藏实现细节防止其他文件直接访问和修改。 2、避免命名冲突 由于static函数只能在其所在的文件内部被访问因此不同源文件中的同名static函数不会引起命名冲突。 这允许开发者在不同的源文件中使用相同名称的函数而无需担心命名冲突。 3、生命周期 static关键字对函数的生命周期没有影响。函数的生命周期总是从程序开始执行到程序结束。static关键字仅影响函数的链接属性即函数的可见性。 static 是 静态的 的意思可以用来 • 修饰局部变量 • 修饰全局变量 • 修饰函数
2.3 static修饰局部变量
我们先来看个例子
#includestdio.h
void test()
{int i 0;i;printf(%d, i);
}int main()
{int i 0;for (i 0; i 5; i){test();}return 0;
}结果是这样的 如果我们这样改
#includestdio.h
void test()
{static int i 0;i;printf(%d, i);
}int main()
{int i 0;for (i 0; i 5; i){test();}return 0;
}结果就会变成这样 我们来对比代码1和代码2的效果 代码1的test函数中的局部变量i是每次进入test函数先创建变量生命周期开始并赋值为0然后再打印出函数的时候变量生命周期将要结束释放内存。 代码2中我们从输出结果来看i的值有累加的效果其实test函数中的i创建好后出函数的时候是不会销毁的重新进入函数也就不会重新创建变量直接上次累积的数值继续计算。 结论static修饰局部变量改变了变量的生命周期被static修饰后生命周期会变长生命周期改变的本质是改变了变量的存储类型本来一个局部变量是存储在内存的栈区的但是被 static 修饰后存储到了静态区。 存储在静态区的变量和全局变量是⼀样的生命周期就和程序的生命周期⼀样了只有程序结束变量才销毁内存才回收。但是作用域不变的。
使用建议未来一个变量出了函数后我们还想保留值等下次进入函数继续使用就可以使用static修饰。
2.4 static修饰全局变量extern声明外部符号 extern 是用来声明外部符号的如果一个全局的符号在A文件中定义的在B文件中想使用就可以使用 extern 进行声明然后使用。 我们首先创建两个源文件然后我们在其中一个源文件创建一个变量然后另一个源文件用extern声明一下像下面的做法一样
int xiaofeixiang 666;#includestdio.h
int main()
{extern int xiaofeixiang;//声明一下printf(%d, xiaofeixiang);return 0;}我们运行看看结果 运行一切正常
如果我们这个时候在变量旁边添加static的话
static int xiaofeixiang 666;这个时候我们如果运行的话就会发现运行错误 结论 static相当于改变作用域一个全局变量被static修饰使得这个全局变量只能在本源文件内使用不能在其他源文件内使用。 本质原因是**全局变量默认是具有外部链接属性的**在外部的文件中想使用只要适当的声明就可以使用但是全局变量被 static 修饰之后外部链接属性就变成了内部链接属性 只能在自己所在的源文件内部使用了其他源文件即使声明了也是无法正常使用的。 使用建议如果一个全局变量只想在所在的源文件内部使用不想被其他文件发现就可以使用static修饰。 2.5 static修饰函数
直接来个例子
int add(int x, int y)
{return x y;
}#includestdio.h
extern int add(int x, int y);
int main()
{int a 0;int b 0;scanf(%d %d, a, b);int c add(a,b);//声明一下printf(%d,c );return 0;}这里的extern是指声明外部函数的作用 我们运行一下结果没有问题 如果我们在函数前面加上static的话会发生什么呢我们来看看
static int add(int x,int y);看看结果直接就报错了 其实 static 修饰函数和 static 修饰全局变量是一模一样的一个函数在整个工程都可以使用被static修饰后只能在本文件内部使用其他文件无法正常的链接使用了。 本质是因为 函数默认是具有外部链接属性具有外部链接属性使得函数在整个工程中只要适当的声明就可以被使用。但是 被 static 修饰后变成了内部链接属性使得函数只能在自己所在源文件内部使用。 使用建议一个函数只想在所在的源文件内部使用不想被其他源文件使用就可以使用 static 修饰。 三、结尾
这一课的内容就到这里了下节课继续学习递归的其他一些知识 如果内容有什么问题的话欢迎指正有什么问题也可以问我