9.函数

//函数
/*
函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
C 语言中的函数定义的一般形式如下:
return_type function_name( parameter list )
{
   body of the function
}
在 C 语言中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
	返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
	函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。	参数:参数就像是占位符。当函数被调用时,向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
	函数主体:函数主体包含一组定义函数执行任务的语句。
*/

//举个栗子
//下面这个函数将返回num1和num2中较大的那个数
#include <stdio.h>
int max(int num1, int num2)
{
	int result; //局部变量声明,用于存放最大值
	if (num1>num2)
	{
		result = num1;
	}
	else
	{
		result = num2;
	}
	//当然这里也可以使用三元运算符  result = (num1>num2)?num1:num2;
	return result;
}

//函数声明
/*
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
函数声明包括以下几个部分:
	return_type function_name( parameter list );
针对上面定义的函数 max(),以下是函数声明:
	int max(int num1, int num2);
在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:
	int max(int, int);
当在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,应该在调用函数的文件顶部声明函数。
*/

//调用函数 
/*
创建 C 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。例如:
*/
int max(int, int);
int main01()
{
	//局部变量定义
	int a = 100;
	int b = 200;
	int ret;
	
	//调用函数来获取最大值
	ret = max(a, b);
	printf("max value is %d\n"); //max value is 200
	return 0;
}


//关于传值调用和引用调用
//1.传值调用:传递的是值
//2.引用调用:传递的是指针

int swap_value(int x,int y)
{
	int tem;
	tem = x;
	x = y;
	y = tem;
	return 0;
}

int swap_pointer(int *x,int *y)//如果传递指针类型,只需要在参数前加个*
{
	int tem;
	tem = *x;
	*x = *y;
	*y = tem;
	return 0;
}

int main()
{
	int a=10;
	int b=20;
	printf("值传递前:a=%d,b=%d\n",a,b); //值传递前:a=10,b=20
	swap_value(a,b);
	printf("值传递后:a=%d,b=%d\n",a,b); //值传递后:a=10,b=20
	
	a = 40;
	b = 50;
	printf("指针传递前:a=%d,b=%d\n",a,b); //指针传递前:a=40,b=50
	swap_pointer(&a,&b); //指针传递后
	printf("指针传递后:a=%d,b=%d\n",a,b); //指针传递后:a=50,b=40
}
//我们来画图分析一下,为什么值传递和引用传递会有两个不同的结果

  

//笔记
/*
根据函数能否被本文件的其他函数所引用,将函数区分为内部函数和外部函数
内部函数:
	如果一个函数只能被本文件中的其他函数所调用,那么称这个函数为内部函数。
	定义内部函数时,在函数名和函数类型前面加上static,即static 类型名 函数名(参数)
	例如:函数的首行:static int max(int num1, int num2);
	内部函数又称静态函数,使用内部函数,使得函数的作用域只局限于所在文件。即使在不同的内部文件中,
	存在同名的内部函数,也互不干扰,提高程序的可靠性
外部函数:
	如果在定义函数时,在函数的最左端加上了关键字extern,则此函数是外部函数,可供其他文件调用
	extern int max(int num1, int num2);
内联函数     
	内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。
	内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。
	内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数,对于小内存空间的函数非常受益。
	使用内联函数的时候要注意:
		递归函数不能定义为内联函数
		内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。
		内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。
		对内联函数不能进行异常的接口声明。
	示例:一个简单的交换函数

	inline void swap(int *a, int *b)
	{
		int t = *a;
		*a = *b;
		*b = t;
	}
*/

//main函数的参数
/*
有的时候看到main的参数是这个int main( int argc, char *argv[] )
而我们一般写int main(),这两者有什么区别呢?
如果不加这两个参数,那么我们在执行的时候,只能通过./xx.exe
如果加上了参数,比方我在执行的时候加上一些其他的东西,./xx.c 古明地觉 椎名真白 牧濑红莉栖
*/
int main03(int argc, char *argv[])
{
	printf("%d\n", argc);  //4
	int i;
	for(i=0;i<argc;i++)
	{
		printf("%s\n",argv[i]);
	}
	/*
	C:\Users\Administrator\Desktop\C\(9)函数.exe
	古明地觉
	椎名真白
	牧濑红莉栖
	*/
	//可以看到一共argc打印了4,说明总共有四个参数。而argv是一个数组,保存一系列的指针
	//每一个指针都指向了我们输入的参数
	//提到指针提前插一嘴,如果指针p指向了一个字符数组,比方说"abcd",那么此时的p就有两种含义
	/*
		因为字符数组的地址就是其首元素的地址,因此对char s[]="abcd",&s=&s[0]
		所以如果以指针形式打印,那么打印出的结果就是字符数组首元素的内存地址
		如果以%s打印,那么打印出的结果就是这整个字符数组。因为通过字符数组的首元素,
		便可以将它剩下的元素也找到,因为数组是一片连续的内存空间
	*/
	//可以一块来验证一下
	//通过xx.exe abc bcd def, 那么argv里面应该有四个指针,当然我们就不看第一个了
	//我们来看一下第二个,argv[1]是第二个元素,以%p打印那么就是字符数组的首元素的地址,那么应该等于&argv[1][0]
	printf("%p--%p\n", argv[1], &argv[1][0]);  //009E1200--009E1200
	//也可以当做字符数组来用,上面也说了,数组是一片连续的内存空间。
	//数组的地址和首元素的地址一样,通过首元素的地址可以找到数组的其他元素。
	//当做指针来用,那么就是首元素的地址,当做数组来用的话,就是这个整个数组
	//argv[1]应该是abc,那么我们分析正确的话,应该打印a-b
	printf("%c-%c", argv[1][0],argv[1][1]); //a-b
	//可见我们分析正确的
}

//函数的递归
/*
	求1+2+3+4+······100的递归实例
*/
int recursion(int n)
{
	if (n==1)  //如果n==1,那么就返回1
	{
		return 1;
	}
	//如果大于1,就返回n+recursion(n-1)
	return n+recursion(n-1);
	/*
		其实很简单,recursion(100)-->100+recursion(99)-->100+99+recursion(98)-->100+99+····+2+recursion(1)
		recursion(1)==1,所以recursion(100)==100+99+98+····+1
	*/
}
//声明函数,不关心里面的参数如何,只要函数名返回值类型相同,参数个数和对应类型相同即可。形参叫什么名字无所谓
int recursion(int); 
int main()
{
	int sum = recursion(100);
	printf("1+2+····100=%d\n", sum); //1+2+····100=5050
}

//占位符
/*
	占位符就是占着一个位置,然后等着你往相应的位置里面添加内容
	一般使用的占位符如下:
		%d, %i 代表整数
		%f 浮点
		%s 字符串
		%c char
		%p 指针
		%fL 长log
		%e 科学计数
		%d 读入十进制整数。
		%i 读入十进制,八进制,十六进制整数。
		%o 读入八进制整数。
		%x,%X 读入十六进制整数。
		%s 读入一个字符串,遇空格、制表符或换行符结束。
		%f,%F,%e,%E,%g,%G 用来输入实数,可以用小数形式或指数形式输入。
		%p 读入一个指针。
		%u 读入一个无符号十进制整数。
		%n 至此已读入值的等价字符数。
		%[] 扫描字符集合。
		%% 读 % 符号
*/
	

  

猜你喜欢

转载自www.cnblogs.com/traditional/p/9463956.html