当前位置: 首页 > news >正文

C语言——深入理解函数声明定义和调用访问


🏡润下:个人主页

  🔥个人专栏: 《C语言基础》

🏔️山高万仞,只登一步!

在这里插入图片描述在这里插入图片描述

文章目录

  • 一.嵌套调用
  • 二. 链式访问
  • 三.函数的声明和定义
    • 3.1 单个文件
    • 3.2 多个文件
    • 3.3 static和extern
      • 3.3.1 作用域和生命周期
      • 3.3.2 static修饰局部变量
      • 3.3.3 static修饰全局变量
      • 3.3.4 static修饰函数
  • 四. 练习

前面我分享了函数的一些基本概念以及易混淆点,但函数最重要的是如何调用和实现,接下来我将分享一些实例,更进一步理解函数的运用!

上篇函数介绍点击下方链接
C语言——函数(超详细分析)

一.嵌套调用

嵌套调用时函数之间的相互调用,我们可以把函数间的调用类比成用乐高零件拼玩具,每个函数就像是一个乐高零件,只不过这种零件可以重复使用,一个个函数 “堆积“ 成一个大的程序。
:计算某年某月多少天,可以定义两个函数

is_leap_year() 根据年份确定是否是闰年
get_day_of_year() 调用is_leap_year(),再计算每月天数

 int is_leap_year(int y)
{if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))return 1;elsereturn 0;
}
int get_days_of_year(int y, int m)
{int days[] = {0, 31,28,31,30,31,30 ,31,31,30,31,30,31 };//  0  1  2  3  4  5   6  7  8  9  10  11  12int day = days[m];if (is_leap_year(y) && m==2)day += 1;return day;
}
int main()
{int y = 0;int m = 0;scanf("%d %d", &y, &m);int d=get_days_of_year(y,m);printf("%d\n", d);return 0;
}

调用的scanf,printf,get_days_of_year
get_days_of_year调用的is_leap_year都是嵌套调用
但是函数不能嵌套定义

二. 链式访问

链式访问就是把函数的返回值最为另外一个函数的参数,这样像链条一样把函数串起来就是函数的链式访问

#include<stdio.h>
int main()
{int len = strlen("abcdefg");printf("%zu\n", len);return 0;
}

如果直接把上述代码中strlen的返回值作为函数的参数,这样就是链式访问
没有中间商赚差价😆

#include<stdio.h>
int main()
{printf("%zu\n", strlen("abcdefg"));return 0;
}

一个有趣的例子:

#include<stdio.h>
int main()
{printf("%d", printf("%d", printf("%d", 43)));return 0;
}

可以预测一下这段代码打印输出的结果
在这里插入图片描述
首先了解printf函数的返回值是什么
在这里插入图片描述
返回打印在屏幕上字符的个数
第三个printf函数打印43,屏幕上打印2字符返回值2;
第二个printf函数打印2,屏幕上打印1字符返回值1;
第一个printf函数打印1
最终打印4321


#include<stdio.h>
int main()
{printf("%d ", printf("%d ", printf("%d ", 43)));return 0;
}

这段代码打印多少可以猜测一下

三.函数的声明和定义

3.1 单个文件

一般我们使用函数的时候直接就可以使用
例:假如我们写一个函数判断是否是闰年

int test(int y)
{if (((y%4==0)&&(y%100!=0))||(y%400==0)){return 1;}else{return 0;}
}
int main()
{int y = 0;scanf("%d", &y);test(y);if (y==1){printf("是闰年\n");}else {printf("不是闰年\n");}return 0;
}

上面test()部分包括下面的函数体是函数的定义,test(y)是函数的调用
这样正常的写没事,但是把函数的定义放在调用的后面就会出现警告

int main()
{int y = 0;scanf("%d", &y);test(y);if (y==1){printf("是闰年\n");}else {printf("不是闰年\n");}return 0;
}
int test(int y)
{if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)){return 1;}else{return 0;}
}

在这里插入图片描述
因此我们要在函数调用前先进行声明
即:
函数要满足先声明再使用,函数的定义也是一种特殊的声明,所以函数定义放在调用之前是可以的

声明格式
int test (int )
1.有返回类型
2.参数的个数和类型
3.要有函数名,参数名可以省略

3.2 多个文件

但是在实际生活中写代码数量很大,因此会把代码都放在多个文件中,根据所写程序的功能和特点进行分类。

方便模块化编程
方便协作

函数的声明,类型的声明放在头文件.h中,函数的实现文件放在.c文件中

add.h

int Add(int x, int y);

add.c

int Add(int x, int y)
{return x + y;
}

test.c

#include<stdio.h>
#include"add.h"
int main()
{int a = 10;int b = 20;int c = Add(a, b);printf("%d\n", c);return 0;
}

在这里插入图片描述

3.3 static和extern

static和extern 都是C语言中的关键字
static是修饰静态变量,可以用来:

修饰局部变量
修饰全局变量
修饰函数

extern 是用来声明外部符号
外部符号可以是全局变量函数
在这里插入图片描述

3.3.1 作用域和生命周期

作用域:是程序设计的概念,一段代码中所用到的名字并不总是有效的,这个名字有效的范围就是作用域 即:可以使用的范围
1.局部变量作用域:变量所在的局部范围
2.全局变量的作用域是整的工程(项目)
例1

在这里插入图片描述
例2
在这里插入图片描述
**生命周期:**是指变量的创建(申请内存)到变量的销毁(收回内存)的一个时间段
1.局部变量的生命周期是:进入作用域变量创建生命周期开始,出作用域生命周期结束
2.全局变量的生命周期是:整个程序的生命周期(main函数的生命周期)

3.3.2 static修饰局部变量

两个例子了解static的作用

void test()
{int i = 0;i++;printf("%d\n", i);
}
int main()
{int i = 0;for ( i = 0; i < 5; i++){test();}return 0;
}
void test()
{static int i = 0;i++;printf("%d\n", i);
}
int main()
{int i = 0;for ( i = 0; i < 5; i++){test();}return 0;
}

结果
在这里插入图片描述
static修饰局部变量改变了变量的生命周期 加static之后出函数的时候是不会销毁的,重新进入函数也不会创建新的变量,直接上次累加的值进行计算

3.3.3 static修饰全局变量

在这里插入图片描述
全局变量具有外部连接属性,static修饰之后变成内部连接属性,不能被其他文件访问

3.3.4 static修饰函数

在这里插入图片描述
函数同样具有外部连接属性,static修饰之后变成内部连接属性,不能被其他文件访问

static 会把具有外部链接属性的全局变量和函数,变成内部连接属性只能被本身源文件使用,如果不想被其他文件发现就可以使用static修饰

static改变了具有局部变量的存储类型由栈区改为了静态区,局部变量就和全局变量一样,出这个作用域不会销毁等到下次进入函数再次使用。
在这里插入图片描述

四. 练习

创建一个整形数组,完成对数组的操作
实现函数init() 初始化数组为全0
实现print() 打印数组的每个元素
实现reverse() 函数完成数组元素的逆置。

void Init(int arr[], int sz, int set)
{int i = 0;for (i = 0; i < sz; i++){arr[i] = set;}
}void Print(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}
void Reverse(int arr[], int sz)
{int left = 0;int right = sz - 1;while (left < right){int tmp = arr[left];arr[left] = arr[right];arr[right] = tmp;left++;right--;}
}
int main()
{int arry[] = { 0,1,2,3,4,5,6,7,8,9 };int sz = sizeof(arry) / sizeof(arry[0]);Print(arry, sz);Reverse(arry, sz);Print(arry, sz);Init(arry, sz, 0);Print(arry, sz);return 0;
}
http://www.dtcms.com/a/423113.html

相关文章:

  • 网站开发大约多少钱制作一个网站的步骤是什么
  • RabbitMQ (一)简单模式
  • 阿里巴巴 Java 开发手册 v1.2.0
  • Leetcode+Java+单调栈
  • Word和WPS文字如何从特定的页开始编号(页码)?
  • EDSR模型
  • thinkphp做中英文网站网站跟app区别
  • 6. 数据库设计基础知识
  • 【nginx平滑升级演示】
  • 桥梁缺陷检测数据集:腐蚀、剥落、渗透等5类,3k+图像,yolo标注
  • 上交提出单图生成3D场景方法SceneGen:单图输入,多资源输出,3D 合成性能飙升的“秘密武器”!
  • 百度验证网站济南网络科技公司
  • NO5.硼:火箭专家
  • 细化处理refinement process
  • 第四部分:VTK常用类详解(第120章 vtkWarpTo变形到类)
  • Day01_Linux移植基础
  • 工控网做网站维护吗免费网站建站申请
  • kcwebplus可视化框架
  • JVM如何管理直接内存?
  • 【完整源码+数据集+部署教程】医疗设备显示器图像分割系统: yolov8-seg-C2f-SCConv
  • PyCharm项目依赖库的备份与还原方法
  • OpenSSL 3.0对某些加密算法增加了限制
  • git fatal:Server aborted the SSL handshake
  • 深入理解 Python `ssl` 库:安全通信的基石
  • 江门网页建站模板临沂网站建设费用
  • 网站手机模板和pc模板要分开做网站首页需求
  • 国内 huggingfaces 仓下载
  • 基因组学发展史
  • 论文阅读(第4章,page55)
  • java设计模式:适配器模式