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

C语言入门(十一)续:函数的深入认识

一:嵌套调用和链式访问

1.嵌套调用

嵌套调⽤就是函数之间的互相调⽤,每个函数就像⼀个乐⾼零件,正是因为多个乐⾼的零件互相⽆缝 的配合才能搭建出精美的乐⾼玩具,也正是因为函数之间有效的互相调⽤,最后写出来了相对⼤型的 程序。

问题:计算某年某月有多少天,例如2008年8月,它共有多少天(分闰年和平年)

部分代码如下:

int is_leap_year(int year)//判断函数,这里的return后面的数,只表示真假意义,C语言一般规定0为假,非0为真
{if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))//计算  闰年 return 1;//是闰年则返回1elsereturn 0;//不是闰年则返回0
}

判断函数,这里的return后面的数,只表示真假意义,C语言一般规定0为假,非0为真

int   is_leap_year(int year)                                                                                                        return 1;

return 0;

计算闰年的方法

if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))

部分代码如下:


int get_days_of_month(int year, int month)
{                    //这里的参数可以和get那一串函数括号里面的不一样,不影响我们int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31, };//1-12月对应的天数int day = days[month];if (is_leap_year(year) && month == 2)day += 1;return day;
}

下面的代码是计算函数,return后面的数,只表示返回具体的天数(计算结果),这里返回值是day即我们需要的那个天数,如果是0那就没有意义了

int get_days_of_month(int year, int month)

return day;

如果是闰年则2月的天数加1  即29天

day += 1

1-12月对应的天数,因为下标是从0开始的,所以这里我们故意加个0进去,一一对应起来

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  1 0 11 12  月

利用下标来找某月所对应的天数,如果我们的month的下标是5,那么对应的就是5月,31天

int day = days[month];

计算是闰年的情况即2月是29天

if (is_leap_year(year) && month == 2)

主函数代码如下:

int main()
{int year = 0;int month = 0;scanf("%d %d", &year, &month);//输入 年 月int days = 	get_days_of_month(year,month);//获取某月的天数   printf("%d\n", days);//将天数打印出来return 0;
}

获取某月的天数

注意:这里用 _ 是因为函数名字中间不能用空格,如果不用空格让它们贴在一起虽然可以,但是不好看,这个()里面的代码是将year month 传给int get_days_of_month那一串函数里面去,然后算出我们的天数,然后我们将天数存入int days 里面去

int days =   get_days_of_month(year,month);

完整代码如下:

int is_leap_year(int year)//判断函数,这里的return后面的数,只表示真假意义,C语言一般规定0为假,非0为真
{if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))//计算  闰年 return 1;//是闰年则返回1elsereturn 0;//不是闰年则返回0
}
//
//下面的代码是计算函数,return后面的数,只表示返回具体的天数(计算结果)
int get_days_of_month(int year, int month)//由于我们计算的是天数,所以我们的返回函数类型是 int 整型
{                      //这里的参数可以和下面get那一串函数括号里面的不一样,不影响我们int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31, };//1-12月对应的天数
//	   下标     0  1  2   3  4  5  6  7  8  9  10 11 12月  因为下标是从0开始的,所以这里我们故意加个0进去,一一对应起来int day = days[month];//利用下标来找某月所对应的天数,如果我们的month的下标是5,那么对应的就是5月,31天if (is_leap_year(year) && month == 2)//计算是闰年的情况即2月是29天day += 1;//如果是闰年则2月的天数加1  即29天return day;//这里返回值是day 即我们需要的那个天数,如果是0那就没有意义了
}
//
// 
int main()
{int year = 0;int month = 0;scanf("%d %d", &year, &month);//输入 年 月int days = 	get_days_of_month(year,month);//获取某月的天数   //    这里用 _ 是因为函数名字中间不能用空格,如果不用空格让它们贴在一起虽然可以,但是不好看   
//	上面这个()里面的代码是将year month 传给int get_days_of_month那一串函数里面去,然后算出我们的天数
//    然后我们将天数存入int days 里面去printf("%d\n", days);//将天数打印出来return 0;
}

闰年的输出结果:

平年的输出结果:

2.链式访问

所谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数 的链式访问。

代码如下:

普通的计算字符长度

#include<string.h>//strlen函数需要的头文件
int main()
{int len = strlen("abcdef");//计算字符长度并将它存放到len里面去printf("%d\n", len);//将字符长度打印出来return 0;
}

strlen函数需要的头文件

#include<string.h>

输出结果:

前⾯的代码完成动作写了2条语句,把如果把strlen的返回值直接作为printf函数的参数呢?这样就是⼀ 个链式访问的例⼦了。

利用链式访问,计算出字符长度

代码如下:

int main()
{printf("%d\n", strlen("abcdef") );return 0;
}

输出结果:

练习:下面代码的输出结果是什么?

代码如下:

int main()
{printf("%d\n", printf("%d", printf("%d", 43) )   );printf("%d", printf("%d ", printf("%d ", 43) )   );return 0;
}

第一个:输出4321

原因:里面的先执行,将每一步的返回值慢慢的往外

printf函数返回的是打印在屏幕上的字符的个数。 上⾯的例⼦中,我们就第⼀个printf打印的是第⼆个printf的返回值,第⼆个printf打印的是第三个 printf的返回值。 第三个printf打印43,在屏幕上打印2个字符,再返回2 第⼆个printf打印2,在屏幕上打印1个字符,再放回1 第⼀个printf打印1 所以屏幕上最终打印:4321

printf("%d\n", printf("%d", printf("%d", 43) )   );

输出结果:

第二个:输出43 3 2

原因:这里我们会先打印出43 是2个字符,然后有1个空格,总共3个字符于是它的返回值是3并且返回到第二个printf里面去,于是打印出3  它是1个字符,然后后面还有一个空格,于是它是2个字符,同样返回值是2返回到第一个printf里面去,于是打印出2

注意:空格也算一个字符

    printf("%d", printf("%d ", printf("%d ", 43) )   );

输出结果:

二:函数的声明和定义

1.单个⽂件

  • 函数的定义

问题:判断一年是否是闰年

部分代码如下:


函数定义(main函数以上的代码)
int is_leap_year(int year)
{if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))//计算闰年{return 1;//是闰年则返回值为1}else{return 0;//不是闰年则返回值为0}return 0;
}

计算闰年的方法:

if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))

主函数代码如下:


int main()
{int year = 0;scanf("%d", &year);//输出年份int r = is_leap_year(year);//通过调用函数is_leap_year(year);将返回值穿到int r里面去if (r == 1){printf("闰年\n");}else{printf("非闰年\n");}return 0;
}

通过调用函数is_leap_year(year); 将返回值穿到int r里面去

int r = is_leap_year(year);

完整代码如下:

int is_leap_year(int year)
{if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))//计算闰年{return 1;//是闰年则返回值为1}else{return 0;//不是闰年则返回值为0}return 0;
}int main()
{int year = 0;scanf("%d", &year);//输出年份int r = is_leap_year(year);//通过调用函数is_leap_year(year);将返回值穿到int r里面去if (r == 1){printf("闰年\n");}else{printf("非闰年\n");}return 0;
}

非闰年的输出结果:

闰年的输出结果:

如果我们将定义函数和主函数main的位置进行调换,主函数在前面,定义函数在后面,那么我们的结果是什么呢?

答案是:编译器会出现警告,会报错误的

原因:这是因为C语⾔编译器对源代码进⾏编译的时候,从第⼀⾏往下扫描的,当遇到第7⾏的 函数调⽤的时候,并没有发现前⾯有 is_leap_year的定义,就报出了上述的警告。 

  • 函数的声明

函数的调⽤⼀定要满⾜,先声明后使⽤

怎么把怎么解决这个问题呢?就是函数调⽤之前先声明⼀下 is_leap_year is_leap_year这个函数,声明函数只要交代清 楚:函数名,函数的返回类型和函数的参数。 如: int is_leap_year(int y);这就是函数声明,函数声明中参数只保留类型,省略掉名字也是可以 的

声明后的完整代码如下:

int is_leap_year(int year);//有了它我们就可以将main函数与int is_leap_year(int year)函数调换位置,否则我们只能将main函数写在后面int main()
{int year = 0;scanf("%d", &year);//输出年份int r = is_leap_year(year);//通过调用函数is_leap_year(year);将返回值穿到int r里面去if (r == 1){printf("闰年\n");}else{printf("非闰年\n");}return 0;
}int is_leap_year(int year)
{if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))//计算闰年{return 1;//是闰年则返回值为1}else{return 0;//不是闰年则返回值为0}return 0;
}

在最前面有了它我们就可以将main函数与int is_leap_year(int year)函数调换位置,否则我们只能将main函数写在后面

int is_leap_year(int year);

2.多个文件

⼀般在企业中我们写代码时候,代码可能⽐较多,不会将所有的代码都放在⼀个⽂件中;我们往往会 根据程序的功能,将代码拆分放在多个⽂件中。

⼀般情况下,函数的声明、类型的声明放在头⽂件(.h)中,函数的实现是放在源⽂件(.c)⽂件中。 如下:

add.c(我们自己要再创建一个文件)


函数的定义
int Add(int x, int y){return x+y;}

add.h(我们自己要再创建一个文件)


函数的声明int Add(int x, int 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;}

有了函数声明和函数定义的理解,我们写代码就更加⽅便了。

结果如下:

三:static 和extern

static 和 extern 都是C语⾔中的关键字。

static 是 静态的的意思,可以⽤来:

• 修饰局部变量

• 修饰全局变量 比特就业课

• 修饰函数

extern 是⽤来声明外部符号的。

在讲解 static 和 extern 之前再讲⼀下:作⽤域和⽣命周期。 作⽤域(scope)是程序设计概念,通常来说,⼀段程序代码中所⽤到的名字并不总是有效(可⽤) 的,⽽限定这个名字的可⽤性的代码范围就是这个名字的作⽤域。 1. 局部变量的作⽤域是变量所在的局部范围。 2. 全局变量的作⽤域是整个⼯程(项⽬)。 ⽣命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。 1. 局部变量的⽣命周期是:进⼊作⽤域变量创建,⽣命周期开始,出作⽤域⽣命周期结束。 2. 全局变量的⽣命周期是:整个程序的⽣命周期。

  • static 修饰局部变量:

代码1如下


#include <stdio.h>void test(){int i = 0;i++;printf("%d ", i);}int main(){int i = 0;for(i=0; i<5; i++){test();}return 0;}

代码2如下:


#include <stdio.h>void test(){//static
修饰局部变量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和代码2的效果,理解 static 修饰局部变量的意义。

代码1的test函数中的局部变量i是每次进⼊test函数先创建变量(⽣命周期开始)并赋值为0,然后 ++,再打印出函数的时候,变量⽣命周期将要结束(释放内存)。

代码2中,我们从输出结果来看,i的值有累加的效果,其实test函数中的i创建好后,出函数的时候是 不会销毁的,重新进⼊函数也就不会重新创建变量,直接上次累积的数值继续计算。

  • static 修饰全局变量

代码如下

extern 是⽤来声明外部符号的,如果⼀个全局的符号在A⽂件中定义的,在B⽂件中想使⽤,就可以使用extern进⾏声明,然后使⽤

代码1正常,代码2在编译的时候会出现链接性错误。

结论: ⼀个全局变量被static修饰,使得这个全局变量只能在本源⽂件内使⽤,不能在其他源⽂件内使⽤。 本质原因是全局变量默认是具有外部链接属性的,在外部的⽂件中想使⽤,只要适当的声明就可以使 ⽤;但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性,只能在⾃⼰所在的源 ⽂件内部使⽤了,其他源⽂件,即使声明了,也是⽆法正常使⽤的。 使⽤建议:如果⼀个全局变量,只想在所在的源⽂件内部使⽤,不想被其他⽂件发现,就可以使⽤ static修饰。

  • static 修饰函数

代码1是能够正常运⾏的,但是代码2就出现了链接错误。 其实 static 修饰函数和 static 修饰全局变量是⼀模⼀样的,⼀个函数在整个⼯程都可以使⽤, 被static修饰后,只能在本⽂件内部使⽤,其他⽂件⽆法正常的链接使⽤了。 本质是因为函数默认是具有外部链接属性,具有外部链接属性,使得函数在整个⼯程中只要适当的声 明就可以被使⽤。但是被 static 修饰后变成了内部链接属性,使得函数只能在⾃⼰所在源⽂件内部 使⽤。

使⽤建议:⼀个函数只想在所在的源⽂件内部使⽤,不想被其他源⽂件使⽤,就可以使⽤static 修饰 

http://www.dtcms.com/a/499623.html

相关文章:

  • wordpress站点路径网上购物商城官网入口
  • 告别“手绘”图表:Illustrator与XD联动的数据可视化(Data Viz)工作流
  • m-card卡片组件
  • 企业内部网站建设方案怎样营销
  • 推荐一款开源的轻量级知识管理工具
  • GNU/Linux - GCC编译的静态库
  • 西安建网站哪家好企业网站蓝色模板下载
  • 成都模板建站代理网站优化要做哪些工作
  • Java MyBatis(一)--- 注解和XML的使用
  • 东莞官方网站 优帮云网站怎么做推广和优化
  • win64_11gR2_client.zip 怎么安装?Oracle 11g 客户端详细安装步骤
  • 建设向58同城的网站给客户做网站需要提供
  • flink sql 所有函数详细用例
  • Flink 1.20 flink-config.yml 配置详解
  • 湖州网站集约化平台南京做网站哪家公司好
  • 【深度学习新浪潮】2025全球机器学习技术大会:Agent技术突破与产业落地全景解析
  • 长沙整站优化梅河口信息网
  • Linux入门:动静态库的理解与加载
  • 云上救火指南:AWS常见服务告警的快速恢复与最小影响方案
  • 九号线香网站建设淘客网站后台怎么做
  • FPGA 入门 3 个月学习计划表
  • 专业的做网站网站做外链好嘛
  • ios android 小程序 蓝牙 CRC16_MODBUS
  • 沧州网站建设优化案例怎么创建一个网站
  • 【小沐杂货铺】基于Three.js渲染三维风力发电机(WebGL、vue、react、WindTurbine)
  • Socket 网络编程
  • 哪里可以做网站网站兼容性怎么解决
  • 网站备案流程实名认证哪个平台做网站好
  • 最版网站建设案例中国建设银行开户行查询
  • 衡水网站制作多少钱世界著名产品设计作品