C语言小结--指针和变量传参

1、普通变量作为函数形参

这种情况使用最多,也比较好理解,贴段代码如下:

#include <stdio.h>

void func(int x)
{
    printf("in fun : x = %d , &x = %p . \n",x,&x);
}


int main(void)
{
    int a = 10;
    printf("in main : a = %d, &a = %p. \n", a , &a);
    func(a);
    return 0;
}

运行结果:

root@ubuntu:/mnt/hgfs/share/code/c_advance/pointer# ./a.out 
in main : a = 10, &a = 0xbf84750c. 
in fun : x = 10 , &x = 0xbf8474f0 . 

结果分析:
(1) a和x是两个独立的变量,在内存中分别占用两个地址,这点很重要。
(2) 当func函数被调用的时候,传参会将a传递给x,所以x=a;相当于完成了一次赋值操作,这其中赋值操作是会浪费CPU的运行时间和内存的。
(3) 这就是大家所说的“传值调用”。

2、数组作为函数的形参

这种情况在上一章节中讨论过,为了内容的连贯性,我们再举个例子来讨论一下:
void func(int x[5], int len)
{
    printf("int fun : sizeof(x) = %d; len = %d \n", sizeof(x), len);
    printf("in fun  : x[0] = %d , x = %p . \n",x[0], x);
    printf("in fun  : x[0] = %d , &x[0] = %p . \n",x[0], &x[0]);
}


int main(void)
{
    int a[10] = {0};
    printf("in main : a[0] = %d, a = %p. \n", a[0] , a);
    printf("in main : a[0] = %d, &a[0] = %p. \n", a[0] , &a[0]);
    func(a,sizeof(a));
    return 0;
}

运行结果:

root@ubuntu:/mnt/hgfs/share/code/c_advance/pointer# ./a.out 
in main : a[0] = 0, a = 0xbff837a8. 
in main : a[0] = 0, &a[0] = 0xbff837a8. 
int fun : sizeof(x) = 4; len = 40 
in fun  : x[0] = 0 , x = 0xbff837a8 . 
in fun  : x[0] = 0 , &x[0] = 0xbff837a8 . 

结果分析:
(1) 函数的形参为数组名时,实际传递的不是整个数组,而是数组的首元素的首地址(也是整个数组的首地址)。 这种方式我们也称之为 “传址调用”。我们只是将数组的首地址传递给了函数,也就是说在函数内部操作的数组的内存空间是同一个。那么在函数中就可以操作数组中的值,所以在很多大型程序设计时,有一些数组的内容会被莫名奇妙的改掉,这个时候就需要注意,是否一些函数的形参是数组名,同时在调用此函数时将这个数组作为实参传递给了该函数。
(2)如果需要将整个数组都传递过去,那么在传参时加一个变量int,传入sizeof(数组),这样就将数组长度和数组的首地址都传进去了。

申明时:
void func(int x[5], int len);
调用时:
func(a,sizeof(a)/sizeof(int ));

(3) 数组作为形参调用时,数组的大小可以是空:x[] , 也可以是任意数字。因为我们只是将一个地址给他传递进去,数组大小对此毫无意义。

3、指针作为函数形参

和数组作为函数形参是一模一样的。本质上我们只是传递个地址给它。

4、结构体作为函数形参

结构体作为函数形参,和普通变量作为函数形参是一样的。写一段代码验证一下:

#include <stdio.h>
#include <string.h>


typedef struct Temp
{
    char name[20];
    int len;
}temp_type;


void func(temp_type x)
{

    printf("in func     :sizeof(x) = %d; \n", sizeof(x));
    printf("in func     :&x = %p; \n", &x);
    printf("in func     :&(x.name)= %p; \n ", &(x.name));

    strcpy(x.name,"abcdefg");
    printf("in func     :a,name = %s,\n", x.name);

}

void func1(temp_type *y)
{

    printf("in func1    :sizeof(y) = %d; \n", sizeof(y));
    printf("in func1    :y = %p; \n", y);
    printf("in func1    :&y = %p; \n", &y);
    strcpy(y->name , "nihao zhongguo");
    printf("in func1    :%s,\n", y->name);

}


int main (void )
{

    temp_type a;
    a.len = 10;
    strcpy(a.name,"hello world");
    printf("in main     :   sizeof(a) = %d; \n", sizeof(a));
    printf("in main     :   &a = %p; \n", &a);
    printf("in main     :   &(a.name)= %p; \n ", &(a.name));
    printf("in main     :   a.name = %s,\n", a.name);
    func(a);
    printf("in main     :a.name = %s,\n", a.name);
    func1(&a);
    printf("in main     :a.name = %s,\n", a.name);

    return 0;
}

运行结果如下:

root@ubuntu:/mnt/hgfs/share/code/c_advance/pointer# ./a.out 
in main     :   sizeof(a) = 24; 
in main     :   &a = 0xbfbe6154; 
in main     :   &(a.name)= 0xbfbe6154; 
 in main        :   a.name = hello world,
in func     :sizeof(x) = 24; 
in func     :&x = 0xbfbe6130; 
in func     :&(x.name)= 0xbfbe6130; 
 in func        :a,name = abcdefg,
in main     :a.name = hello world,
in func1    :sizeof(y) = 4; 
in func1    :y = 0xbfbe6154; 
in func1    :&y = 0xbfbe6130; 
in func1    :nihao zhongguo,
in main     :a.name = nihao zhongguo,

结论:
(1) 结构体作为形参传递时,和普通变量的传递是一模一样的。
(2) 之前的数组不可以整个传递,我们可以将数组封装在结构体中,然后用结构体传递,这样整个数组就传过去了。
(3) 通常情况下结构体作为形参直接传递的做法是不可取的,因为一般情况下,结构体都比较大,占用的内存比较多。在函数调用时,直接传递结构体会造成严重的内存浪费,所以一般做法是传递结构体指针进去。如本例子中的fun1。
(4) 传递结构体指针作为形参,会改变结构体的内容,我们将这种形参传递叫输出型参数,下一节详细介绍。

总结

函数形参的传递其实也不复杂,我们只需要弄清楚传递给函数的是值还是址。 但是本质上来讲,我们都是操作内存,是内存的复制还是用指针的方式直接访问内存呢?就需要根据具体的情况具体对待。这其中还会牵扯出输入型参数和输出型参数,具体在以后篇幅中介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值