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

C语言——函数

C语言——函数

函数的概念

  • 函数:也叫子程序。C语言中的函数就是一个完成某项特定任务的一小段代码
  • C语言函数分类:
    按照用户使用:库函数,自定义函数
    按照参数的形式:无参函数,有参函数
    按照是否有返回值的角度:有返回值函数,无返回值函数
    按照调用的角度:主调函数,被调函数

库函数

标准库和头文件

  • 库函数:C语言国际标准ANSI C归档了一些常用的函数的标准,就被叫做标准库,不同编译器给出一系列函数的实现,这些函数叫库函数,例如:printf,scanf等。
    库函数相关头文件:https://zh.cppreference.com/w/c/header
  • 库函数的使用
    1.进入官网学习和查看,里面有例子
    2.举例:
#include<math.h>
int main
{double r=sqrt(16);printf("%lf\n",r);return 0;
}

运行结果就为4.0
3.库函数文档的一般格式
(1)函数原型
(2)函数功能格式
(3)参数和返回类型说明
(4)代码举例
(5)代码输出
(6)相关知识链接

自定义函数

  • 函数的语法形式
ret_type_fun_name(形式参数)
{
}
//把函数想象成一个小工厂,工厂得输入原材料,才能生产产品,函数一样也需要输入一些值,经过函数内的计算得出结果
//ret_type表示函数计算结果的类型,有时候返回类型为void,表示什么都不返回。
//fun_name是为了方便使用函数,给起了一个名字
//函数的参数相当于工厂中送进去的原材料,函数的参数也可以是void,明确表示函数没有参数,如果有参数,要交代清楚参数的类型和名字,以及参数个数
//{}括起来的是函数体

形参和实参

int Add(int x,int y)//形式参数,简称形参(即如果只定义不调用,这俩参数就只是形式上的参数)
{return x+y;//计算x+y后返回的是结果
}
int main()
{int a=0;int b=0;scanf("%d %d",&a,&b);int c=Add(a,b);//调用Add函数//真实传递给函数的参数,a,b是实际参数,简称实参printf("c=%d\n",c);return 0;
}
  • 形参的实例化:形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形参的实例化
  • 形参和实参的关系:形参和实参各自有独立的空间;
    形参的修改不会影响实参;
    形参是实参的一份临时拷贝;
    实参和形参的名字可以相同,但依然是不同的空间。

return语句

  • return后边可以是一个数值,也可以是一个表达式,如果是表达式则先执行表达式,在返回表达式的结果
  • return后边也可以什么都没有,直接写return;这种写法适合函数返回类型是void的情况
  • return语句执行后,函数就彻底返回,后边的代码不再执行
  • return返回的值和函数返回类型不一致,系统就会自动将返回的值隐式转换为函数的返回类型,例:
int test()
{return 3.5;//这样写就牛头不对马尾
}
int main()
{int r=test();printf("%d\n",r);//此时打印结果就为3,3.5被强制转换成了int类型return 0;
}
  • 如果函数中存在if等分支语句,则要保证每种情况下都有return返回,否则会出现编译错误(必须考虑全面,每一种情况都有返回值)
  • 函数的返回类型如果不写,编译器会默认函数的返回类型是int;
    尽量有明确的返回类型,就直接写清楚,如果不需要返回就写void
  • 函数写了返回类型,但是函数中没有使用return返回值,那么函数的返回值是未知的

数组做函数参数

一维数组的传参

//将数组内容全变成-1并打印
#include<stdio.h>
void set_arr(int arr[],int sz)
{int i=0;for(i=0;i<sz;i++){arr[i]=-1;}
}
//写一个函数,打印arr数组的所有内容
void print_arr(int arr[],int sz)
{	int i=0;for(i=0;i<sz;i++){printf("%d",arr[i]);}printf("\n");
}
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);//函数的调用print_arr(arr,sz);//数组传参的时候,实参应该写数组名return 0;
}

二维数组的传参

void print_arr2(int arr[][5],int r,int c)//行可省,列不可省
{int i=0;for(i=0;i<r;i++){int j=0;for(j=0;j<c;j++){printf("%d ",arr[i][j]);}printf("\n");	}
}
int main()
{int arr[3][5]={{1,2,3},{2,3,4,5},{3,4,5,6,7}};print_arr2(arr,3,5);return 0;
}

数组传参时需要注意

  • 函数的形参要和函数的实参个数匹配
  • 函数的实参是数组,形参也可以是写成数组形式的
  • 形参如果是一维数组,数组大小可以省略不写
  • 形参如果是二维数组,行可以省略,但是列不能省略
  • 数组传参,形参是不会创建新的数组的
  • 形参操作的数组和实参的数组是同一个数组

嵌套调用和链式访问

嵌套调用:函数之间的互相调用,例:

//使用函数的方式实现某年某月有多少天
#include<stdio.h>
#include<stdbool.h>
bool is_leap_year(int y)
{if(((y%4==0)&&(y%100!=0))||(y%400==0))return true;else return false;
}
int get_days_of_month(int y,int m)
{int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//来一个判断闰年的函数功能int d=days[m];if(is_leap_year(y)&&m==2)//嵌套调用{d+=1;}return d;
}int main()
{int year=0;int month=0;scanf("%d %d",&year,&month);int day=get_days_of_month(year,month);printf("%d\n",day);return 0;
}

链式访问:链式访问就是将一个函数的返回值作为另一个函数的参数,像链条一样将函数穿起来就是函数的链式访问,例:

int main()
{printf("%zd\n",strlen("abcdef"));//链式访问,将函数的参数作为返回值
}
int main()
{printf("%d",printf("%d",printf("%d",43)));//链式访问
//printf参数的返回值是打印在屏幕上字符的个数
}

打印结果是4321

函数的声明和定义

单个文件

函数的声明就是告诉编译器 ,有一个函数:名字是什么 ,参数是什么,返回类型是什么

int is_leap_year(int y);//函数的声明
//int is_leap_year(int);//函数的声明中形式参数的名字可以省略
int main()
{int year=0;scanf("%d",&year);if(is_leap_year(year))//函数的调用printf("闰年\n");elseprintf("非闰年\n");return 0;
}
//函数的定义,如果把函数的定义放在最下面函数调用的后面会有问题,除非你先声明一下
int is_leap_year(int y){if((y%4==0)&&(y%100!=0)||(y%400==0))return 1;elsereturn 0;}

多个文件

  • 头文件中放声明函数
    在这里插入图片描述
  • 函数定义
    在这里插入图片描述
  • 包含头文件,然后调用函数
    在这里插入图片描述
    ——这是可以运行的
    在这里插入图片描述
    如果不写头文件也是可以的,只需要在int main()前加入
extern int Add(int x,int y);//相当于声明

extern这个关键字是用来声明外部符号的
以上写法,函数的定义和声明是分离的,这样写方便模块化的编程,也方便协作

static和extern(都是C语言中的关键字)

  • 作用域:一段程序代码中所用到的名字并不总是有效的,而限定这个名字的可用性的代码范围就是这个名字的作用域
    1.局部变量的作用域是变量所在的局部范围;
    2.全局变量的作用域是整个项目。
  • 生命周期:是指变量的创建(申请内存)到变量的销毁 (收回内存)之间的一个时间段
    1.局部变量的生命周期:进入作用域变量创建,生命周期开始,出作用域生命周期结束;
    2.全局变量的生命周期:整个程序的生命周期
  • static
    1.修饰局部变量;在这里插入图片描述

运行结果为23456,若没有static修饰,运行结果为22222
static修饰了局部变量n,使其的生命周期变长了(本质是改变了变量的存储类型,本来是一个局部变量存储在内存的栈区,但被static修饰后到了静态区。存储在静态区的变量和全局变量是一样的,生命周期就和程序的生命周期一样了,只有程序结束 ,变量才销毁,内存才回收。但是作用域不变)

2.修饰全局变量;
static修饰全局变量后(外部链接属性变成了内部链接属性),使得这个全局变量只能在本源文件中使用,即使声明了,也不能在其他源文件中使用

3.修饰函数
函数默认是有外部链接属性的,用static修饰后,函数的外部链接属性变成内部连接属性,是的函数只能在自己的.c文件中使用,其他.c文件不能使用

  • extern:用来声明外部符号(外部符号可以是全局变量,函数等)

相关文章:

  • Spring Security认证流程
  • nacos配置springboot配置信息,并且集成金仓数据库
  • 精选面试题
  • 【解决】Android Gradle Sync 报错 Could not read workspace metadata
  • 程序员鱼皮最新项目-----AI超级智能体教程(一)
  • 04-stm32的标准外设库
  • 【C语言】C语言动态内存管理
  • MS1205N激光测距用高精度时间测量(TDC)电路,单精度模式 60ps,双精度模式 30ps
  • LJF-Framework 第15章 想想搞点啥-若依管理系统兼容一下
  • 机器学习项目管理:团队协作与版本控制
  • aarcpy 列表函数的使用(1)
  • MCP‌和LangGraph‌结合2
  • 第十节:性能优化高频题-虚拟DOM与Diff算法优化
  • 探寻健康密码:养生从日常细节开始
  • ap无法上线问题定位(交换机发包没有剥掉pvid tag)
  • 机械手排列定位设备 PLC梯形图流程
  • 通信新思路:EtherCAT转Profinet网关在自主研发机器人中的技术实践与优化
  • 革新AI生产力,比象AI源码 - 下一代智能创作引擎
  • 【线段树 容斥原理】P3801 红色的幻想乡|普及+
  • 大学生如何学好人工智能
  • 苏炳添任暨南大学体育学院院长
  • 传媒湃︱《金陵晚报》副刊“雨花石”5月起改为免费刊登
  • 长三角数智文化产业基金意向签约会成功举办
  • 当哲学与戏剧作为一种生活方式——《人生六戏》分享会
  • 南方医科大学原副校长宁习洲主动投案,接受审查调查
  • 研究|和去年相比,人们使用AI的需求发生了哪些变化?