c语言之函数(一)
来源:互联网 发布:linux oracle 客户端 编辑:程序博客网 时间:2024/06/08 16:16
(一)函数(Function)是一段可以重复使用的代码,这是从整体上对函数的认识。
C语言本身带了很多库函数,并分门别类地放在了不同的头文件中,使用时只要引入对应的头文件即可。
除了C语言自带的函数,我们也可以编写自己的函数,称为自定义函数(User-Defined Function)。自定义函数和库函数没有本质的区别,表现形式和使用方法一样,只是开发者不同而已。
这一章我们就来讲解如何编写和使用自己的函数。
参数
函数的一个明显特征就是使用时带括号( ),必要的话,括号中还要包含数据或变量,称为参数(Parameter)。参数是函数需要处理的数据,例如:
strlen(str1)用来计算字符串的长度,str1就是参数。
puts("C语言中文网")用来输出字符串,"C语言中文网"就是参数。
返回值
既然函数可以处理数据,那就有必要将处理结果告诉我们,所以很多函数都有返回值(Return Value)。所谓返回值,就是函数的执行结果。例如:
char str1[] = "C Language";
int len = strlen(str1);
strlen() 的处理结果是字符串 str1 的长度,是一个整数,我们通过 len 变量来接收。
函数返回值有固定的数据类型(int、char、float等),用来接收返回值的变量类型要一致。
(二)递归函数
递归函数的定义,不应出现无终止的递归调用。而应定义为有限次数、有终止的递归调用函数。
对于一个问题,只要能够知道递归定义式,及边界条件(即递归终止的条件),就可以编写一个递归函数。
例题用递归函数的方法计算s=8^3
int sum(int n){ if (n>0) return(8*sum(n-1)); else return(1);}main(){ int sum(); printf("s=%d",sum(3));}
(三)局部变量和全局变量
1°
1) 在 main 函数中定义的变量也是局部变量,只能在 main 函数中使用;同时,main 函数中也不能使用其它函数中定义的变量。main 函数也是一个函数,与其它函数地位平等
2) 形参变量、在函数体内定义的变量都是局部变量。实参给形参传值的过程也就是给局部变量赋值的过程。
3) 可以在不同的函数中使用相同的变量名,它们表示不同的数据,分配不同的内存,互不干扰,也不会发生混淆。
4) 在语句块中也可定义变量,它的作用域只限于当前语句块。
2°
全局变量
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。
(四)指针变量作为函数返回值
C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。下面的例子定义了一个函数 strlong(),用来返回两个字符串中较长的一个:
#include #include char *strlong(char *str1, char *str2){ if(strlen(str1) >= strlen(str2)){ return str1; }else{ return str2; }} int main(){ char str1[30], str2[30], *str; gets(str1); gets(str2); str = strlong(str1, str2); printf("Longer string: %s\n", str); return 0;}
运行结果:
C Language↙
HelloWorld↙
Longer string: HelloWorld↙
用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据,C语言没有任何机制来保证这些数据会一直有效,它们在后续使用过程中可能会引发运行时错误。请看下面的例子:
#include#include char *strlong(char *str1, char *str2){ if(strlen(str1) >= strlen(str2)){ return str1; }else{ return str2; }} int main(){ char str1[30], str2[30], *str; gets(str1); gets(str2); str = strlong(str1, str2); printf("Longer string: %s\n", str); return 0;}
#include int *func(){ int n = 100; return &n;} int main(){ int *p = func(), n; n = *p; printf("value = %d\n", n); return 0;}
运行结果:
value = 100
n 是 func() 内部的局部变量,func() 返回了指向 n 的指针,根据上面的观点,func() 运行结束后 n 将被销毁,使用 *p 应该获取不到 n 的值。但是从运行结果来看,我们的推理好像是错误的,func() 运行结束后 *p 依然可以获取局部变量 n 的值,这个上面的观点不是相悖吗?
为了进一步看清问题的本质,不妨将上面的代码稍作修改,在第9~10行之间增加一个函数调用,看看会有什么效果:
#include int *func(){ int n = 100; return &n;} int main(){ int *p = func(), n; printf("c.biancheng.net\n"); n = *p; printf("value = %d\n", n); return 0;}
运行结果:
c.biancheng.net
value = -2
可以看到,现在 p 指向的数据已经不是原来 n 的值了,它变成了一个毫无意义的甚至有些怪异的值。与前面的代码相比,该段代码仅仅是在 *p 之前增加了一个函数调用,这一细节的不同却导致运行结果有天壤之别,究竟是为什么呢?
前面我们说函数运行结束后会销毁所有的局部数据,这个观点并没错,大部分C语言教材也都强调了这一点。但是,这里所谓的销毁并不是将局部数据所占用的内存全部抹掉,而是程序放弃对它的使用权限,弃之不理,后面的代码可以随意使用这块内存。对于上面的两个例子,func() 运行结束后 n 的内存依然保持原样,值还是 100,如果使用及时也能够得到正确的数据,如果有其它函数被调用就会覆盖这块内存,得到的数据就失去了意义。
第一个例子在调用其他函数之前使用 *p 抢先获得了 n 的值并将它保存起来,第二个例子显然没有抓住机会,有其他函数被调用后才使用 *p 获取数据,这个时候已经晚了,内存已经被后来的函数覆盖了,而覆盖它的究竟是一份什么样的数据我们无从推断(一般是一个没有意义甚至有些怪异的值)。
#includeint *func(){ int n = 100; return &n;} int main(){ int *p = func(), n; printf("c.biancheng.net\n"); n = *p; printf("value = %d\n", n); return 0;}
阅读全文
1 0
- c语言之函数(一)
- C语言函数(一)
- c 语言学习之printf函数(一)
- C语言函数(一)
- 【每日一C之十三】C 语言inline内联函数
- 【C语言】C语言字符串函数实现(一)
- C语言时间函数积累(一)
- C语言字符串函数集锦(一)
- C语言字符串函数集锦(一)
- C语言函数集(一)
- C语言:MessageBox()函数(一)
- C语言随记(一)—函数
- C语言--常用函数(一)
- 【一起来学C语言】函数(一)
- C语言面试题---函数(一)
- C语言之函数
- C语言之函数
- C语言之函数
- java一维数组打印杨辉三角
- 欢迎使用CSDN-markdown编辑器
- HDOJ 1874 畅通工程续 (dijkstra算法)
- LeetCode
- 安装Web Storm
- c语言之函数(一)
- 个人总结TP框架小结
- 杭电1242
- bzoj3357[Usaco2004]等差数列 DP
- 这几天看的一篇文章很有感触的文章
- 【转】漫谈Moq(一)
- 关于函数的重载、覆盖和重写(Overload、Overwrite、Override)
- 帧同步相关笔记
- iOS 多线程在项目中的应用场景(一)