再探函数参数

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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值