C —— 函数

函数是指一段可以直接被另一段程序引用的程序。也叫做子程序、(OOP中)方法。

函数

函数是指一段可以直接被另一段程序引用的程序。也叫做子程序、(OOP中)方法。

每个 C 程序都至少有一个函数,即主函数 main() ,并且可以自定义其他的函数。

例如在上一篇《循环结构 》中判断某个自然数是否是质数的这段代码就可以提取成为一个单独的函数,示例如下:

/**
 * 判断数字是否是质数
 * @param number
 */
int isPrimeNumber(int number) {
	if(number < 1) {
		return 0;
	}
	if(number < 4) {
		// 如果比 4 小,则只要是大于1 的自然数都是质数
		return number > 1;		
	}
	
	int i = 2;
	do {
		if(number % i == 0) {
			return 0;
		}
		i++;
	} while(i < number);
	
	return 1;
}

所以,在[1, 100]内有多少个质数的程序可以修改为:

#include<stdio.h>

/**
 * 判断数字是否是质数
 * @param number 需要判断的自然数
 */
int isPrimeNumber(int number) {
	if(number < 1) {
		return 0;
	}
	if(number < 4) {
		// 如果比 4 小,则只要是大于1 的自然数都是质数
		return number > 1;		
	}
	
	int i = 2;
	do {
		if(number % i == 0) {
			return 0;
		}
		i++;
	} while(i < number);
	
	return 1;
}

int main() {
	int top = 100, number = 0, count = 0;
	while(number < top) {
		number++;
		count += isPrimeNumber(number) ? 1 : 0;
	};
	printf("%d.\n", count);	
	
	return 0;
}

不难发现,一旦使用了函数,将判断质数的代码块提取到 main 函数外后,main 函数里的代码变得格外的简洁。整个程序被分为两个函数,一个是主函数,另一个是用于判断某个自然数是否是质数的函数。

函数 isPrimeNumber 存在的意义是为了判断某个自然数是否是质数,故而,函数需要入参和返回,入参是需要判断的自然数,返回的结果是一个布尔值,外部程序可以通过该布尔值知道传给该函数的自然数是否是质数。

C 语言中的函数定义的一般形式如下:

返回类型 函数名称(形式参数列表) {
	// do something here.
}

其中,返回类型 函数名称(形式参数列表) 称之为 函数签名,也叫做 函数头;而一对大括号及其内部的所有的代码被称之为 函数体;所以,函数由函数签名和函数体两部分组成。需要注意的是,函数不像 if 或者 for 那样,当代码只有一行的时候可以省略大括号,无论函数中是否有代码或有几行代码,都不允许省略大括号!如果只是声明函数,可以省略函数体,但是这样的函数是在使用前必须有完整的函数体,否则在编译的时候出错导致编译失败。

如果一个函数的形式参数不止一个,那么逐个放置在小括号中,使用逗号隔开即可。如下所示:

int fun() {return 1;}
int fun1(int a) {return 1;}
int fun2(int a, int b) {return 1;}
int fun3(int a, int b, double c) {return 1;}

在调用对应函数的时候,需要根据需要依次按类型给函数传递对应的参数。而函数返回的结果需要在该函数调用处函数名前面声明对应的变量来接收,当然也可以选择不接收。如下所示:

int a = fun();
fun1(10);
a = fun2(10, 30);
int c = fun3(10, 30, 3.14);

如果函数没有返回值,则声明为 void 。如下所示:

void fun(){}

函数参数传值

向函数传递参数的传值调用方法,把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。如下例所示:

#include<stdio.h>

/**
 * 交换两个数
 */
void swap(int x, int y) {
	printf("\tbefore swap. x = %d, y = %d.\n", x, y);
	int z = x;
	x = y;
	y = z;
	printf("\tafter swap. x = %d, y = %d.\n", x, y);
}

int main() {
	int a = 10, b = 20;
	printf("before swap. a = %d, b = %d.\n", a, b);
	swap(a, b);
	printf("before swap. a = %d, b = %d.\n", a, b);
	return 0;
}

执行结果:

before swap. a = 10, b = 20.
        before swap. x = 10, y = 20.
        after swap. x = 20, y = 10.
before swap. a = 10, b = 20.

不难发现,从 main 函数中已经成功将值传递到函数 swap 内部,并实现交换,但是这种传递方式不影响 main 函数中的两个变量的值。

函数参数传址

  1. 通过引用传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。
  2. 传递指针可以让多个函数访问指针所引用的对象,而不用把对象声明为全局可访问。

如下例所示:

#include<stdio.h>

/**
 * 交换两个数
 */
void swap(int *x, int *y) {
	printf("\tbefore swap. x = %d, y = %d.\n", x, y);

	int z = *x;
	// printf("swaping. *x = %d, *y = %d, z = %d.\n", *x, *y, z);
	*x = *y;
	// printf("swaping. *x = %d, *y = %d, z = %d.\n", *x, *y, z);
	*y = z;
	// printf("swaping. *x = %d, *y = %d, z = %d.\n", *x, *y, z);

	printf("\tafter swap. x = %d, y = %d.\n", x, y);
}

int main() {
	int a = 10, b = 20;
	printf("before swap. a = %d, b = %d.\n", a, b);
	swap(&a, &b);
	printf("before swap. a = %d, b = %d.\n", a, b);
	return 0;
}

执行结果:

before swap. a = 10, b = 20.
        before swap. x = 2293564, y = 2293560.
        after swap. x = 2293564, y = 2293560.
before swap. a = 20, b = 10.

不难发现,这种传递方式不是传递的值本身,而是传递的是两个变量的地址值,在函数内部使用 * 获取对应地址值使得两个地址中的值发生交换,进而让 main 函数中的两个变量的值发生变化。

有关指针的更多内容请移步到《指针

函数的先后关系

在上面的案例中,源程序包含两个函数分别是 swap 和 main, 而且是先编写了 swap 函数,再编写 main 函数,如果将两个函数的位置交换位置,会在编译源程序的时候,可能会出现两个警告个一个提示:

warning: implicit declaration of function 'swap' [-Wimplicit-function-declaration]
...
warning: conflicting types for 'swap'
...
note: previous implicit declaration of 'swap' was here

这是因为在编译器在编译源程序的时候,是自上往下逐行解析源代码的,当遇到在 main 函数中遇到 swap 之前没有发现该函数在此之前被声明过就被使用了。故而,推荐的做法是,将 自定义的函数写在 main 函数的前面,或者,将函数签名写在 main 函数前面作为声明,这样编译器就不会在遇到 swap 函数的时候提示警告了。如下所示:

#include<stdio.h>

/**
 * 声明 swap
 */
void swap(int *x, int *y);

int main() {
	int a = 10, b = 20;
	printf("before swap. a = %d, b = %d.\n", a, b);
	swap(&a, &b);
	printf("before swap. a = %d, b = %d.\n", a, b);
	return 0;
}

/**
 * 定义 swap
 */
void swap(int *x, int *y) {
	printf("\tbefore swap. x = %d, y = %d.\n", x, y);

	int z = *x;
	// printf("swaping. *x = %d, *y = %d, z = %d.\n", *x, *y, z);
	*x = *y;
	// printf("swaping. *x = %d, *y = %d, z = %d.\n", *x, *y, z);
	*y = z;
	// printf("swaping. *x = %d, *y = %d, z = %d.\n", *x, *y, z);

	printf("\tafter swap. x = %d, y = %d.\n", x, y);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值