C函数的所有参数均以“传值调用”方式进行传递。
这意味着函数将获得参数值的一份拷贝,这样函数可以放心修改这个拷贝值,而不必担心会修改调用程序实际传递给它的参数。
作为函数参数的普通数据类型
普通数据类型主要包括:
- 整型
- 浮点型
如下面代码所示:
#include <stdio.h>
void swap(int x , int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int main() {
int a = 10 , b = 20;
printf("before swaping : %d , %d \n" , a , b);
swap(a , b);
printf("after swaping : %d , %d \n" , a , b);
return 0;
}
我们原本是希望编写一个函数,其目的是交换调用程序所传递的这两个参数的值。
但是,这个程序是无效的!
因为函数实际交换的是参数的拷贝,原先的参数值并没有进行交换。
作为函数参数的指针
C函数的所有参数均以“传值调用”方式进行传递,这意味着函数将获得参数值的一份拷贝。
如果被传递的参数是一个指针,那么函数将获得这个指针的一份拷贝。
如果函数对指针执行间接访问操作,将会访问指针所指向的内存位置。
#include <stdio.h>
void swap(int *x , int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main() {
int a = 10 , b = 20;
printf("before swaping : %d , %d \n" , a , b);
swap(&a , &b);
printf("after swaping : %d , %d \n" , a , b);
return 0;
}
作为函数参数的数组
如果想把一个数组名参数传递给函数,正确的函数形参应该是什么样呢?应该声明为一个指针还是一个数组呢?
由于数组名的值实质上就是一个指针,传递给函数的就是这个指针的一份拷贝。下标引用实际上就是间接访问的另一种形式,它可以对指针执行间接访问操作,访问指针指向的内存位置。参数(指针)实际上是一份拷贝,但在这份拷贝上执行间接访问操作所访问的是原先的数组。
所以,下面两个函数原型都是相等的:
void clear_array(int array[] , int n_element);
void clear_array(int arra*y , int n_element);(推荐)
首先,我们回答两个问题:
- 为什么函数原型中的一维数组形参无需写明它的元素数目?
- 因为函数并不为数组参数分配内存空间,形参只是一个指针,它指向的是已经在其他地方分配好内存的空间。
- 为什么数组形参可以与任何长度的数组匹配?
- 数组形参实际传递的只是指向数组第一个元素的指针,所以数组形参可以与任何长度的数组匹配。
- 但是,这样会导致函数无法知道数组的长度。
- 如果函数需要知道数组的长度,数组长度必须作为一个显示的参数传递给函数。
#include <stdio.h>
void clear_array(int *array , int n_element)
{
for (int i = 0; i < n_element; ++i) {
array[i] = 0;
}
}
int main()
{
int vector[] = {0,1,2,3,4,5,6,7,8,9};
clear_array(vector , 10);
for (int i = 0; i < 10; ++i) {
printf("%d, " , vector[i]);
}
}
作为函数参数的结构
结构变量是一个标量,它可以用于其他标量可以使用的任何场合。
因此,把结构作为参数传递给一个函数是合法的,但这种做法往往并不适合。
#include <stdio.h>
#define PRODUCT_SIZE 5
typedef struct {
char product[PRODUCT_SIZE];
int quantity;
float unit_price;
float total_amount;
} transaction;
void print_receipt(transaction trans)
{
printf("%s\n" , trans.product);
printf("%d @ %.2f total %.2f\n" , trans.quantity , trans.unit_price , trans.total_amount);
}
int main()
{
transaction transaction1 = {{'l','i','e','v','s'} , 80 , 12.5 , 1000.0};
print_receipt(transaction1);
}
这种方法能够产生正确的结果,但它的效率很低。
这是因为C语言的参数调用方式要求把参数的一份拷贝传递给函数,如果这个结构占据100个字节的内存空间,将这个结构作为参数进行传递时,我们必须把100个字节复制到堆栈中,以后再丢弃。
但是,如果我们传递给函数的是一个指向结构的指针,由于指针比整个结构小很多,所以把它压倒堆栈上的效率能提高很多,结构越大,把指向它的指针传递给函数的效率就越高。
但是,向函数传递指针的缺陷在于
- 我们必须在函数中使用间接访问来访问结构的成员。
- 函数可以对调用程序的结构变量进行修改,如果我们不希望如此,可以在函数使用const关键字来防止这类修改。
#include <stdio.h>
#define PRODUCT_SIZE 5
typedef struct {
char product[PRODUCT_SIZE];
int quantity;
float unit_price;
float total_amount;
} transaction;
void print_receipt(const transaction *trans)
{
printf("%s\n" , trans->product);
printf("%d @ %.2f total %.2f\n" , trans->quantity , trans->unit_price , trans->total_amount);
}
int main()
{
transaction transaction1 = {{'l','i','e','v','s'} , 80 , 12.5 , 1000.0};
transaction *transaction2 = &transaction1;
print_receipt(transaction2);
}