我们先来说一说上一篇博客留下的代码
int main()
{
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i = 0;
for (i = 0; i <= 10; i++)
{
arr[i] = 0;
}
return 0;
}
在上一篇博客中我们说到,这一段代码最终会死循环。而死循环的原因则是数组越界。具体来说,这段代码首先创建了一个长度为10的整型数组,随后又建立了一个局部变量 i 。一般情况下,编译器在编译这段代码时,首先会在栈区开辟一块空间存放整型数组,然后在相邻的内存空间中开辟空间存放临时变量(关于栈区的内容,以后我会单独写一篇博客来介绍)。在一些编译器中,数组越界并不会报错,上述代码在数组越界时,恰好内存空间在数组后面存放的是临时变量 i ,因而 i 被重新赋值为0,接着循环。
接下来进入我们今天的正题:函数。内容稍微有点多,我应该会分成两到三期来介绍。。
目录
一、函数的概念
如果大家接触或者系统的学习过《微机原理》,相信对子程序这个概念一点都不陌生,在C语言中,函数的作用近乎等同于汇编语言中的子程序。当然,没有学过《微机原理》理解起来也很容易,大家可以把函数看作是一个机器人,这个机器人呢,要么只会做饭,要么只会扫地,反正是只会做一件事。当我们需要去做饭活着扫地的时候,只要吩咐一下对应的机器人好了。以此可以看出,函数的功能是它可以完成一个固定的任务,具有独立性。
int ADD(int x, int y)
{
int z = x + y;
return z;
}
void print(int ret)
{
printf("%d", ret);
}
int main()
{
int x = 10;
int y = 20;
int ret = ADD(a,b);
print(ret);
return 0;
}
以上述代码为例,在main函数上方的就是函数,这两段函数的功能是求两个数的和,以及打印一个数字,相信大家一定发现了这个函数似乎长得和main函数一样,但又不完全一样。从名字本身来看,其实main函数也是一种函数(具体会在后续栈区的时候详细介绍)。
我们一点一点来看,首先,这两个函数的开头并不相同,一个是int,另一个是void,这二者的区别,我们还是以前面提到的机器人为例,int是是用来定义一个整型变量的,在这里就像是做饭机器人,在机器人做完饭之后,是要把饭菜送到我们手中的,而这个送到我们手中的饭菜就是求出来的和,返回到main函数中,用一个整形变量ret来接收。而对于void来说,这个单词本身就是空的意思,也就相当于扫地机器人,扫完就扫完了,垃圾也倒掉了,不可能说把垃圾也带回来给你,也就是说void开头的函数,是完成了一个功能,也只是完成了一个功能。
其次是函数名,先来说一下命名的要求,只能使用大小写字母、数字或者下划线,并且不能以数字开头,也就是说2b不可以,you_is_2b就可以了。一般情况下,函数名的命名要求与函数的功能相同或相近,这样对于其他程序员来说,可以不用阅读代码,只是通过函数名就可以快速的得知该函数的大致功能,一上述代码为例ADD就是加的意思,print就是打印的意思,简单易懂。
再然后是括号里面的函数参数,这个在后面我会详细介绍,这里不再展开说。最后就是函数内部,函数内部便是完成某一特定功能的实现了,这一点与main函数相同。
二、库函数
还是以先前的机器人为例,库函数就像是大公司生产出来的机器人,这些机器人所能执行的功能因为会被人们经常用到,销量好,所以被大公司封装好了,供我们使用。一方面,能够让防止我们在写这些库函数的出错,另一方面也使得编程更加简单。
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d", n);
return 0;
}
以上述代码为例,scanf和printf都是库函数,在使用这些库函数之前,我们需要引用头文件,这个头文件一般是放在代码的第一行,在此代码中就是#include <stdio.h>,不同的库函数可能需要引用不同的库函数。那这个时候,有一部分长得比较帅的同学可能就会问了:库函数那么多,该怎么去学习呢,在这里我介绍两种方法:一,进入C/C++官网查找对应的库函数,里面会有详细的使用方法介绍。具体网址,中文版:http://zh.cppreference.com 英文版:http://en.cppreference.com
二,下载微软公司提供的MSDN软件,在索引中,可以查找到当前可以使用的所有库函数。
三、自定义函数
诚然,库函数可以解决相当一部分的编程问题,但在具体实践中,仍有许多功能需要程序员自己去实现,这就给了程序员很大的操作空间。在先前的函数的概念处,我所介绍的函数就是自定义函数,可以看出,自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计。
今天我们先来简单地介绍一下,函数参数的内容,老规矩,先上代码:
#include <stdio.h>
#include <string.h>
void reverse(char arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
char arr[] = {"abcdef"};
int sz = srrlen(arr);
printf("%s\n", arr);
reverse(arr,sz);
printf("%s\n", arr);
return 0;
}
以上述代码为例,此函数的功能是对字符串的逆置,这里我们主要介绍一下在自定义函数中,函数参数的注意事项。首先,在调用函数时,传递给自定义函数的参数需要在自定义函数中用相同的数据类型接收,具体来说,reverse这个函数,在传递参数时,传了字符数组arr以及整型变量sz,那么在自定义函数中,也应该用一个字符数组和一个整型变量来接收。值得一提的是,对于用来接收的数据类型来说,其名称可以不同,这个看个人的习惯,我的话,传递的参数是大写,就改成小写,其他不变。其次要注意的是数组传参,传递的其实是数组首元素的地址,尽管在自定义函数中,我们用的是一个字符数组来接收,但实际上,接收的还是数组的收元素地址,这一点在下一篇博客中,我会重点介绍。
今天是五一劳动节,祝大家节日快乐哦 :)