一、函数概述

1、首先什么是函数?

函数是用于完成特定任务的程序代码的自包含单元。

2、为什么使用函数?

第一、函数的使用可以身故重复代码的编写。第二、函数使得程序更加模块化,有利于程序的阅读修改和完善。

3、main函数原型

int main (int argc, char * argv[], char * envp[]) {....}

第一个参数:命令行参数的个数

第二个参数:命令行参数的地址信息

第三个参数:环境表的首地址

参数argc表示输入参数的个数(含命令名),如果有命令行参数,argc应不小于1;argv表示传入的参数的字符串,是一个字符串数组,argv[0]表示命令名,argv[1]指向第一个命令行参数;至于第三个参数env,它与全局变量environ相比也没有带来更多益处,所以POSIX.1也规定应使用environ而不使用第三个参数。通常用getenv和putenv函数来存取特定的环境变量,而不是直接使用environ变量。例如:

//main函数原型的使用
#include <stdio.h>
int main(int argc,char* argv[],char* envp[])
{printf("argc=%d\n",argc);int i=0;for(i=0;i<argc;i++){printf("感谢%s\n",argv[i]);}//声明全局变量extern char** environ;printf("environ=%p,envp=%p\n",environ,envp);//直接访问环境表return 0;
}
输出结果为:
argc=1
感谢./a.out
environ=0xbfab74cc,envp=0xbfab74cc

再如:

命令行为:myprogram c:\a.txt c:\b.txt
则:argc==3
argv[0]=="myprogram"
argv[1]=="c:\\a.txt"
argv[2]=="c:\\b.txt"

再再如:

#include <stdio.h>
int main (int argc, char *argv[])
{int count;printf ("The command line has %d arguments: \n", argc - 1);for (count = 1; count < argc; count++)printf ("%d: %s\n", count, argv[count]);printf ("\n");return 0;
}
输出结果:
tarena@ubuntu:~/project/C$ ./a.out I LOVE YOU
The command line has 3 arguments:
1: I
2: LOVE
3: YOU


每个C程序都必须有一个 main 函数,因为它是程序执行的起点。关键字 int 表示函数返回一个整型值,关键字 void 表示函数不接受任何参数。main 函数的函数体包括左花括号和与之匹配的右花括号之间的任何内容。

注意:如果没有写明返回值,一般默认为 int 类型。

main (void)
{
...return 0;
}

二、函数声明和定义

1、函数声明

在任何程序在使用函数之前都需要声明该函数的类型。

例如:int imax (int a, int b);

第一个int指的是函数类型;位于圆括号内的两个int表明该函数的形式参数为int类型。分号的作用表示该语句是进行函数声明而不是函数定义。

在函数原型中可以根据自己的喜好省略变量名。

int imax (int , int);

需要注意的是这些变量名只是虚设的名字,他们不必和函数定义中使用的变量名想匹配。使用这种函数原型信息,编译器就可以检查函数调用语句是否和其原型声明一致。比如检查参数个数是否正确,参数类型是否匹配。将声明语句放置在main ()之前和之内两种方式都是正确的。需要重点注意的是函数声明要在使用函数之前进行。当在main之前函数定义的话,就不需要声明语句了。

#include <stdio.h>
int imin (int, int);
int main (void)
{int inim (int, int);
}

2、隐式声明

如果被调用函数写在调用函数后面则编译器会猜测被调用函数的格式,这叫做函数的隐式声明。隐式声明可以和实际情况不一致这时就会出错,可以把被调用函数的声明单独写在文件开头,这叫做函数的显示声明。除了主函数以外的所有函数都应该进行显示声明,因为主函数永远不是被调用函数。如果main()之后又函数定义,main()之前却没有函数声明的话,编译的时候会出现隐式声明报错。

3、头文件的使用

如果把main ()函数放在第一个文件中吧自定义哈拿书放在第二个文件中实现,那么第一个文件仍需要使用函数原型。如果把函数原型放在一个头文件中,就不必每次使用这些函数时输入其原型声明了。

#ifndef  __02READ_H__
#define __02READ_H__
extern int num;     //主函数全局变量写在了头文件里且要加extern关键字
int read(char, int); //函数声明
#define PI 3.14
#endif 

4、函数定义
函数声明只是将函数类型告诉编译器,而函数定义部分则是函数的实际实现代码。之所以使用函数原型,是为了在编译器编译第一个调用函数的语句之前想其表明该函数的使用方法。因此,可以在首次调用某函数之前对该函授进行完整的定义。这样函数定义部分就和函数原型有着相同的作用。通常对较小的函数会这样做:

//下面既是一个函数的定义,也是它的原型
#include <stdio.h>
int imax (int a, int b)
{return a > b ? a : b;
}int main (void)
{int x, z;scanf ("%d", &x);z = imax (x, 50);printf ("%d\n", z);return 0;
}

三、函数形参与实参

1、形式参数

函数定义为下面的函数:

void show (char ch, int num)

这行代码通知编译器show()使用名为ch和num的两个参数,并且这两个参数的类型分别为char和int。变量ch和num被称为形式参数。

注意:ANSI C形式要求在每个变量前声明其类型。也就是说,不能像通常变量声明那样使用变量列表声明同一类型的变量。如下所示:

void dibs (int x, y, z)  /*不正确的函数头*/

void dibs (int x, int y, int z)  /*正确的函数头*/

2、实际参数

函数调用中,通常使用实际参数对ch和num赋值,如:

show (SPACE, 12);

形式参数是被调函数中的变量,而实际参数是调用函数分配给被调用函数变量的特定数值。实际参数可以是常量、变量或一个复杂的表达式。但是无论何种形式的实际参数,执行时首先要计算其值,然后将该值复制给被调用函数中相应的形式参数。

3、无参数

void dibs (void);

为了表示一个函数确实不使用参数,需要在圆括号内加入void关键字。

四、递归函数

1、递归介绍

C允许一个函数条用其本身,这种调用过程被称为递归。

递归与循环比较:

采用递归函数解决问题的思路叫递归
采用循环解决同样问题的思路叫递推

递归一般可以代替循环语句使用。有些情况下使用循环语句比较好,而有些时候使用递归更有效。递归方法虽然使用程序结构优美,但其执行效率却没有循环语句高。一般来说,选择循环更好一些。首先,因为每次递归调用都拥有自己的变量集合,所以就需要占用较多的内存;每次递归调用需要把心的变量集合存储在堆栈中。其次,由于进行每次函数调用需要花费一定的时间,所以递归的执行速度较慢。

//示例一
#include <stdio.h>
void show (int);int main (void)
{show (1);return 0;
}void show (int n)
{printf ("Level %d: n location %p\n", n, &n);if (n < 4)show (n + 1);printf ("Level %d: n location %p\n", n, &n);
}执行结果如下:
Level 1: n location 0xbf8bf680
Level 2: n location 0xbf8bf660
Level 3: n location 0xbf8bf640
Level 4: n location 0xbf8bf620
Level 4: n location 0xbf8bf620
Level 3: n location 0xbf8bf640
Level 2: n location 0xbf8bf660
Level 1: n location 0xbf8bf680
//示例二
#include <stdio.h>void print (int num)
{if (num == 1){printf ("1\n");return ;}printf ("%d\n", num);print (num -1);
}int main (void)
{print (10);return 0;
}
输出结果:
10
9
8
7
6
5
4
3
2
1

2、递归的基本原理

第一:每一级的函数调用都有自己的变量。

第二:每一次函数调用都会有一次返回。

第三:递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序。

第四:递归函数中,位于递归调用后的语句的执行顺序和各个被调用函数的顺序相反。

第五:虽然每一级递归都有自己的变量,但是函数代码并不会得到复制。

最后:递归函数中必须包含可以终止递归调用的语句。

3、递归的优缺点

其优点在于为某些变成问题提供了最简单的解决方法,而缺点是一些递归算法会很快耗尽计算机的内存资源。同时,使用递归的程序难于阅读和维护。

五、指针函数和函数指针

指针函数:返回指向char的指针的函数,例如:char * fump ( );
函数指针:指向返回类型char的函数指针,例如:char (* frump) ( );
这里需要明白一个符号之间优先级的问题,"( )"的优先级比"*"要高。

再考虑一个,char (* flump[3]) ( );

由3个指针组成的数组,每个指针指向返回类型为 char 的函数。

C语言再学习 -- 函数相关推荐

  1. C语言再学习 -- 时间函数

    在软件设计中经常会用到关于时间的处理,用来计算语句.函数的执行时间,这时就需要精确到毫秒甚至是微妙的时间.我们首先来介绍一下,时间单位: 时间单位还有:秒(s).毫秒(ms).微秒 (μs).纳秒(n ...

  2. C语言再学习 -- 字符串和字符串函数

    最近身体很不给力,很乏累!白天没精神,晚上睡不着,心情还很烦躁.看书都有点看不下去的样子,到了C语言最难掌握的部分了,数组.指针.字符串.硬着头皮看书总结吧. 一.字符串 1.字符串介绍 字符串是以空 ...

  3. C语言再学习 -- 关键字return和exit ()函数

    终于到了最后一个关键字 return 了.感觉时间过的飞快,转眼间又是一年,如果时间可以 return 就好了. 一.return 介绍 参看:C语言中return 用法 1.含义: return 表 ...

  4. C语言再学习--关键字

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/53021879 C语言一共有32个关键字,如下表所示: 关键字 说明 auto ...

  5. UNIX再学习 -- 函数abort

    abort 函数之前有讲过的,参看:C语言再学习 -- 关键字return和exit ()函数 然后我们在讲 8 中进程终止时,也说过.参看:UNIX再学习 -- exit 和 wait 系列函数 下 ...

  6. C语言再学习 -- 再论内存管理

    之前有总结过内存管理,参看:C语言再学习 -- 内存管理 但现在看来,缺少示例.从新再写一篇文章,着重介绍常见内存错误.跨函数使用存储区.开始吧,再论内存管理!! 发生内存错误是件非常麻烦的事情.编译 ...

  7. C语言再学习 -- 详解C++/C 面试题 2

    (经典)C语言测试:想成为嵌入式程序员应知道的0x10个基本问题. 参看:嵌入式程序员面试问题集锦 1.用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define ...

  8. C语言再学习 -- 详解C++/C 面试题 1

    参看:<高质量C++ C编程指南>.林锐 对这篇文章记忆犹新,因为之前找工作面试的时候,遇到过一家公司就是用的这套面试题.现在就结合考查的知识点和我总结完 C 语言再学习后的深入理解,来详 ...

  9. C语言再学习 -- 再论数组和指针

    之前有总结指针数组,但是现在看来总结的太简单了.好多重要的知识点都是一带而过的.本想在后面添加后来想想算了,还是再写一篇文章来详细介绍数组和指针这对冤家吧. 之前总结的,参看:C语言再学习 -- 数组 ...

最新文章

  1. es创建索引设置字段不分词_ES的使用笔记
  2. 寻找最大的K个数(上)
  3. python像素大于_用python处理图片实现图像中的像素访问
  4. django安装初步使用命令整理
  5. 关于 xml 库运行时的segmentation fault 问题
  6. 小巧优美的ORM框架-doodads
  7. 自定义DrawableTextView——实现TextView左上右下的点击监听
  8. 抓糗百数据和图片的Python爬虫
  9. ConfigParser.InterpolationSyntaxError: ‘%‘ must be followed by ‘%‘ or ‘(‘, found: “%‘“
  10. iOS键盘监听以及获取键盘高度
  11. Panasonic: FP-X0 L30R 使用 FPWIN GR7 通讯及编程
  12. 服务器装系统就蓝屏,重装了下系统老是蓝屏
  13. 短视频发布之前要注意什么?从配音到发布时间,选对才能吸粉引流
  14. eot文件html,html – 为什么IE8没有加载我的eot文件?
  15. 显卡性能比较 GPU common sense
  16. linux下的程序开发实验,Linux程序实验.docx
  17. 阿里云人工智能pai云计算平台使用方法
  18. 全球及中国LCP行业发展动态与投资趋势分析报告2022~2028年
  19. 机器学习算法--分类的衡量指标(误差矩阵或混淆矩阵)
  20. 如何实现报表的动态列展现效果

热门文章

  1. 2017-2018-2 20155228 《网络对抗技术》 实验四:恶意代码分析
  2. Chrome浏览器密码框自动填充的bug
  3. 区域增长——初步学习
  4. C++用法的学习心得
  5. spark on mesos 两种运行模式
  6. Deeplearning入门篇(2)
  7. 多台工作站搭建MPI并行环境
  8. 直接排序python实现
  9. 一爱就是一辈子:坚持4年的编程爱好
  10. 台湾大学林轩田机器学习基石课程学习笔记7 -- The VC Dimension