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

来源:互联网 发布:魔兽世界源码 编辑:程序博客网 时间:2024/06/08 18:35

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) 传递结构体指针作为形参,会改变结构体的内容,我们将这种形参传递叫输出型参数,下一节详细介绍。

总结

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