前言
好久不见大家,继续给大家更新C语言学习专栏系列。喜欢点点赞和收藏、关注。
函数是什么
函数格式和内容
内容
包括:函数名、返回值类型(函数名前面的数据类型)、函数参数(函数括号里的东东)、函数内代码(花括号里的东东)。
格式
返回值类型 函数名(函数参数, 函数参数……)
{
函数内代码;
}
函数参数可以有多个,也可以没有函数参数,用英文逗号隔开。
main函数
main函数为什么要单独拿出来讲呢?因为它很重要,它是整个程序/工程的入口,它开始表示程序的开始。
main函数格式
int main()
{
代码;
return 0;
}
请大家刚开始学习时务必参照这个格式写,不要再把main的返回值类型写成void了。那是上个世纪的写法,return 0;也不要忘记了。特别是写算法题时,不好好参照这个格式写是过不了的。
函数分类
函数大致可以分为两类,库函数和自定义函数。
库函数
为什么会有库函数?
1. 我们知道在我们学习 C 语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格式打印到屏幕上(printf )。2. 在编程的过程中我们会频繁的做一些字符串的拷贝工作( strcpy )。3. 在编程是我们也计算,总是会计算 n 的 k 次方这样的运算( pow )。
库函数作用
那怎么学习库函数呢?
我的建议是可以看看cplusplus.com - The C++ Resources Network。
在对应搜索框可以搜索你想要学习的函数。
PS:学习库函数不用将所有库函数记住。只要记住常见的几个,memset、strcpy等。以后遇到不懂的上cplusplus.com - The C++ Resources Network看看就好了。
库函数的使用
使用一个库函数之前要上 cplusplus.com - The C++ Resources Network查找这个库函数所属的头文件并用尖括号引用<>,在文件中引用之后就可以使用该文件下的库函数。
引用格式
#include <文件名>
比如要使用printf函数,就要引用stdio.h文件
#include <stdio.h>
自定义函数
由于库函数不能完成所有的工作,所以需要我们自定义函数去完成指定工作。
自定义函数的返回值类型、函数名、函数参数、函数执行代码都可以自定义。
下面是一个程序,其中有我定义一个加法函数add。
#include <stdio.h>
int add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int x = 10;
int y = 20;
int z = add(x, y);
printf("%d\n", z);
return 0;
}
代码分析
可以参考函数格式去分析。
int add(int a, int b)
{
int c = a + b;
return c;
}
add前面的int是返回值类型,说白了跟数学的函数很像,函数得出的数据结果必须是int(整型)的。 add是函数名,a和b都是函数参数,他们的数据类型都是int。
这个函数的作用是把两个数相加。函数结果就是两者之和。
int z = add(x, y);
这句语句作用是调用add函数,把x传给(赋值)a,y传给(赋值)b,a和b相加结果赋值给z。
函数参数
实际参数(实参)
形式参数(形参)
解释
就像上面那个程序,x和y是实际参数,a和b是形式参数。
PS:形式参数的改变不影响实际参数。
为什么形式参数的改变不影响实际参数?
上图形参a成20,但是a对应的实参x却没有改变。因为他们是两个不一样的变量。
逐语句运行到add函数内部时,我们调出监视窗口,可以很明显的看出,虽然实参x和y分别对应形参a和b,但是他们的地址并不相同。
例子
下面我们写一个函数实现两个变量的数据交换
#include <stdio.h>
//实现成函数,但是不能完成任务
void Swap1(int x, int y)
{
int tmp = 0;
tmp = x;
x = y;
y = tmp;
}
//正确的版本
void Swap2(int* px, int* py)
{
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}
int main()
{
int num1 = 1;
int num2 = 2;
Swap1(num1, num2);
printf("Swap1::num1 = %d num2 = %d\n", num1, num2);
Swap2(&num1, &num2);
printf("Swap2::num1 = %d num2 = %d\n", num1, num2);
return 0;
}
形式参数x、y、px、py,实际参数num1、num2、&num1、&num2。
swap1这个函数不能交换成功还是那个原因,地址不一样,交换注定失败!
而swap2这个函数形式参数是指针接受是实参的地址,所以形参和实参是同一地址。交换可以成功。
函数调用
传值调用
传址调用
函数的嵌套调用和链式访问
嵌套调用
#include <stdio.h>
void fun1()
{
printf("haha\n");
}
void fun2()
{
fun1();
printf("hehe\n");
}
int main()
{
fun2();
return 0;
}
运行结果:
可以看见,函数是可以进行嵌套调用的。但请注意函数并不能嵌套定义。
链式访问
把一个函数的返回值作为另外一个函数的参数。
例子
#include <stdio.h>
#include <string.h>
int main()
{
char arr[20] = "hello";
int ret = strlen(strcat(arr,"bit"));//这里介绍一下strlen函数
printf("%d\n", ret);
return 0;
}
strcat函数是把两个字符串连接起来,"helllo"和"bit"相连接成"hello bit",连接完后被当作返回值返回。
strlen函数是计算一个字符串的长度,(包含几个字符),返回值是整数。
函数的声明和定义(实现)
函数声明
引用格式
#include "文件名"
函数定义(实现)
函数的定义是指函数的具体实现,交待函数的功能实现。
例子
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void Swap1(int x, int y);//函数声明
void Swap2(int*, int*);//函数声明,参数名字可以不需要,只有类型也可以。
int main()
{
int num1 = 1;
int num2 = 2;
Swap1(num1, num2);//函数使用
printf("Swap1::num1 = %d num2 = %d\n", num1, num2);
Swap2(&num1, &num2);//函数使用
printf("Swap2::num1 = %d num2 = %d\n", num1, num2);
return 0;
}
void Swap1(int x, int y)//函数定义(实现)
{
int tmp = 0;
tmp = x;
x = y;
y = tmp;
}
void Swap2(int* px, int* py)//函数定义(实现)
{
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}
这里提一下如果你要写只是一小段代码,建议代码如上述代码这样排版。
小文件排版格式
文件引用
函数声明
main函数
函数实现
工程代码排版格式
PS:test文件不一定要叫test,可以任意起名,你只要知道里面放着main函数就行。
test.h对应上图的专门的头文件
#ifndef __TEST_H__
#define __TEST_H__
//函数的声明
int Add(int x, int y);
#endif //__TEST_H__
test.c对应上图专门的cpp文件(可这里是.c欸,别管!)
#include "test.h"
//函数Add的实现
int Add(int x, int y)
{
return x+y;
}
因为函数涉及到递归,递归比较重要,后续我打算单独写一篇文章讲递归。
最后
创作不易,球球了。如果有问题可以在评论区提出或者私信我!