C 语言里的“按值”与“按址”:一次 struct 传参的对比实验

在这里插入图片描述

🚀个人主页:BabyZZの秘密日记
📖收入专栏:C语言


很多初学者第一次写结构体时都会遇到一个问题:
“为什么我写的 print 函数有时候用 struct book b,有时候又用 struct book *b
它们到底差在哪?”
今天,我们就通过一个最小可复现实验——打印两本书的信息——把这件事彻底讲透。


1. 先上代码:两种打印风格

#include <stdio.h>

struct book
{
    char  name[20];
    char  id[20];
    char  author[20];
    float price;
};

/* 方式一:按值传递 */
void print1(struct book b1)
{
    printf("%s %s %s %.1f\n",
           b1.name, b1.id, b1.author, b1.price);
}

/* 方式二:按地址传递(指针) */
void print2(struct book *b2)
{
    printf("%s %s %s %.1f\n",
           b2->name, b2->id, b2->author, b2->price);
}

int main(void)
{
    struct book b1 = { .name = "兄弟",   .id = "A101",
                       .author = "余华", .price = 29.8f };
    struct book b2 = { .name = "白夜行", .id = "B102",
                       .author = "东野圭吾", .price = 25.8f };

    print1(b1);    /* 传值:把整本书复制一份 */
    print2(&b2);   /* 传址:只送过去门牌号 */
    return 0;
}

2. 现象:输出完全一致

兄弟 A101 余华 29.8
白夜行 B102 东野圭吾 25.8

既然结果一样,那两种方式还有区别吗?
当然有,区别藏在“内存”和“性能”里。


3. 原理:一次复制 vs. 一个指针

调用方式背后发生了什么时间开销空间开销能否修改原对象
print1(b1)在栈上新建一个 完整的 struct book 副本复制 20+20+20+4 字节较大❌(修改的是副本)
print2(&b2)只传递 8 字节左右的指针几乎可忽略极小✅(可通过 b2->price = 30 修改原对象)

注:结构体越大,按值传递的复制成本越高;而指针始终是固定大小(32 位 4 字节、64 位 8 字节)。


4. 何时该用谁?

  1. 只读场景

    • 结构体很小(像本例 64 字节左右):两种方式都行,按值更直观。
    • 结构体很大(几百字节以上):优先 const struct book *,避免无意义拷贝。
  2. 需要修改原对象

    • 必须传指针。
    • 若不想被误改,可加 const 修饰:
      void print2(const struct book *b)
  3. C++ 用户请注意

    • C++ 中推荐用引用 const book&,语法更简洁,效果与 const book* 类似。

5. 动手实验:验证复制行为

print1 里偷偷改一下:

void print1(struct book b1)
{
    b1.price = 0;          // 改副本
    printf("print1 内 price = %.1f\n", b1.price);
}

再在 main 里打印原对象:

print1(b1);
printf("main 里 price = %.1f\n", b1.price);

结果:

print1 内 price = 0.0
main 里 price = 29.8

证实:print1 拿到的是副本,对原书毫无影响。


6. 小结

  • 按值传递:简单、安全,但有复制成本。
  • 按址传递:高效、可写,但要自己保证指针合法,必要时加 const 防误改。

记住一句话:

“小数据传值,大数据传址;只读加 const,想改就指针。”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值