第一次学c语言系列之——函数补充!!!

一、函数的声明

(1)什么是函数的声明

告诉编译器函数返回类型、函数名、参数。

(2)单个文件的声明

当你的自定义函数写在main函数之前时,则编译器会默认你已经声明过了;

当你的自定义函数写在main函数之后时,则需要在main函数之前进行声明。

cpp 复制代码
//函数在单个文件中的声明
int Add(int a, int b);//自定义函数在main函数之后,需要声明
int main() {
	int ret = Add(3, 5);
	printf("%d\n",ret);
}

int Add(int a, int b) {
	return a + b;
}

(2)多个文件的声明

①使用

创建3个文件,一个.c文件用来写你的主代码块;一个.c文件用来写你的函数实现;一个.h文件用来存放你的函数声明。(使用时要包含你的自定义头文件)

cpp 复制代码
//主函数部分  test.c
#include <stdio.h>
#include "calc.h"
int main() {
	printf("%d\n", Add(9, 3));
	printf("%d\n", Sub(9, 3));
	printf("%d\n", Mul(9, 3));
	printf("%d\n", Div(9, 3));
}
//函数实现部分  calc.h
int Add(int a, int b) {
	return a + b;
}

int Sub(int a, int b) {
	return a - b;
}

int Mul(int a, int b) {
	return a * b;
}

int Div(int a, int b) {
	return a / b;
}
//函数声明部分  calc.h
int Add(int a, int b);
int Sub(int a, int b);
int Mul(int a, int b);
int Div(int a, int b);

②好处

逻辑清晰;方便多人协作。

二、static和extern

关键字之一,并不是函数,不需要包含头文件。

static用于延长生命周期(修饰局部变量时,由函数栈帧范围延长为整个程序),收窄作用域(修饰函数和全局变量时,由多个文件收窄到当前文件)。

extren用于声明外部符号。

(1)作用域

限定变量的可用范围。

cpp 复制代码
#include <stdio.h>
int main() {
	{
		int a = 3;
		printf("%d\n", a);//代码正常执行,a的使用范围在这个大括号内
	}
	printf("%d\n", a);//代码无法执行,超出了a的作用域,无法使用
}

(2)生命周期

变量从创建(申请内存)到销毁(收回内存)的过程。

(3)内存划分图

(4)static修饰局部变量

static修饰的局部变量存储在静态区,改变了局部变量的生命周期,程序运行结束,局部变量的声明周期才结束,但是作用域不发生变化。

cpp 复制代码
void test() {
	static int i = 0;//仅在第一次使用test函数时执行这一行
	i++;
	printf("%d ",i);
}

#include <stdio.h>
int main() {
	for (int i = 0; i < 5; i++)
		test();//打印 1 2 3 4 5
}

(5)extern声明全局变量

cpp 复制代码
//testo1.c
int a = 18;

//test02.c
//extern
extern a;
#include <stdio.h>
int main() {
	printf("%d\n", a);//extern声明外部符号a后,a就可以正常使用了
}

(6)static修饰全局变量

使全局变量失去外部链接性。

cpp 复制代码
//test01.c
static int a = 18;
//static修饰后,这个文件里的全局变量就失去了外部链接属性,只能在这个文件里使用

//test02.c
extern a;
#include <stdio.h>
int main() {
	printf("%d\n", a);//全局变量a被static修饰了,即使声明也不能再次使用了
}

(7)extern声明函数

cpp 复制代码
//test01.c
int Add(int a, int b) {
	return a + b;
}
//test02.c
extern Add(int a, int b);
#include <stdio.h>
int main() {
	printf("%d\n", Add(2,3));//声明外部函数后,可以正常使用
}

(8)static声明函数

使函数失去外部链接属性。

cpp 复制代码
//testo1.c
static int Add(int a, int b) {
	return a + b;
}
//test02.c
extern Add(int a, int b);
#include <stdio.h>
int main() {
	printf("%d\n", Add(2,3));//static修饰的外部函数,已经失去了外部链接属性
}

三、函数栈帧

(1)内存

①定义

内存(RAM)就是用来存储临时数据的硬件,对于数据而言是一片空间。

②构成

栈区:函数栈帧(局部变量、函数参数、返回地址)、寄存器(例如ebp:基址指针寄存器,存放指向当前函数栈帧栈底的指针;esp:栈指针寄存器,存放指向当前函数栈帧栈顶的指针)

堆区:动态分配的内存(malloc/calloc/realloc申请的空间)

静态区:全局变量、static修饰的变量

常量区:字符串常量

代码区:程序的二进制指令

(2)寄存器

寄存器其实也是一片空间,用来临时存储cpu正在运算的数据。

(3)函数栈帧的创建和销毁过程

栈帧创建:把返回地址和旧栈底存起来,用两个寄存器定好当前栈帧的头尾,腾出空间放局部变量。

栈帧销毁:把计算结果存好,恢复之前的栈底和栈顶位置,跳回原来的函数继续执行,当前函数的栈帧随之销毁。


相关推荐
小花2 小时前
java后端框架之spring
java·开发语言·spring
一条大祥脚2 小时前
势能分析与势能线段树
开发语言·javascript·数据结构·算法
chao1898442 小时前
基于字典缩放的属性散射中心参数提取算法与MATLAB实现
开发语言·算法·matlab
小尧嵌入式2 小时前
【Linux开发四】Linux中概念|MobaXterm和Filezilla软件使用|线程|互斥锁|读写锁
linux·运维·服务器·开发语言·数据结构
a努力。2 小时前
Spring Boot 4 全面拥抱 Jackson 3
java·运维·开发语言·spring boot·后端·spring·jenkins
晚霞的不甘2 小时前
Flutter for OpenHarmony 布局探秘:从理论到实战构建交互式组件讲解应用
开发语言·前端·flutter·正则表达式·前端框架·firefox·鸿蒙
爱吃大芒果2 小时前
Flutter for OpenHarmony核心组件学习: MaterialApp、Scaffold 两大基础组件以及有无状态组件
开发语言·学习·flutter
做科研的周师兄2 小时前
【MATLAB 实战】栅格数据一元线性回归计算(NDVI 趋势分析)| 附完整可运行代码
开发语言·matlab·线性回归
fengfuyao9852 小时前
基于MATLAB的量子图像加密实现
开发语言·matlab·量子计算