目录
1 函数是什么?
C语言的函数是一段可重用的代码,它可以执行特定的任务。函数在C语言中被定义为一组语句,并且可以有输入和输出。函数的定义包括函数的返回类型、函数名、参数列表和函数体。
以下是C语言中定义和调用函数的一般语法:
<返回类型> <函数名>(<参数列表>) {
// 函数体
// 执行特定的任务
// 返回值(可选)
}
int main() {
// 调用函数
<函数名>(<参数列表>);
return 0;
}
其中,<返回类型>
指定了函数的返回值类型,例如int
、float
、void
等。<函数名>
是给函数起的名字,可以根据需要自定义。<参数列表>
是指定函数的输入参数,可以为空或包含多个参数,多个参数之间用逗号分隔。<函数体>
是函数的具体实现,包含一组语句,用于执行特定的任务。如果函数需要返回值,则使用return
语句返回结果。
函数的调用是通过函数名和实参列表进行的。在main
函数中,可以通过写函数名和实参列表的方式调用函数,例如<函数名>(<实参列表>)
。调用函数时,实参的数量和类型必须与函数定义中的形参相匹配。
下 面是一个简单的例子,演示如何定义和调用一个C语言函数:
#include <stdio.h>
// 定义函数
void sayHello() {
printf("Hello, C!\n");
}
int main() {
// 调用函数
sayHello();
return 0;
}
运行程序将输出Hello, C!
。
#include <stdio.h>
int sum(int a,int b) // 求两个数之和
{
int num = a + b;
return num;
}
int main() {
int x = 5;
int y = 10;
int z;
z = sum(x, y);
printf("%d",z);
return 0;
}
2 函数分类
函数可以分为库函数和自定义函数。 库函数分类l0函数、字符串操作函数、字符操作函数、内存操作函数、时间/日期函数、数学函数、其他库函数。
2.1 库函数
C语言常见的库函数:C语言常用库函数总结_c语言数学函数库-CSDN博客 或 www.cplusplus.com
#include<stdio.h>
int main()
{
//strcpy 头文件stdio.h
char arr1[20] = { 0 };
char arr2[] = { "hello world" };
strcpy(arr1,arr2); // 浅拷贝,改arr1 指向位置
printf("%s\n", arr1);
// memset 头文件stdio.h
char arr[20] = "hello world";
memset(arr+6, 'x', 3); // 内存设置,将arr偏移6个位置的前5五个位置设置为x
printf("%s\n", arr);
return 0;
}
2.2 自定义函数
自己定义的函数,包括函数名、函数体、返回值、输入值。
函数里面为形式参数,外面是实际参数,当实参传递给形参后,形参只是实参的一份临时拷贝,对形参进行修改不会影响实参。要更改实参可以采用指针的形式。
注意:一个工程可以有许多c文件,但只能有一个main函数。
3 函数的参数
3.1 实际参数
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
3.2 形式参数
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
3.3 函数传参
传值调用:
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
#include<stdio.h>
void func(int x)
{
x = 5;
}
int main()
{
int a = 0;
func(a);
printf("%d", a); //打印为0
return 0;
}
传址调用:
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
#include<stdio.h>
void func(int* p)
{
*p = 5;
}
int main()
{
int a = 0;
func(&a);
printf("%d", a); //打印为5
return 0;
}
4 嵌套调用
函数可以嵌套调用,但是不能嵌套定义,即不能在函数里面调用函数。
#include<stdio.h>
void func2()
{}
void func1()
{
func2(); // 函数里面调用函数
}
int main()
{
func();
return 0;
}
链式访问:
把一个函数的返回值作为参数输入。
目录
1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
2.函数的声明一般出现在函数的使用之前。要满足先声明后使用。
3.函数的声明一般要放在头文件中的。
4.函数的定义是指函数的具体实现,交待函数的功能实现。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int sum(int x, int y); //函数声明,否则会警告
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int n = sum(a, b); // 加法
printf("%d\n", n);
return 0;
}
int sum(int x, int y) // 函数定义
{
return x + y;
}
函数声明放头文件中:
sum.c:
sum.h:
在主函数中应用:
6 函数递归
程序调用自身的编程技巧称为递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解递归策略
只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
unsigned int print(unsigned int num)
{
if (num > 9)
{
print(num / 10);
}
printf("%d ", num % 10);
}
int main()
{
// 输入一个无符号整数,并挨个打印每一位
unsigned int a = 0;
scanf("%u", &a); //%d是有符号整数,%u是无符号整数
print(a);
//printf("%u\n",a);
return 0;
}
函数递归的必要条件:
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。
系统分配给程序的栈空间是有限的,但是如果出现了死循环,或者(死递归),这样有可能导致一直开辟栈空间,最终产生栈空间耗尽的情况,这样的现象我们称为栈溢出。递归容易出现栈溢出。
1.将递归改写成非递归。
⒉使用static对象替代nonstatic局部对象。在递归函数设计中,可以使用static对象替代nonstatic局部对象(即栈对象),这不仅可以减少每次递归调用和返回时产生和释放nonstatic对象的开销,而且static对象还可以保存递归调用的中间状态,并且可为各个调用层所访问。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <string.h>
int my_strlen(char* str) // 传入的是第一个的地址
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr1[] = "abcd";
int len1 = strlen(arr1);
printf("arr1的长度为%d\n", len1);
// 编写函数,采用递归方式求字符串长度,上面是调用函数实现
int len2 = my_strlen(arr1);
printf("%d\n", len1);
return 0;
}