个人理解—值传递与地址传递

        前面说到了sizeof(),在其中就涉及到了形参传递,现在就来说一下这里面涉及到的一些问题。

int main()
{
    int a=4;
    printf("&a=%p\n",&a);  输出0xbf80d4cc
    void func(a);
}

void func(int b)
{
    printf("&b=%p\n",&b);  输出0xbf80d4b0
}

        我们发现,实参与形参地址不同,说明是在两个内存空间中。b是由a赋值得到的,所以也就有了函数执行完成后销毁,开辟内存空间后销毁什么的,如上方法为传值调用,实参做右值,形参做左值。

        再来看下面一个实例:

int main()
{
    int a[5]={1,2,3,4,5};
    printf("&a=%p\n",&a);  输出0x012ffad4
    void func2(a);
}

void func2(int b[])
{
    printf("&b=%p\n",&b);  输出0x012ffad4
}

        我们可以看到,传入函数的实参其实是一个地址,传入后依旧使用的是同一片内存空间,像这样数组传递的参数实际传递的是首元素地址,也就是完成了地址传递。

        为什么要对值传递和地址传递进行研究,其原因一方面是为了简化操作复杂性另一方面是为了节省内存空间。

struct A
{
    char a;
    int b;
}

int main()
{
    struct A a={a=4,b=555};
    sizeof(a);  输出8,内存对齐
    printf("&a=%p",&a); 0xbfbad048
    func2(a);
}

func2(struct A a)
{
    sizeof(a);  输出8
    printf("&a=%p",&a); 0xbfbad030
}

        我们可以看到,当我们将结构体做值传递时,是一整个结构体去新的内存空间进行了新内存的开辟,也就是说此时我们内存中有两个数据相同的结构体,都开辟了8字节的内存空间,但结构体更大呢,这样就会影响代码运行效率,以及占用内存空间。所以我们可以使用值传递的方式进行结构体传递。

struct A
{
    char a;
    int b;
}

int main()
{
    struct A a={a=4,b=555};
    sizeof(a);  输出8,内存对齐
    printf("&a=%p",&a); 0xbfda5508 
    func3(&a);
}

func2(struct A *a1)
{
    sizeof(a1);  输出4 指针大小
    sizeof(*a1);  输出8 结构体大小
    printf("&a1=%p",&a1); 0xbfda54f0 存放指针的地址
    printf("a1=%p",a1); 0xbfda5508 a1指向的地址,结构体起始地址
    printf("a1.b=%d",a1->b); 输出555
}

        看上面这个例子,就是使用地址传递,在同一块内存中完成了相应操作,唯一多出的就是一块存放a1指针的内存空间,在大结构体操作过程中由于不用copy老结构体到新内存空间,使用将会提高访问效率节省内存使用空间。

        看了上面的示例,想必应该明白了二者的区别,也就明白了经典案例—swap两值交换的正确写法。

int main
{
    int a=3,b=5;
    swp1(a,b);
    printf("a=%d,b=%d"a,b); 输出3,5 交换失效
    swp2(&a,&b)
    printf("a=%d,b=%d"a,b); 输出5,3 交换成功
}

void swp1(int a,int b) 值传递开辟新空间,在新空间中自己换着玩
{
    int tmp=0;
    tmp=a;
    a=b;
    b=tmp;
}

void swp2(int* a,int* b) 地址传递,在老空间内完成值的交互
{
    int tmp=0;
    tmp=*a;
    *a=*b;
    *b=tmp;
}

        函数名本质上只是一个符号,表示了整个代码段的起始地址,也就是一个指针,所以在函数中使用函数名都是当地址进行调用。

       形参为函数输入部分,返回值为输出部分,一个函数即使没有形参也能加工全局变量。

        我们都知道,return只能返回一个值,所以一般用于返回操作执行判断,那么多个变量返回我们应该如何处理,答案是用函数的参数做返回值(指针)。

func(int a,int *p,const int *p2)

        看到函数接口有三个参数,其中int a为输入形参数(原因是去新空间了),int *p为输出形参数,const int *p2是输入形参数(原因是const修饰后为常量不可改变,使用const修饰后一方面是避免值被修改,另一方面是提高代码可读性,将输入后在函数中不变的参数设为const)。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值