C语言初阶(5)——函数

目录

1.函数的概念

2.形参和实参

3.return语句

4.数组的函数参数

5.嵌套调用和链式访问

5.1.嵌套调用

5.2.链式访问

6.函数的声明和定义

6.1单个文件

6.2.多个文件

6.3.static和extern

6.4.static修饰局部变量:

6.5.static修饰全局变量

6.6.static修饰函数


1.函数的概念

(1)C语言中的函数就是一个完成某项特定任务的一小段代码

(2)函数的功能:

1.可以拆分任务;

2.可以复用回归,提升开发效率;

(3)C语言中的两类函数:

1.库函数:现成可以直接使用的函数;

2.自定义函数:根据需要,自己设计和创造的函数;

ret_type fun_name(形式参数)
{    |        |
     |        |
函数返回类型 函数名 

}//被{}括起来的是函数体(描述的是函数完成任务的过程)

举例:Add函数:

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

(4)参数:

1.参数个数可以有0个/多个;

2.参数类型只能为合法类型:char、int、double、float...内置类型/自定义类型;

3.函数参数如果为0个(不需要参数),函数参数类型可以写成void(表示函数没有参数也不需要参数);

(5)返回类型:如果不写则默认为int类型;

2.形参和实参
#include <stdio.h>
int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int main()
{
    int a = 0;
    int b = 0;
//输⼊
    scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
    int r = Add(a, b);
 //输出
    printf("%d\n", r);
    return 0;
}

(1)调用Add函数传递给函数的参数a和b,称为实际参数,简称实参

(2)Add函数括号中的x和y为形式参数,简称形参; 

(3)形参是实参的一份临时拷贝,对形参的修改不影响实参;

(4)x86:表示32位环境,编译生成32位程序;x64:表示64位环境,编译生成64位程序;

#include <stdio.h>
int Add(int x, int y)//若不调用,则一直为形参
{
     int z = 0;
     z = x + y;
     return z;
}//括号中的部分均为函数定义
int main()
{
     int a = 0;
     int b = 0;
//输⼊
     scanf("%d %d", &a, &b);
//调⽤加法函数,完成a和b的相加
//求和的结果放在r中
     int r = Add(a, b);//函数调用时,传递给函数的均为实参
//输出
     printf("%d\n", r);
     return 0;
}
3.return语句

(1)return后边可以是数值/表达式,如果是表达式则先执⾏表达式,再返回表达式的结果;

(2)return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况;

(3)return返回的值和函数返回类型不⼀致,系统会⾃动将返回的值隐式转换为函数的返回类型;

(4)return语句执⾏后,函数就彻底返回,后边的代码不再执⾏;

(5)如果函数中存在if等分⽀的语句,则要保证每种情况下都有return返回,否则会出现编译错误 ;

(6)函数的返回类型可以为char、int、short、double...自定义类型这些内置类型;

(7)函数需不需要返回值是根据实际情况决定的;

4.数组的函数参数
#include <stdio.h>
int main()
{
     int arr[] = {1,2,3,4,5,6,7,8,9,10};
     int sz = sizeof(arr)/sizeof(arr[0]);
     set_arr(arr, sz);//设置数组内容为-1
//arr为数组名,sz为元素个数
     print_arr(arr, sz);//打印数组内容
     return 0;
}

(1)实参和形参名字可以相同;

(2)数组传参写的是数组名;

(3)形参写的也是数组的形式,形参书写时可以忽略元素个数(针对一维数组);

(4)数组传参后,形参的数组和实参的数组为同一块空间,改变形参的数组就是在改变实参的数组;

(5)函数的形式参数要和函数的实参个数匹配;

(6)函数的实参是数组,形参也是可以写成数组形式的;;

(7)形参如果是⼀维数组,数组⼤⼩可以省略不写;

(8)形参如果是⼆维数组,⾏可以省略,但是列不能省略;

(9)数组传参,形参是不会创建新的数组的;

(10)形参操作的数组和实参的数组是同⼀个数组;

5.嵌套调用和链式访问
5.1.嵌套调用

嵌套调用就是函数之间的互相调用;函数之间有效的互相调用写出了相对大型的程序:

练习:计算某年某月有多少天:

//is_leap_year:根据年份确定是否为闰年;
//get_days_of_month:调用is_leap_year确定是否为闰年以后,再根据月计算这个月的天数;

int is_leap_year(int y)
{
//判断是否为闰年:
//1.能被4整除且不能被100整除;
//2.能被400整除;
     if(((y%4==0)&&(y%100!=0))||(y%400==0))
     return 1;
     else
     return 0;
}

int get_days_of_month(int y, int m)
{
//此处0的作用:将下标调整为与月份数一一对应
     int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
     int day = days[m];
     if (is_leap_year(y) && m == 2)//若为闰年(嵌套上一个函数)且为2月,则调整为29天
     day += 1;//闰年2月:29=28+1
 
return day;
}

int main()
{
     int y = 0;
     int m = 0;
     scanf("%d %d", &y, &m);
     int d = get_days_of_month(y, m);//嵌套前两个函数,打印年份与月份
     printf("%d\n", d);
return 0;
}

此题中的函数调用:
(1)main函数调⽤ scanf 、printf 、get_days_of_month;

(2)get_days_of_month函数调⽤ is_leap_year;

(3)函数不能用嵌套定义;

5.2.链式访问

将一个函数作为另一个函数的参数,像链条一样将函数串起来就是函数的链式访问;

#include <stdio.h>
int main()
{
     printf("%d\n", strlen("abcdef"));//链式访问:将strlen函数的返回值直接作为printf函数的参数
     return 0;
}
#include <stdio.h>
int main()
{
     printf("%d", printf("%d", printf("%d", 43)));
//1.printf("%d", 43):打印43;
//2.printf("%d", printf("%d", 43)):43只有2个字符,故打印2;
//3.printf("%d", printf("%d", printf("%d", 43))):2只有1个字符,故打印1;
     return 0;
}
//printf返回的是打印在屏幕上的字符的个数
6.函数的声明和定义
6.1单个文件

函数必须先声明后使用:

#include <stido.h>
//判断⼀年是不是闰年
int is_leap_year(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);
     int r = is_leap_year(y);//函数的调用
     if(r == 1)
     printf("闰年\n");
     else
     printf("⾮闰年\n");
return 0;
}

若将函数的定义放在函数的调用之后:

#include <stido.h>
int main()
{
     int y = 0;
     scanf("%d", &y);
     int r = is_leap_year(y);
     if(r == 1)
     printf("闰年\n");
     else
     printf("⾮闰年\n");
return 0;
}

//判断⼀年是不是闰年
int is_leap_year(int y)
{
     if(((y%4==0)&&(y%100!=0)) || (y%400==0))
     return 1;
     else
     return 0;
}

此时的运行结果:

此时会出现警告信息:

原因:当is_leap_year函数调用的时候,并未发现is_leap_year函数的定义;

解决方法:在函数调用之前加上函数的声明:int is_leap_year(int y) ,函数声明中只保留类型,去掉函数名也可行。

#include <stido.h>
int is_leap_year(int y)//函数的声明:类型、参数、函数名

int main()
{
     int y = 0;
     scanf("%d", &y);
     int r = is_leap_year(y);
     if(r == 1)
     printf("闰年\n");
     else
     printf("⾮闰年\n");
return 0;
}

//判断⼀年是不是闰年
int is_leap_year(int y)
{
     if(((y%4==0)&&(y%100!=0)) || (y%400==0))
     return 1;
     else
     return 0;
}
 6.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;
}
6.3.static和extern

(1)static意为“静态的”,功能:

1>修饰局部变量;

2>修饰全局变量;

3>修饰函数;

(2)extern:声明外部符号

(3)作用域:

1>局部变量的作用域是局部变量所在的范围;

2>全局变量的作用域是整个工程(项目);

(4)生命周期:

1>局部变量的生命周期:进入作用域变量创建,生命周期开始,出作用域生命周期结束(大括号外面的);

2>全局变量的生命周期:整个程序的生命周期(大括号里面的);

6.4.static修饰局部变量:
//代码1
#include <stdio.h>
void test()
{//进入
     int i = 0;
     i++;//i=2
     printf("%d ", i);
}//销毁

int main()
{
     int i = 0;
     for(i=0; i<5; i++)//循环5次
     {
         test();
     }
return 0;//最终结果:2 2 2 2 2
}

//代码2
#include <stdio.h>
void test()
{
//static修饰局部变量
     static int i = 0;//被static修饰,未被销毁
     i++;//i=2,3,4,5,6
     printf("%d ", i);
}

int main()
{
     int i = 0;//i的累加值进入函数
     for(i=0; i<5; i++)
     {
         test();//再次进入test函数中
     }
return 0;//最终结果:2 3 4 5 6
}

结论static修饰局部变量改变了变量的⽣命周期;存储类型变化导致生命周期改变,但作用域不变;

⽣命周期改变的本质是改变了变量的存储类型,本来⼀个局部变量是存储在内存的栈区的,但是被static修饰后存储到了静态区。存储在静态区的变量和全局变量是⼀样的,⽣命周期就和程序的⽣命周期⼀样了,只有程序结束,变量才销毁,内存才回收。但是作⽤域不变的。

6.5.static修饰全局变量
//代码1
​//add.c
int g_val = 2018;
//test.c
#include <stdio.h>
extern int g_val;
int main()
{
    printf("%d\n", g_val);
    return 0;
}

//代码2
//add.c
static int g_val = 2018;
//test.c
#include <stdio.h>
extern int g_val;//extern声明外部链接
int main()
{
     printf("%d\n", g_val);
     return 0;
}

 由运行结果可知:代码1运行正常,代码2运行报错;

结论:

(1)全局变量具有外部链接属性;

(2)全局变量被static修饰后,外部链接属性变为内部链接属性;此全局变量只能在自己所在的.c文件中使用,其他文件看不到,相当于作用域变小了;

使用建议:如果只想在所在源文件的内部使用一个全局变量而不想被其他文件发现,就可以使用static修饰。

6.6.static修饰函数
//代码1
//add.c
int Add(int x, int y)
{
     return x+y;
}
//test.c
#include <stdio.h>
extern int Add(int x, int y);
int main()
{
     printf("%d\n", Add(2, 3));
     return 0;
}

//代码2
//add.c
static int Add(int x, int y)
{
     return x+y;
}
//test.c
#include <stdio.h>
extern int Add(int x, int y);
int main()
{
     printf("%d\n", Add(2, 3));
     return 0;
}

代码1运行正常,代码2运行报错;

结论: 

(1)函数具有外部链接属性;

(2)函数被static修饰后,外部链接属性变为内部链接属性;此函数只能在自己所在的.c文件中使用,其他文件即使声明了也无法使用;

使⽤建议:如果只想在所在源文件的内部使用一个函数而不想被其他文件发现,就可以使用static修饰。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值