1. 函数是什么?
函数(子程序):
- 是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性;
- 一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
2. 库函数
- 为什么有库函数(效率高,稳定性好)
为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。 - c语言常用的库函数
IO函数、字符串操作函数、字符操作函数、内存操作函数、时间/日期函数、数学函数、其他库函数 - strcpy和memset
strcpy(字符串拷贝)
char * strcpy(char * destination, const char * source );
memset(对指定内存进行设置,在进行空间初始化或者设置时,只关心内存,不关心类型;设置时以字节为单位)
void * memset ( void * ptr, int value, size_t num );
这里说一下:
void (空类型;不能定义变量,因为其字节大小不明确)
void *(类型明确,指针类型,可以定义变量,void *x;*x不能被解引用,void可以用来接受任意类型,常用于接受指针类型)void * 可以设定成通用接口
注:使用库函数,必须包含#include对应的头文件。
3. 自定义函数
1:自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间;
2:自定义函数名最好见名知意;返回值得写,不然默认整型;
3:具有一定的独立性;
//自定义函数组成:
ret_type fun_name(para1, * )//返回类型 函数名(函数参数, *)
{
statement;//语句项
}
//例如:写一个函数找出两个整数的最大值
#include<stdio.h>
int get_max(int x,int y)
{
return(x>y)?(x):(y);
}
int main()
{
int num1=10;
int num2=20;
int max=get_max(num1,num2);
peintf("max=%d\n",max);
return 0;
}
4. 函数参数
实际参数(实参):
真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。再进行函数调用时,他们都有必须有确定的值。
形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形参再函数调用完被释放,即只在本函数内有效。
例如:
#include <stdio.h>
void Swap1(int x, int y)//这里的x,y为形式参数
{
int tmp = 0;
tmp = x;
x = y;
y = tmp;
}
int main()
{
int num1 = 1;//这里的num1、num2是实际参数
int num2 = 2;
Swap1(num1, num2);
printf("Swap1::num1 = %d num2 = %d\n", num1, num2);
return 0;
}
5. 函数调用
1 . 要发生形参实例化
在函数调用时候,形参会发生实例化,实例化相当于实参的一份临时拷贝
2 . 形参实例化时间:函数调用后,代码执行之前;
3. 函数传参必定形成临时变量(指针变量也是变量);
4. 注意传值传参和传址传参(都定义临时变量);
6. 函数的嵌套调用和链式访问
嵌套调用:
#include <stdio.h>
void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for(i=0; i<3; i++)
{
new_line();
}
}
int main()//相当于调B函数,但是B中有A函数,在执行B时候就会同时调用A函数。
{
three_line();
return 0;
}
链式访问:
把一个函数的返回值作为另外一个函数的参数。
printf返回值是往显示器上显示的(打印的)字符的个数
int num=printf(" aa:%d\n,123 ") //其结果为7,%d替换为123再计算个数
printf(" \nnum=%d\n, num ")
printf("%d", printf("%d", printf("%d", 43))); //其结果为4321;
拼接:
stract(目标串,要拼接的内容);
7. 函数的声明和定义
声明:
- 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,无关
紧要。 - 函数的声明一般出现在函数的使用之前。要满足先声明后使用。
- 函数的声明一般要放在头文件中的。
定义:
函数的定义是指函数的具体实现,交待函数的功能实现。(定义必须包含函数体)test.c防止函数的声明,test.h放置函数体。(多文件)
#//预处理
#pragma once//(防止头文件被重复包含的第一种方法)
#ifndef __TEST_H__ //(防止头文件被重复包含第二种方法)
#define __TEST_H__
8. 函数递归
- 什么是递归?
程序调用自身的编程技巧称为递归。其主要思考方式在于大事化小,即将一些复杂程序拆解成与原程序相似的规模较小的子问题来求解。对于一些问题,可大大减少程序的代码量。 - 递归的两个必要条件
a: 存在限制条件,当满足这个限制条件的时候,递归便不再继续。(递归的出口)
b: 每次递归调用之后越来越接近这个限制条件。(子问题如何解决)
举例:
//接受一个整型值(无符号),按照顺序打印它的每一位。
// 例如: 输入:1234,输出 1 2 3 4.
#include <stdio.h>
void print(int n)
{
if(n>9)
{
print(n/10);//由于返回值为整型,所以在循环时 1234/10 结果为123...如此循环
}
printf("%d ", n%10);
}
int main()
{
int num = 1234;
print(num);
return 0;
}
栈溢出:
在某些函数体中,由于循环次数过多或者出现了死循环,这样就有可能导致一直开辟空间,最终导致产生栈空间耗尽的情况,这样的现象我们称为栈溢出。
例如:
//求第n个斐波那契数。
#include<stdio.h>
int fib(int n)
{
if (n <= 2)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n=5;
fib(n);
printf("%d ",fib(n));
return 0;
}
上述代码如果将n换为较大一点的,如50,则会在运行时发现运行速度会非常慢。这是因为参数较大,进行了许多重复的计算。这时可以尝试将递归改为非递归。
斐波那契数写成迭代版本:
#include<stdio.h>
int fib_1(int n)
{
int first = 1;
int second = 1;
int third = 1;
while(n > 2){
third = first + second;
first = second;
second = third;
n--;
}
return third;
}
int main()
{
int n = 5;
int res = fib_(n);
printf("%d\n", res);
system("pause");
return 0;
}
可以发现这个代码相对于递归来说,运行速度更快。
总结:
- 多问题是以递归的形式进行解释的,这只是因为它比非递归的形式更为清晰。
- 但是这些问题的迭代实现往往比递归实现效率更高,虽然代码的可读性稍微差些。
- 当一个问题相当复杂,难以用迭代实现时,此时递归实现的简洁性便可以补偿它所带来的运行时开销。
注:各位读者阅读完本文,如果对你有所帮助,还请一键三连哦!如果文章有不妥之处,欢迎在下方评论指出!