C语言函数

一、函数是什么

1.函数。

  • 计算机中,子程序是一个大型程序,由一个或多个语句块组成,它负责完成某项特定任务,具备相对的独立性。
  • 一般有输入参数和返回值,提供对过程的封装和细节的隐藏,这些代码通常被称为软件库

2.函数的分类。

1.库函数。

2.自定义函数。

二、库函数。

由编译器定义的可以直接引用的函数称为库函数。

头文件 -->  库函数

1.常用库函数。

  • IO函数
  • 字符串操作函数
  • 字符操作函数
  • 内存操作函数
  • 时间/日期函数
  • 数学函数
  • 其它

学习用库函数网站:

  • cppreference.com
  • cplusplus.com
  • MSDN

三、自定义函数。

1.自定义函数。

自定义函数和库函数一样,有返回值类型、函数名和函数参数。但这些都需要我们自己设计。

2.函数的组成。

函数定义的一般形式:

int fun_name(int g,int h)//函数首部
{
    printf();         //函数体
}

> int      函数类型
> fun_name 函数名
> g,h  函数参数

大括号和中间的语句称为一个函数体。

举个例子:定义求两个数中最大数的函数

#include<stdio.h>
// 函数定义
int get_max(int x, int y)
{
    int z = 0;
    if (x > y)
    {
        z = x;
    }
    else
    {
        z = y;
    }
    return z;//返回z,---返回最大值
}
int main()
{
    int a = 10;
    int b = 20;

    int max = get_max(a, b);
    //函数调用
    printf("%d", max);
    return 0;
}

若函数返回类型为 void ,则这个函数不需要返回。即不用return 。

交换两个变量的值

#include<stdio.h>
//swap1被调用时,实参的值传给形参,实际上形参只是实参的临时拷贝,改变形参不影响实参。
void swap1(int x, int y)
{
    int z = 0;
    z = x;
    x = y;
    y = z;
}

//swap2被调用时,实参把地址传给形参,形参可改变实参。
void swap2(int* pa,int* pb)
{
    int z = 0;
    z = *pa;
    *pa = *pb;
    *pb = z;
}

int main()
{
    int a = 10;
    int b = 20;
    printf("交换前:a = %d, b = %d",a,b);
    swap1(a,b);  //传值调用
    swap2(&a,&b);//传址调用
    printf("交换后:a = %d, b = %d",a,b);
    
    return 0;
}

四、函数参数。

  1. 实际参数(实参):真实传递给函数的参数,可以是常量,变量,表达式,函数。进行函数调用时必须有确定的值,以便把值传给形参。
  2. 形式参数(形参):定义函数时,函数名后括号中的变量,形参只在函数被调用时实例化(实参把值传给形参,形参被分配内存单元),函数调用完后自动销毁。因此形参只在自定义函数体中有效。

上述例子中swap1, swap2中的参x, y, pa, pb 都是形式参数。

main函数中传给swap1的 a, b 和传给swap2的 &a, &b 都是实参。

实参 a, b 和形参 x, y 使用的不是同一空间。

五、函数的调用。

1.传值调用

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

2.传址调用

  • 传址调用是把函数外部创建变量的内存地址传给函数参数的调用方法。
  • 可以让函数形参和实参建立联系,函数内部可直接操作函数外部的变量。

上述例子二就是传址调用

六、函数的嵌套调用和链式访问。

1.嵌套调用

  • 函数可以嵌套调用
void test3()
{
    printf();
}

int test2()
{
    test3();
    return 0;
}
int main()
{
    test2();
    return 0;
}
//这段代码中,函数test2中调用了函数test3,main函数中调用了函数test2.
//这就是嵌套调用。
  • 函数不可以嵌套定义
void test3()
{
    int test2()
    {
        
    }
}
//不能在函数test3中嵌套定义函数test2.

七、函数的声明和定义。

1.函数声明

  1. 函数声明告诉编译器有个函数的名称、参数、返回类型。
  2. 函数声明在函数调用之前,先声明后调用
  3. 函数声明一般放在头文件中。

2.函数定义

定义指函数的具体实现,交代函数的功能。

3.

sub.h中放函数声明

//函数的声明
int sub(int x,int y);

sub.c中放函数的定义

//函数sub的定义
int sub(int x,int y)
{
    return x-y;
}

引用头文件

#include "sub.h"

八、函数递归。

1.什么是递归?

程序调用自身的编程技巧叫做递归,一个过程或函数在其定义或说明中直接或间接地调用自身的一种方法。它通常把一个大型问题层层转化为一个与原问题相似的规模小的问题来求解。递归的主要思考方式在于:大事化小。

2.递归的两个必要条件

  1. 存在限制条件,当这个限制条件满足时,递归不再继续。
  2. 每次递归调用之后越来越接近这个限制条件。

EG:
接受一个无符号整型值,按照顺序打印它的每一位。如,输入"1234",打印"1 2 3 4"

//输入"1234",求出每位的值
1234 % 10 =            4
1234/10=123  123%10=   3
123/10=12     12%10=   2
              1%10=    1
#include<stdio.h>

void get(int n)
{
    if (n > 9)
    {   //递归:函数自己调用自己
        get(n / 10);
    }
    printf("%d ", n % 10);
}

int main()
{
    unsigned int num = 0;
    scanf("%d",&num);
    get(num);			//get函数打印num每一位
    return 0;
}

get()函数实现过程:输入n=123。
n>9,进入二级递归语句,将n/10=12传入get()函数。
n>9,进入三级递归语句,12/10=1传入get()函数。
1 < 9,跳出if语句,执行printf(),打印1%10=1,回到二级递归,打印12%10=2,回到一级递归,打印123%10=3.

3.递归常见问题

栈溢出:Stackoverflow.栈区开辟的空间过多。

要求:

  1. 不能死递归,要有跳出条件,每次递归逼近跳出条件。
  2. 递归层次不能太深。
  3. 学习网站:www.stackoverflow.com

4.迭代与递归

循环就是迭代。

eg:实现求n的阶乘

1.迭代法
#include<stdio.h>
int main()
{
	int n,i;
	int ret = 1;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		ret = ret * i;
	}
	printf("%d", ret);
	return 0;
}
2.递归法
#include<stdio.h>
int fac(int n)
{
	if (n <= 1)
		return 1;
	else
	{
		return n * fac(n - 1);
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fac(n);
	printf("%d", ret);
	return 0;
}
  1. 有些功能即可用递归,也可用迭代解决。
  2. 递归有时会有bug,要考虑用迭代来优化。

eg:求第n个斐波那契数列

1.递归法
#include<stdio.h>
int fab(int n)
{
	if (n < 3)
		return 1;
	else
		return fab(n - 1) + fab(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = fab(n);
	printf("%d", ret);
	return 0;
}
  • 递归所用的fab()函数进行了大量重复计算。
2.迭代法
#include<stdio.h>
int gtr(int n)
{
	int a = 1, b = 1, c = 1;
	while (n>2)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = gtr(n);
	printf("%d", ret);
	return 0;
}

eg:求字符串长度

1.递归法
#include<stdio.h>

int my_strlen(char* str)
{
	if (*str != '\0')
		return 1 + my_strlen(str + 1);   //进行函数递归操作。
	else
		return 0;
}

int main()
{
	char arr[32] = {};
	scanf("%s", &arr);
	printf("%d", my_strlen(arr));   //调用求字符串长度的函数。
	return 0;
}
2.迭代法
#include<stdio.h>
int my_strlen(char* str)
{

	int count=0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "bit";
	printf("%d", my_strlen(arr));
	return 0;
}

字符串的后面都省略了一个 ‘\0’ .
如字符串"abc"实际上是 ‘a’,‘b’,‘c’,’\0’.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值