系列文章目录
C语言学习笔记(1)常量和变量
C语言学习笔记(2)条件判断 if语句
C语言学习笔记(3)循环
C语言学习笔记(4)逻辑运算
C语言学习笔记(5) 嵌套和分支
C语言学习笔记(6)数组
文章目录
前言
从函数的定义讲起,讲解函数的调用,再讲解一些函数的细节,例如:返回值、参数、变量等等。大家如果有不清楚的地方,欢迎评论区留言讨论。
提示:以下是本篇文章正文内容,下面案例可供参考
一、函数的使用示例
问题1: 求出给定范围内的素数的和
// 素数求和
#include<stdio.h>
int isPrime(int i)
{
int ret = 1;
int k;
for(k = 2;k<i-1;k++){
if(i%k == 0){
ret = 0;
break;
}
}
return ret;
}
int main()
{
int m,n;
int sum=0;
int cnt=0;
int i;
scanf("%d %d",&m,&n);//求 [m,n]之间的素数和
if(m==1) m==2;
for(i=m; i<=n; i++){
if(isPrime(i)){
sum += i;
cnt++;
}
}
printf("%d %d\n",cnt,sum);
return 0;
}
问题2:求出1到10,20到30,35到45的和
//求出给定范围内的和
# include<stdio.h>
void sum(int begin,int end)
{
int a,b;
int res=0;
a = begin;
b = end;
for(a;a<=b;a++){
res += a;
}
printf("%d到%d的和是:%d\n",begin,end,res);
}
int main()
{
sum(1,10);
sum(20,30);
sum(35,45);
return 0;
}
把重复的代码放在一个函数中。
二、函数的定义
- 函数是一块代码,接受0个或者多个参数,返回0个或者1个值。
函数结构
voidvoid是返回类型
sumsum是函数名
(int begin,int end这里是参数表
)这一行是函数头
{花括号内的是函数体
int a,b;
int res=0;
a = begin;
b = end;
for(a;a<=b;a++){
res += a;
}
printf(“%d到%d的和是:%d\n”,begin,end,res);
}
其中
三、调用函数
调用格式:
- 函数名(参数值);
即使函数没有参数,调用的时候,也要有()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
四、函数的返回值
函数通过 return 返回值,如果在函数头中声名的是 int ,就返回 int 类型的值。
return的特点:
- 遇到return 就停止函数的执行,并送回一个值。
- 一个函数里面可以有多个 return。
- return 也不一定需要放到最后
注: 如果有多个 return ,则不满足 单一出口的理念,如果以后需要修改出口的话,就会出现困难。
return 的两种写法:
return;
return 表达式
没有返回值的函数
void 函数名(参数表)
- 不能使用带值的 return
- 可以没有 return
- 调用的时候,不能做返回值的赋值
五、函数先后关系
main()函数写在最下面,自定义的函数写在上面。
原因:
C的编译器自上而下顺序分析你的代码。
如果需要将自定义函数写在 main 函数下面,就需要
把函数头复制到 main 函数之前,并加上 分号,进行函数声名。代码示例如下:
//求出给定范围内的和
# include<stdio.h>
void sum(int begin,int end);//函数原型声名
int main()
{
sum(1,10);
sum(20,30);
sum(35,45);
return 0;
}
void sum(int begin,int end) // 函数定义
{
int a,b;
int res=0;
a = begin;
b = end;
for(a;a<=b;a++){
res += a;
}
printf("%d到%d的和是:%d\n",begin,end,res);
}
函数原型
- 构成: 函数头,分号结尾
函数原型的目的是告诉编译器函数是什么样子。函数信息有:
- 名称
- 参数(数量、类型)//函数声名里面可以不写参数名称,但是要有参数类型。一般还是会写上参数名字。
- 返回类型
调用的时候,会根据声名来检查函数。
六、参数传递
C语言的漏洞:
调用函数时给的值与参数的类型不匹配,编译器总是会自动进行强制类型转换,但是可能不是你期望的数值。
后续的 C++ / Java 在这方面很严格。
一个错误的示例
#include<stdio.h>
void swap(int a ,int b) //希望可以交换两个变量的值
{
int t = a;
a = b;
b = t;
}
int main()
{
int a = 5;
int b = 6;
swap(a,b);
printf("a=%d b=%d\n",a,b);//发现并没有交换 a,b 变量的值
return 0;
}
错误原因:
C语言在调用函数时,只能传递值给函数。
也就是说swap函数中的变量a,b和main函数中的变量a,b不是同一个变量
传值
- 每个函数都有自己的变量空间,参数也位于这个独立的空间中,和其他函数没有关系。
- 函数参数表中的参数叫“形式参数”,调用函数时的值叫“实际参数”
- 可以把形参成为参数,实参成为值。
- 因为形参和实参的概念,容易误以为,调用函数传递的是变量。但是调用函数的时候,实际传输的仅是值。
七、本地变量
- 函数的每一次运行,都会产生一个独立的变量空间,在这个变量空间中的变量,是函数的这次运行所独有的,称为本地变量
- 定义在函数内部的变量就是本地变量
- 参数也是本地变量(和本地变量具有一样的生存期和作用域)
变量的生存期和作用域
- 生存期:什么时候这个变量开始出现了,到什么时候它消亡了
- 作用域:在(代码的)什么范围内可以访问这个变量(这个变量可以起作用)
- 对于本地变量,生存期和作用域都是在 { 函数体} 内
int main()
{
int a = 5;
int b = 6;
swap(a,b);
printf("a=%d b=%d\n",a,b);//发现并没有交换 a,b 变量的值
return 0;
}
void swap(int a ,int b) //希望可以交换两个变量的值
{
int t = a;
a = b;
b = t;
}
main()函数有自己的变量空间,swap()有自己的变量空间,当进入swap()函数时,就离开了main()的变量空间,此时main函数中的变量还在生存期,但是作用域不在swap函数里面。
swap函数中不能调用 main函数中的变量。
本地变量的规则
- 本地变量是定义在块内的
-
- 它可以是定义在函数的块内
-
- 也可以定义在语句的块内
if( a < b)
{
int i =10;
}
i 是定义在 if 块里的变量,在这个块里的变量,生存期和作用域也在这个块里面。在{} 外面就不可以调用 i 了
-
- 甚至可以随便拉一对大括号来定义变量
-
程序进入这个块之前,其中的变量不存在,离开这个块,其中的变量也消失了
-
块外面定义的变量,在里面仍然有效。但是里面定义的变量,块外面就不存在了。
-
块里面定义了和外面同名的变量,则掩盖了外面的。
-
本地变量不会被默认初始化。
-
参数在进入函数的时候被初始化了
注:
- 函数里面不能再定义函数(即函数不能嵌套定义)。可以放一个函数的声名,但是不能放一个函数体
-
int i, j sum(int i , int j ) // 声名 Int变量 i 和 j ,声名sum()函数,其中,i,j是整数的形参,返回值是 Int (不建议这么写)
-
return ( i );// return 是一个语句,后面跟的是表达式,所以 (i) <=> i,但是容易让人误以为 return 是函数。(不建议这么写)