首页 函数传参
文章
取消

函数传参

传参分类

从传参类型上看

传参分为传值传指针

传指针本质上也是传值,只不过传的是指针值。由于传一般值和传指针值还是有点区别,所以分成两种说法。传值一般就指传一般值,传指针专门用于描述传指针值。

从传参行为上看

传参分为值复制传自己

传自己本质上也是值复制,只不过是取地址传无名指针,形参直接接上;而不是直接传有名指针。例如:

1
2
3
4
5
6
7
// 函数调用
func1(id, index, flag, &count);
func2(arr);

// 函数定义头
func1(int id, int index, int flag, int *p_count)
func2(int *arr)

其中,idindexflag 是值复制,这毫无疑义。arr 是数组名,这里退化为指针,直接进行了传参,也就是我说的“直接传有名指针”,所以我将其归为值复制。&count 是取地址传无名指针,然后形参直接接上,是传自己。

传参分析

传值是值复制。

传指针有两种情况,第一种是值复制,第二种是传自己,如图所示。

以下是一些经验,不一定正确,只能说这些场景遇到的比较多,看个眼熟就成。

  1. 值复制倾向于使用,传自己倾向于赋值。
  2. 一般而言,实参直接传为值复制,实参取地址为传自己。多数情况下,实参取地址可以理解为赋值。
  3. 形参中的值变量属于值复制,形参中的指针变量有上图两种情况。(其实就是传参分析的两条,这里着眼于形参。该经验一定正确。)
  4. 无论是为了使用还是赋值,传数组一般直接传数组名。
  5. char 为例。函数形参中,经常能看见 const char *char * 的使用。const char * 显然不会更改指针所指向内存的内容,但是 char * 就可能更改指针所指向的内容,这一点在实践中值得注意,即我们的内存传递给 char * 后有可能会被更改。

这里对经验4多说几句。我曾经以为,若是为了给数组赋值,应该对数组名取地址传参。一是因为输出参数一般都加&,写成类似下面这样,一眼就能看出哪些是出参,可读性高。二是觉得平时数组指针的概念都没怎么用过,在这里正好用起来,岂不美哉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 这是问题写法
#include <stdio.h>

void func(int, int (*)[], int *);

int main()
{
    int i = 0;
    int arr[10] = {0};
    int count = 5;
    int sum = 0;

    func(count, &arr, &sum);
    for (i = 0; i < count; i++)
    {
        printf("%d\n", arr[i]);
    }

    printf("sum = %d\n", sum);
    
    return 0;
}

void func(int count, int (*parr)[10], int *p_sum)
{
    int i = 0;
    int sum = 0;

    for (i = 0; i < count; i++)
    {
        (*parr)[i] = i;
        // parr[0][i] = i;
        sum += i;
    }

    *p_sum = sum;
}

然而后来我发现了自己的错误,不要这样传参

  • 原因一:没人这么用。
  • 原因二:memcpy()snprintf() 这种库函数,平时使用的时候都是直接传数组名的。
  • 原因三:可读性未必好。出参都加了&,算是满足了强迫症,但是函数定义里面就要写成 (*parr)[i] = i 或者 parr[0][i] = i ,这显得复杂。
  • 原因四:性能不佳。使用的时候,(*parr)[i] = i 或者 parr[0][i] = i 要取值两次。
  • 原因五:数组指针有用,但压根不是这么用的。直接传二维数组名的时候,形参就得定义数组指针,这才是数组指针正常的用法。

所以给数组名取地址传参是多此一举。

上述例子的正确写法应为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 这是正常写法
#include <stdio.h>

void func(int, int *, int *);

int main()
{
    int i = 0;
    int arr[10] = {0};
    int count = 5;
    int sum = 0;

    func(count, arr, &sum);
    for (i = 0; i < count; i++)
    {
        printf("%d\n", arr[i]);
    }

    printf("sum = %d\n", sum);
    
    return 0;
}

void func(int count, int *p, int *p_sum)
{
    int i = 0;
    int sum = 0;

    for (i = 0; i < count; i++)
    {
        p[i] = i;
        sum += i;
    }

    *p_sum = sum;
}
本文由作者按照 CC BY 4.0 进行授权
热门标签
文章内容

记一次指针强转导致脏数据写入问题

C语言标准发展历史

热门标签