C语言函数知识点小结

函数的作用

  1. 代码更简洁,避免重复
  2. 程序更模块化,可读性更强
  3. 便于修改

函数名的四种含义

函数名的4种含义
看函数名后面是否有圆括号
看函数最后是否有分号
函数的地址
看函数名前是否有显式的类型
函数的声明
参数的个数和类型
返回的类型
函数的调用
函数的定义
进入函数并执行函数内的语句
相当于黑箱
具体描述了函数的动作

传递参数

传参的工作原理

  • 无论参数的数据类型是什么,传参都是传入参数的
  • 当实际参数的类型与形式参数类型不一致时,传给函数的参数的值相当于实际参数赋给与函数形参类型相同的变量所得到的值
  • 形参是局部变量,作用域(本文后面会提到)只在函数内部。
#include 

int f(int i)
{
	return 0;
} 

int main()
{
	int j;
	j = f(7);
}

如上代码,调用f函数的过程即

int j;
int i = 7;
j = 0;

解释:

  1. 定义int型变量j
  2. 定义int型变量i,并将7赋值给i
  3. 将返回的0值赋值给j

当形参是指针时,调用函数的原理也同上

#include 

void change1(int i, int j)
{
	int k = i;
	i = j;
	j = k;
	return;
} 

void change2(int *i, int *j)
{
	int k = *i;
	*i = *j;
	*j = k;
	return;
} 

void change3(int *i, int *j)
{
	int *k = i;
	i = j;
	j = k;
	return;
} 

int main()
{
	int p = 0;
	int q = 1;
	int *m = &p;
	int *n = &q;
	
	change1(p, q);
	if(p)
	{
		printf("change1成功交换了2个数!\n");
	}
	else
	{
		printf("change1无法交换2个数\n");
	}
	change1(p, q);
	
	change2(m, n);
	if(p)
	{
		printf("change2成功交换了2个数!\n");
	}
	else
	{
		printf("change2无法交换2个数\n");
	}
	change2(m, n);
	
	change3(m, n);
		if(*m)
	{
		printf("change3成功交换了2个指针!\n");
	}
	else
	{
		printf("change3无法交换2个指针\n");
	}
	change3(m, n);		 
}

输出结果如下
C语言函数知识点小结_第1张图片 传递指针时传给被调用函数的是指针的值,也就是指针指向对象的地址,因此将指针传入时,指针指向对象的值可以通过指针进行间接的修改(见change2),但指针的内容无法通过函数进行修改(见change3)。

参数格式

定义 声明 调用
在每个变量前都声明其类型 用逗号分隔参数,可省略变量名,此时并未给变量分配实际的内存空间 括号内的表达式被求值,传给函数
#include 
void f(int i)
{
	printf("%d\n", i);
	return;
}
int main()
{
	int x = 0;
	int y = 0;
	f(++x);
	f(y++);
	printf("x = %d, y = %d", x, y);
}

C语言函数知识点小结_第2张图片可见,第一次调用f的时候传入的是++x,第二次调用f传入的是y++。两次调用都在主函数main中对对应变量进行了求值,因此最终打印的结果为x和y都是1。

参数列表为空vs参数列表是"void"

函数声明的参数列表为空时,支持ANSI C的编译器将不会检查函数声明与函数定义的参数是否匹配;而更老的编译器则会对参数类型进行"猜测",有时程序能通过,但会带来不可预知的结果。
参数列表是void则调用函数时不传递任何参数。

用return语句传出

return的工作原理

从执行return语句开始,被调用函数中定义的局部自动变量释放内存空间,return后的表达式的返回值(可能是具体值,也可能是地址)被拷贝到调用点。
注意:
1.当返回类型是指针时必须返回调用点可视范围内的变量
2.实际得到的返回值相当于把函数中得到的返回值赋给与函数返回类型相同的变量所得到的值
(有点绕)

返回值不仅可以赋给变量,还可以被用作表达式的一部分。
返回值不一定是变量的值,也可以是任意表达式的值。
——《C Primer Plus》

返回值是指针

int j;
int *f(int i)
{
	return &i;//错误,返回时i被释放了,在main函数中无法检测到此变量
	return &j;//正确
} 

int main()
{
	int m;
	int *ptr = f(m);
}

return后表达式的值与返回类型不一致

#include 

int f(double d)
{
	printf("%lf ", d);
	return d;
}

int main()
{
	double x = 1.5;
	int y = 1;
	printf("%d\n", f(y));
	printf("%d\n", f(x));
}

输出结果如下:
C语言函数知识点小结_第3张图片由此可见,类型为int的y在传入函数时被转化为double类型,而在f()函数中,类型为double的d在传出函数时被转化为int类型。

作用域和生命周期

二者的区别

  • 作用域是指某变量在代码块中可视范围
  • 生命周期是指某变量在运行时存在的一段时间
#include 

int i;
void func()
{
	static int m;
	printf("%d\n", m);
	m = 5;
}

int main()
{
	int j;
	{
		int k;
	}
	func();
	func();
}

在这段代码,i、func在整个代码段中可视,m在func函数中可视,j在main函数中可视,k在main的内层大括号中可视;变量m在运行过程中一直存在,且只在第一次定义时自动初始化为0,而第二次输出的m是在第一次调用func函数后赋值为5的结果,故输出结果如下:
C语言函数知识点小结_第4张图片

你可能感兴趣的:(C语言函数知识点小结)