目录
cppreference.comhttps://en.cppreference.com/w/
cppreference.comhttps://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5
含义
- 在计算机科学中,子程序(function, callable unit)是一个大型程序的某部分代码,由一个或多个语块组成部分,它负责完成某个特定任务,相对于其它代码具有相对独立性
- 一般有输入参数和返回值,提供对过程的封装和对细节的隐藏,这些代码通常被集成为软件库,方便重复使用。
分类
-
库函数
库函数查询指南
Tutorials - C++ Tutorialshttps://cplusplus.com/doc/英文版
cppreference.comhttps://en.cppreference.com/w/
中文版
cppreference.comhttps://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5
-
自定义函数
组成
// ret_type 返回值类型
//fun_name 函数名
// para1 参数
ret_type fun_name(para1, *)
{
statement; // 语句项
}
函数调用
-
传值调用
形参,实参占据不同的地址空间,不同的内存块
形参实例化后相当于实参的一份临时拷贝,所以对该形参的修改不影响实参
-
传地址调用
传地址调用是把函数外部创建的变量的地址传给变量的一种调用方式
让函数内外的变量建立真正的联系,使在函数内部能够修改外部变量
所以对该形参的修改影响实参,通过解引用修改其内容
参数
-
实参
真实传给函数的参数是实参
实参可以是变量、常量、表达式、函数等
在函数调用时,实参必须有个确定的值
-
形参
形参是指函数名后边的变量,至于在函数调用时才实例化(分配内存单元),形参实例化后相当于实参的一份临时拷贝
当函数调用完后形参销毁,形参只在函数中有效
函数内的变量为局部变量
不同局部变量相互独立
让一个局部变量在另一个函数中使用,将它作为参数传递到另一个函数中去
-
数组作为函数参数
-
数组元素作为参数
数组元素作为参数时与普通变量没有区别,是值传递
-
数组元素地址作为参数
为地址传递
-
数组名作为参数
数组名是数组中第一个元素的地址
数组名作为参数时执行地址传递,是地址传递
形参的接收方式
1 必须是可接受地址的数组名或者指针变量
2 arr[0]
3 arr
4 *a
返回值
函数的返回值是指函数被调用后,执行体中的代码运行结果,通过return返回这个结果
形式
1 return expr;
2 return (expr);
没有返回值的函数为空类型,用void表示
return 语句可以有多个,但是每次调用只被执行一次
程序遇到return后返回结果,终止运行
return是提前结束函数的唯一方法,单独一个return 表示终止程序
-
练习
// 交换数值
// 当实参传给形参时, 形参是实参的一份临时拷贝, 对形参的修改不影响实参
#include <stdio.h>
void Swap(int *n, int *m) // 开辟两块空间, 声明指针变量*n, *m, 将a, b的地址存入*n, *m
{
int temp;
temp = *n; //*n >> 解引用, *n = a >> temp = a
*n = *m; //*m = b >> a = b
*m = temp; //b = a
}
int main()
{
int a; // 开辟两块空间a, b
int b;
scanf("%d%d", &a, &b); // 往a,b 里存入数值
printf("a = %d b = %d\n", a, b);
Swap(&a, &b); //取a, b地址
printf("a = %d b = %d\n", a, b);
}
//判断一个数是不是素数
//素数只能被它本身和1整除
//判断条件 >> 因式 <= sqrt(数)
// if 数 % 因式 == 0 >> 数 = a * b >> 必然不是素数
#include <stdio.h>
#include <math.h>
int Is_prime_num(int n)
{
int i;
for (i = 1; i <= sqrt(n); i += 2) // 遍历出因式
{
if (i == 1)
continue;
if (n % i == 0) // if 数 % 因式 == 0 >> return 0 程序终止
return 0;
}
return 1; //跳出来只有1个原因,n没有因式,是素数,返回1,程序终止
}
int main()
{
int num;
scanf("%d", &num);
int re = Is_prime_num(num);
if (re == 1)
{
printf("%d是素数\n", num);
}
else
{
printf("%d不是素数\n", num);
}
return 0;
}
// 判断一个年是不是闰年
//闰年 > 能被四整除不能被100整除 || 能被400整除
// 非整百年份 >> 能被四整除不能被100整除 >> 1900不是闰年 ; 整百年份 >> 能被400整除 >> 2000是闰年
#include <stdio.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 year;
scanf("%d", &year);
int re = Is_leap_year(year);
if (re == 1)
printf("%d是闰年\n", year);
else if (re == 0)
{
printf("%d不是闰年\n", year);
}
return 0;
}
//实现整型有序数字的二分查找
//注意 数组传参 传过去的是数组第一个元素的地址,因为数组是存在了一片连续空间里,这样可以节省内存, 所以在外面把数组元素个数算出来
#include <stdio.h>
int binary_search(char a[], int b, int sz)
{
int l = 0; // left_index
int r = sz - 1; // right_index
int m;
for (; l <= r;) //注意左右下标相等时不是终止条件。 l = r, m = (l+l)/2 = 目标
{
m = (l + r) / 2; // middle_index
if (b < a[m]) // 1 2 3 4 5 6 7\ 8
{
r = m - 1;
}
else if (b > a[m])
{
l = m + 1;
}
else if (b == a[m])
{
return m;
}
}
if (l > r)
return 0;
}
int main()
{
char arr[] = {1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11};
int sz = sizeof(arr) / sizeof(arr[0]);
int aim = 8;
int re = binary_search(arr, aim, sz); // arr 传过去的是数组首元素的地址
if (re == 0)
printf("数字不存在\n");
else
printf("下标:%d\n", re);
}
// 每调用一次函数 num + 1
// 注意*n++ ++作用到了n上,所以(n*)++
#include <stdio.h>
void Count(int *n)
{
(*n)++;
}
int main()
{
int num = 0;
Count(&num);
Count(&num);
Count(&num);
Count(&num);
printf("%d\n", num);
return 0;
}
函数的嵌套调用和链式访问
-
嵌套访问
C语言不允许函数的嵌套定义,所有的函数在程序中书写处于平等地位;
C语言允许函数之间的嵌套调用;
例子
#include<stdio.h>
void Line_2()
{
printf("第二行\n");
}
void Line_1()
{
printf("第一行\n");
Line_2();
}
int main()
{
Line_1();
return 0;
}
-
链式访问
把一个函数的返回值作为另一个函数的参数
例子
#include<stdio.h>
int main()
{
char arr[] = "asd";
printf("%d",printf("%d",printf("%s", arr))); // arr31
}
函数的声明与定义
-
声明
1 C语言中只有后面定义的函数才能调用前面定义过的函数;
2 若果想把定义写在main函数后面,必须在main函数前声明函数(可以省略变量名
-->函数头;
3 告诉编译器函数的名字,参数类型,返回值类型是什么,具体不存在
4 函数声明的格式 int sum(int, int);
5 函数声明一般出现在函数的使用之前,要满足先声明后使用
6 函数的声明一般放在头文件里
7 只有声明, 没有定义,会在链接阶段报错
Undefined symbols for architecture x86_64: "_sum", referenced from: _main in main-261b4d.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
-
例子
#include <stdio.h>
// 函数声明
int He(int, int);
int main()
{
int a = 1;
int b = 2;
int re = He(a, b);
printf("%d\n", re);
}
// 函数的定义(实现)
int He(int a, int b)
{
return a + b;
}
-
多源文件开发
目的 : 模块化开发
一个正常的C语言项目,由多个.c源文件构成
-
例子
!不要使用关键字做变量名,否则
error: implicit declaration of function 'sum' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
> He.h //头文件
int main(int, int); //声明函数
> He.c // 定义函数
#include <stdio.h>
int He(int a, int b)
{
return a + b;
}
>main.c //主函数
#include <stdio.h>
#include"He.h"
int main()
{
int a = 1;
int b = 2;
int re = He(a, b);
printf("%d\n", re);
}
编译方式 手动
gcc -c sum.c main.c
gcc sum.c main.c -o main.out
./main.out >>>> 结果 3
自动编译会会在链接阶段报错,未解决