大家好,很高兴又和大家见面啦!经过前段时间的学习,我们已经对分支与循环语句有了一个基本的认知,咱们也通过了一些编码题加深了对这些知识点的理解与运用。今天开始,咱们将进入下一个内容的学习——函数。
一、函数是什么?
在初识C语言12的篇章中我们有探讨过函数,感兴趣的朋友可以回顾一下,这里我就不多加叙述了。之前是我自己在学习的过程中对这个知识点引发的思考而编写的内容,通过类比的方式,将数学中的函数类比到咱们的C语言中,今天我们来看一下在维基百科中对函数的定义:
1.在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
2.一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
这里面的子程序也就是咱们说的函数,从上面的描述我们可以知道一下几点:
1.函数可以是一个语句,也可以是多个语句;
2.函数我们可以理解为就是咱们所说的功能,每个函数都有它自己的功能,也可以说是函数是为了实现这些功能才存在的。相比于其它的代码,它是相对独立的,这里我理解的是我需要使用它的时候,它才能起作用,我不需要使用它的时候,它也能存在于咱们的代码里这里我举个例子来证明一下:
大家可以看到,在这个代码中,我们编写了一个求两数之和的函数SUM,但是在主程序中,我们执行的是打印hello,并没有去使用这个函数,但是此时这个函数确实存在于我们的代码中,但是它并不会影响我们的代码正常运行,也不一定非得运行,相比于主函数来说,我们编写的SUM函数是相对独立的。
二、C语言中函数的分类
在C语言中函数分为两种:库函数、自定义函数。那什么是库函数,什么是自定义函数呢?咱们现在就来揭晓。
库函数
1.什么是库函数
库函数简单的理解就是C语言数据库里面的函数。
2.为什么会有库函数
对于这个问题,我是这样理解的,首先我们要知道的是函数的作用就是来使我们能够更加高效方便的写代码,我们在编写代码的过程中,所有的程序员都会反反复复的去运用一些功能,比如输入、输出……如果每一个程序员在使用这些功能之前都需要将这些功能重新编写一遍的话,这样就大大增加了工作量,所以,方便程序员更加高效的编写代码,C语言的数据库中就将这些函数给汇总并添加进去了,这也就是所谓的库函数。换一种角度来看,库函数其实也是自定义函数,只不过这个自定义是C语言库的自定义。
3.怎么学习库函数呢?
这里给大家推荐几个途径可以学习库函数:
从网站中可以看到C库中含有的头文件,通过这些头文件可以去学习相应头文件里面的库函数;
(2)MSDN(Microsoft Developer Network)
这个软件咱们在前面分支与循环9中在编写猜数字游戏时有使用过,这里我就不展开叙述了,感兴趣的朋友可以再回顾一下相关内容。
4.库函数的分类
(1)IO函数(引用头文件<stdio.h>):
我们已经学习过的IO函数有printf、scanf、getchar、putchar:
从网站里我们能找到所有的IO函数,点击对应的函数,就能看到函数对应的信息,如字符输入函数getchar:
通过这个网站我们更好的知道了getchar这个函数,这里我们可以简单概括一下:
●getchar读取的是标准输入中的字符,这里的标准输入就是我们前面提到的字符缓冲区;
●被读取字符的返回类型是int;
●读取EOF分为两种情况:
a.标准输入中的内容为文件结束标志,则返回EOF并设置标准输入的文件结束指示符;
b.发生读取错误时,也返回EOF但是设置的是错误指示符。
(2)字符串操作函数(引用头文件<string.h>):
我们已经学过的字符串操作函数有:strlen、strcmp,今天我们借助网站来学习一下strcpy——复制字符串:
通过网站内容,我们来对字符串拷贝函数做一个总结:
a.使用格式:strcpy(目的地地址,源头地址);
b.strcpy可以将源头地址里的字符串包括结束字符也就是\0一同拷贝到目标地址中;
c.目标地址的长度应该足够长,用来包含与源地址相同的字符串以及结束字符,并且不能与源地址重叠;
下面我们举几个列子来进一步理解strcpy的用法:
#define _CRT_SECURE_NO_WARNINGS 1//防止使用strcpy时,VS程序报错
#include <stdio.h>//printf引用头文件;
#include <string.h>//strcpy引用头文件;
int main()
{
char a[] = "1234";
char b[10] = "abcdefgh";
strcpy(b, a);//将数组a的字符串复制到数组b的字符串中;
printf("%s", b);
return 0;
}
下面我们来看一下运行结果:
大家可以看到,此时数组a的字符串以及成功拷贝到了数组b中。现在有几个问题需要我们探讨一下
<1>字符串结束标志\0是否有被拷贝到数组b中?<2>数组b中的其它字符去哪里了?
接下来我们通过调试中的监视窗口来一探究竟:
从监视窗口我们可以总结一下几点:
●复制的过程类似于替换,将数组b中与数组a中对应下标的元素给一一替换,包括\0;
●数组b中未被替换的元素任存在数组b中;
●数组b中未被替换的元素之所以未被打印出来,是因为他们的前一位元素是字符串结束标志\0,打印函数读取到字符\0时就停止了打印。
不知道大家对初识C语言19中探讨的结构体内容是否还有印象,下面来举例子说明strcpy在结构体中的应用:
这里我们可以看到,我们定义的结构体struct book中的成员name是一个字符数组,我们在第一次使用时,数组中的元素是“5元如何用7天”这个字符串,我们需要修改这个里面的内容的话,就需要通过strcpy来将修改的字符串复制到该数组中,而结构体成员price是一个整型变量,我们在修改变量的值时只需要重新赋值就可以完成。
对于strcpy这个函数我们就先学习到这里,接下来还有其它类型的库函数,我们简单了解一下:
(3)字符操作函数、(4)内存操作函数、(5)时间/日期操作函数、(6)数学函数、(7)其它函数;
对于这几个类型的库函数我们在前面的学习中有接触过时间函数(time—时间戳)和数学函数(sqrt—求平方根),这里就不展开探讨了,后面有机会,我们再来继续探讨这些不同的类型
自定义函数
1.自定义函数与库函数的区别
我对自定义函数的理解就是库函数的一种补充,因为在写代码的过程中,并不是所有的问题都能用库函数解决,这时候就需要自定义函数来解决这些问题,而且在早期没有库函数的时候,程序员需要使用打印、输入、输出等功能都需要自己先定义函数才行,这也就是为什么我觉得库函数也是自定义函数,而自定义函数是对库函数的补充。自定义函数与库函数相同的地方就是它们都有函数名、返回值类型和函数参数,它们的区别我们可以简单的理解为就是一个已经被定义好而且被收录在C语言库中,一个是由程序员根据实际情况进行设计且未被收入到C语言库中。但是对于程序员来说,更重要的还是自定义函数。接下来我们开始探讨一下自定义函数:
2.函数的组成
//函数的基本组成
ret_type fun_name(paral, *)//ret_type——返回类型;fun_name——函数名;paral——函数参数;
{
statement;//语句项也叫函数体——交代的是函数如何实现的
}
3.自定义函数实例理解
在之前的学习中,我们也经常使用自定义函数,下面我们还是例举几个例子来加深对自定义函数的理解:
(1)写一个函数可以找出两个整数中的最大值:
//找出两个整数中的最大值
int MAX(int x, int y)//int——返回类型;MAX——函数名;x,y——函数参数;
{
if (x >= y)//通过if语句实现找出两数中的最大值;
return x;
else
return y;
}
int main()
{
int a, b;//定义参数;
scanf("%d%d", &a, &b);//通过scanf函数给两参数赋值;
int c = MAX(a, b);//将参数a,b传送给自定义函数MAX,并将MAX的返回值赋值给c;
printf("MAX=%d\n", c);
return 0;
}
下面我们输入55、89来看一下运行结果:
这里我们也可以通过三目操作符来实现函数:
//找出两个整数中的最大值
int MAX(int x, int y)//int——返回类型;MAX——函数名;x,y——函数参数;
{
return (x >= y ? x : y);
}
int main()
{
int a, b;//定义参数;
scanf("%d%d", &a, &b);//通过scanf函数给两参数赋值;
int c = MAX(a, b);//将参数a,b传送给自定义函数MAX,并将MAX的返回值赋值给c;
printf("MAX=%d\n", c);
return 0;
}
这里我们也可以输入55、89来看一下运行结果:
我相信各位朋友通过这个例子能够更好的理解自定义函数了,下面我们接着看下一个例子;
(2)写一个函数可以交换两个整型变量的内容:
这个内容我们之前也接触过很多次了,前面我们都是直接在主函数中完成交换内容的,那么今天我们来尝试一下通过自定义函数来完成交换内容:
//写一个函数可以交换两个整型变量的内容
void swap(int x, int y)//void——无返回类型;swap——函数名;x、y——参数;
{
int z = x;//函数体——交代函数如何实现
x = y;
y = z;
}
int main()
{
int a = 1;
int b = 2;
printf("a=%d b=%d\n", a, b);
swap(a, b);
printf("a=%d b=%d\n", a, b);
return 0;
}
像这样我们是不是就已经完成了这个任务,接下来我们运行来看一下:
诶!不对呀,按照起前面的方法,现在我们应该是成功交换了呀,为什么a,b的值没有交换呢?下面我们来调试一下,看看问题出在了哪里:
这里我们可以看到,此时参数a/b的值成功的传输给了x/y,屏幕上也正常打印了此时a/b的值,接下来我们继续运行完成交换:
这里我们可以看到,此时x/y的值已经完成了交换,但是a/b还是原先的值,想必有些朋友跟我一样都很疑惑吧,别着急,下面就是我对这个内容的理解,你们可以跟随我的思路一起来思考一下:
我们在搞清楚为什么它们的值并没有交换这个问题前,我们先要思考,这里能不能用x/y来代替a/b。现在我们需要回顾一下在初识C语言18中提到的指针的知识点——我们在定义变量的时候就是向内存申请了一块空间来存放数据,那我们现在再来看一下a/b/x/y四个变量的空间地址,我们可以清楚的看到,空间地址并不相同,也就是说,它们四个是四个不同的变量,那这样就很好理解了:
现在就好比有四个人,张三、李四、王五、赵六,张三和李四今天穿的一个是黑T恤,一个是白T恤,王五和赵六看到了很喜欢,王五找张三要了黑T恤的链接买了一件一模一样的,赵六则向李四要了白T恤的链接买了一件一模一样的 ,所以当快递到达时,王五身上的T恤就和张三的T恤是一样的,赵六身上的T恤就和李四的T恤是一模一样的,接下来,王五和赵六相互交换了自己的T恤,这一下王五的T恤就和李四的是一样的了,赵六身上的T恤就和张三的是一样的了,但是在这个过程中,张三和李四并未有过交换T恤的举动,所以在交换完之后,张三和李四身上的T恤就没有发生改变,真正变的是王五和赵六。
既然这样我们就要想办法使得x就代表的是a,y就代表的是b呀!我们继续回顾指针的知识点——我们可以通过取地址操作符将变量的地址给取出来存放在指针中,再通过解引用操作符就可以将被存放的地址给取出来进行正常使用。此时解引用的对象就等价于原对象,这里可能不太好理解,没关系,我们用代码来进一步理解:
//写一个函数可以交换两个整型变量的内容
void swap2(int* x, int* y)//因为传送过来的是地址,所以函数需要接收地址,这里定义的就是指针类型的x、y;
{
int z = *x;//*——解引用操作符,此时的*x等价于变量a,所以这里需要有整型变量来接收a的值;
*x = *y;//*y等价于b,此时将*y赋值给*x就等价于b赋值给a;
*y = z;//最后将带有a值的z赋值给*y,也就等价于将b值赋值给a,此时完成两数交换;
}
void swap(int x, int y)//void——无返回类型;swap——函数名;x、y——参数;
{
int z = x;//函数体——交代函数如何实现
x = y;
y = z;
}
int main()
{
int a = 1;
int b = 2;
printf("a=%d b=%d\n", a, b);
swap2(&a, &b);//将a、b的地址传送进函数swap2;
printf("a=%d b=%d\n", a, b);
return 0;
}
这里我们可以看到,在函数swap2中我们的参数类型是指针类型,接收的是地址,也就是此时的x、y的地址与a和b的地址一致,紧接着我们在函数体内通过解引用操作符将a和b的值分别取出来赋值给变量z和*x最后再将变量z赋值给*y完成值的交换,经过这一系列操作后,最终完成a、b值的互换。那结果会如我们所想的一样吗?我们来运行验证一下:
这里我们可以看到此时x与a地址相等,y与b地址相等,*x的值等于a的值,*y的值等于b的值:
此时我们还是一样完成了*x与*y的值的交换,a和b此时的值是不变的,但是我们可以观察到虽然x和y与a和b的地址相同,但是此时里面的值是不同的,那我们接着运行又会出现什么结果呢:
这里我们可以看到,在函数swap2运行完后将内容传送回来时,a和b的值进行了交换,此时x和a,y和b地址里的值也都相同了,我们通过指针的相关知识确实完成了通过自定义函数进行两个数值的交换。为什么在进行比大小的时候不需要用指针,而这里需要用指针呢?这个问题我们先保留,下一篇会继续展开说明。
那今天的内容到这里就结束了,希望本篇的内容能够帮助大家更好的去理解库函数与自定义函数,同时也希望大家在看完本篇内容后学会借助工具来学习库函数。接下来随着学习的深入,我会继续给大家分享我在学习过程中的感受,感谢大家的翻阅,咱们下一篇再见。
标签:函数,自定义,int,小白,T恤,历程,我们,库函数 From: https://blog.51cto.com/u_16231477/7499830