【C语言 |函数】C语言函数详解

目录

一、 函数的概念

 二、库函数

1.标准库和头文件

2.库函数的使用

三、⾃定义函数

 四、形参和实参

五、return语句

六、数组做函数参数

七、嵌套调⽤和链式访问

1.嵌套调⽤

2.链式访问

八、函数的声明和定义

九、函数的调用

1.传值调用

2.传址调用

十、函数的递归


一、 函数的概念

C语⾔也引⼊函数(function)的概念,有些翻译为:⼦程序,这种翻译更加准确⼀些
C语⾔中的函数就是⼀个完成某项特定的任务的⼀⼩段代码
提升了开发软件的效率
我们⼀般会⻅到两类函数:
        • 库函数
        • ⾃定义函数
下面正文开始

 二、库函数

1.标准库和头文件

C语⾔标准中规定了C语⾔的各种语法规则,C语⾔并不提供库函数
C语⾔的国际标准ANSIC规定了⼀ 些常⽤的函数的标准,被称为标准库
那不同的编译器⼚商根据ANSI提供的C语⾔标准就给出了系列函数的实现
这些函数就被称为库函数
有了库函数,⼀些常⻅的功能就不需要程序员⾃⼰实现了,⼀ 定程度提升了效率;同时库函数的质量和执⾏效率上都更有保证
库函数相关头⽂件: https://zh.cppreference.com/w/c/header

2.库函数的使用

库函数是在标准库中对应的头⽂件中声明的,所以库函数的使⽤,务必包含对应的头⽂件

double sqrt (double x)
{
    语句;
}

//sqrt 是函数名
//x 是函数的参数,表⽰调⽤sqrt函数需要传递⼀个double类型的值
//double 是返回值类型 - 表⽰函数计算的结果是double类型的值
库函数的学习和查看⼯具很多,⽐如:
C/C++官⽅的链接: https://zh.cppreference.com/w/c/header
cplusplus.com: https://legacy.cplusplus.com/reference/clibrary/
库函数有许多,我们需要什么如何使用,各种各样大家可以自行查阅
库函数⽂档的⼀般格式
1. 函数原型
2. 函数功能介绍
3. 参数和返回类型说明
4. 代码举例
5. 代码输出
6. 相关知识链接

就拿上面的sqrt函数为例

 可以看到它返回了一个double类型的值,传递⼀个double类型的值,并且包含头文件math.h

所以我们就可以使用了

#include<math.h>
#include<stdio.h>
int main()
{
	float num = 64.0;
	printf("%f", sqrt(num));
}


三、⾃定义函数

了解了库函数,我们的关注度应该聚焦在⾃定义函数上,⾃定义函数其实更加重要,也能给程序员写 代码更多的创造性
库函数的语法形势跟库函数一样的其实
ret_type fun_name(形式参数)
{
     语句;
}

//ret_type 返回类型
//fun_name 函数名
//形式参数    函数参数
//{}括起来的是函数体

因为自定义函数的自由度比较高,所以我们就得明白

设计函数的参数部分需要交代清楚:参数个数,每个参数的类型是啥,形参的名字叫啥,并且函数返回什么类型的数据,函数的命名

eg.

就好比现在需要实现一个算两个人年龄之和的函数

函数参数:年龄是非负值值,所以可以用size_t数据类型,然后两个人的年龄,所以要传两个参数,分别age1,age2

函数返回值:年龄是非负值值,所以可以用size_t数据类型

函数命名:两个数相加,可以起Add()

#include<stdio.h>
size_t Add(size_t age1,size_t age2)
{
	return age1 + age2;
}
int main()
{
    int a = 12,b = 19;
	printf("%zd",Add(a,b));
	return 0;
}

这样就实现了两个人年龄之和的函数 


 四、形参和实参

在函数使⽤的过程中,把函数的参数分为,实参和形参

形参是实参的一份临时拷贝

#include<stdio.h>
size_t Add(size_t age1,size_t age2)
{
	return age1 + age2;
}
int main()
{
    int a = 12,b = 19;
	printf("%zd",Add(a,b));
	return 0;
}

就好比上面这段代码 

  • 传递给函数的参数a和b,称为实际参数,简称实参,实际参数就是真实传递给函数的参数
  • 函数名 Add 后的括号中写的 age1 和 age2,称为形式参数简称形参
  • 形式参数只有在 函数被调⽤的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形式的实例化

 

我们在调试的可以观察到,age1和age2确实得到了a和b的值,但是地址和a和b的地址是不⼀样的,所 以我们可以理解为形参是实参的⼀份临时拷⻉。


五、return语句

• return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执⾏表达式,再返回表达式 的结果
• return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况
• return返回的值和函数返回类型不⼀致,系统会⾃动将返回的值隐式转换为函数的返回类型
• return语句执⾏后,函数就彻底返回,后边的代码不再执⾏
• 如果函数中存在if等分⽀的语句,则要保证每种情况下都有return返回,否则会出现编译错误

六、数组做函数参数

在使⽤函数解决问题的时候,难免会将数组作为参数传递给函数,在函数内部对数组进⾏操作

函数的形式参数要和函数的实参个数匹配
函数的实参是数组,形参也是可以写成数组形式的
形参如果是⼀维数组,数组⼤⼩可以省略不写
形参如果是⼆维数组,⾏可以省略,但是列不能省略
数组传参,形参是不会创建新的数组的
形参操作的数组和实参的数组是同⼀个数组
#include <stdio.h>
void set_arr(int arr[], int sz)
{
 int i = 0;
 for(i=0; i<sz; i++)
 {
 arr[i] = -1;
 }
}

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);//设置数组内容为-1
 print_arr(arr, sz);//打印数组内容
 return 0;
}
1

七、嵌套调⽤和链式访问

1.嵌套调⽤

嵌套调⽤就是函数之间的互相调⽤,函数之间的嵌套调⽤,但是函数是不能嵌套定义的

eg.计算某年某⽉有多少天

is_leap_year():根据年份确定是否是闰年
get_days_of_month():调⽤is_leap_year确定是否是闰年后,再根据⽉计算这个⽉的天数

int is_leap_year(int y)
{
 if(((y%4==0)&&(y%100!=0))||(y%400==0))
 return 1;
 else
 return 0;
}
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 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_month(y, m);
 printf("%d\n", d);
 return 0;
}
main 函数调⽤ scanf printf get_days_of_month , get_days_of_month 函数调⽤ is_leap_year
反应了不少的函数调⽤,就是这样互相嵌套的使用

2.链式访问

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

        下面代码其实就是一个很简单的链式,strlen的返回值直接作为printf函数的参数

#include <stdio.h>
int main()
{
 printf("%d\n", strlen("abcdef"));//链式访问
 return 0;

八、函数的声明和定义

函数的调⽤⼀定要满足,先声明后使⽤;
函数的定义也是⼀种特殊的声明,所以如果函数定义放在调⽤之前也是可以的

函数的定义在函数调⽤之前

红色的部分是函数的定义,绿⾊的部分是函数的调⽤ 

 函数的定义在函数调⽤之后

我们发现这个代码在VS2022上编译,会出现下⾯的警告信息: 

C语⾔编译器对源代码进⾏编译的时候,从第⼀⾏往下扫描的,所以要进行函数声明

声明函数只要交代清 楚:函数名,函数的返回类型和函数的参数

 这样就能正常编译了 


九、函数的调用

1.传值调用

函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。

传过去函数形参接受,算是实参的临时拷贝

2.传址调用

传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。

十、函数的递归

只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量

递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接 调用自身的

的递就是递推的意思,归就是回归

递归的两个必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续
每次递归调用之后越来越接近这个限制条件

eg

求n的阶乘

#include <stdio.h>
int Fact(int n)
{
     if(n<=0)
     return 1;
     else
     return n*Fact(n-1);
}
int main()
{
     int n = 0;
     scanf("%d", &n);
    int ret = Fact(n); 
    printf("%d\n", ret);
    return 0;
}

 红色的是递,绿色的为归

 迭代的⽅式(通常就是循环的⽅式)

迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。

合理使用递归 跟迭代能够高效解决很多问题 


希望对你有帮助 

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言中的string函数主要包括字符串的处理函数和字符串的操作函数。 字符串的处理函数主要有以下几个: 1. strlen:用于计算字符串的长度,即包含的字符数目。 2. strcpy:用于将一个字符串复制到另一个字符串中。 3. strcat:用于将两个字符串连接起来。 4. strcmp:用于比较两个字符串的大小关系。 5. strchr:用于在一个字符串中查找指定字符的位置。 6. strstr:用于在一个字符串中查找指定子串的位置。 字符串的操作函数主要有以下几个: 1. sprintf:用于将格式化的数据写入字符串中。 2. sscanf:用于从字符串中读取格式化的数据。 3. strtok:用于将一个字符串按照指定的分隔符进行分割。 4. strncmp:用于比较两个字符串的前n个字符的大小关系。 5. strncpy:用于将一个字符串的部分内容复制到另一个字符串中。 6. memset:用于给字符串的指定范围内的每个字符赋予相同的值。 这些函数可以帮助我们在C语言中方便地处理字符串,实现字符串的复制、连接、比较、查找等操作。通过这些函数,我们可以更高效地处理文本数据,提高代码的可读性和可维护性。 需要注意的是,使用这些函数时要确保输入的参数合法,以避免内存越界等错误。同时,字符串的内存空间需要提前分配好,以免出现不可预知的问题。在实际编程中,我们需要灵活运用这些函数,结合具体需求,进行字符串的处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值