Menu
CoddyTech

指针与值

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 9 课,共 61 课。

将结构体传递给函数时,C 提供了两种选择:按值传递(复制整个结构体),或按指针传递(只复制地址)。这个选择对性能影响很大。

按值传递会在栈上创建结构体的完整副本。对于只包含几个整数的小型结构体,这样做没问题。但想象一下,一个结构体有几百字节:每次调用函数都会复制所有这些数据:

typedef struct {
    char name[100];
    int scores[50];
    double average;
} Student;

// 按值传递:每次调用都会复制约 308 字节
void print_by_value(Student s) {
    printf("%s: %.2f\n", s.name, s.average);
}

// 按指针传递:只复制 8 字节(地址)
void print_by_pointer(const Student *s) {
    printf("%s: %.2f\n", s->name, s->average);
}

语法也不同。使用值参数时,你要用点运算符(s.name)。使用指针时,你要用箭头运算符(s->name)。

指针版本效率更高,因为它只传递一个内存地址,通常为 8 字节,与结构体大小无关。

这就是 C 程序员几乎总是通过指针传递结构体的原因。如果函数不应修改数据,就使用 const;如果应该修改,就使用普通指针。这样既高效,又能清楚地表达意图。

challenge icon

挑战

简单

让我们创建一个 Product 模块,演示按值传递结构体和按指针传递结构体的区别。你将创建两个显示函数:一个接收整个结构体的副本,另一个只接收指向它的指针。

你将创建三个文件:

  • product.h:声明一个包含三个成员的 Product 结构体:char name[50]、double price 和 int quantity。另外还要声明两个函数:
    • display_by_value:按值接收一个 Product,并打印它的信息
    • display_by_pointer:接收一个 const Product *,并打印相同的信息
    使用符号 PRODUCT_H 设置包含保护。
  • product.c:实现这两个函数。注意语法上的区别:按值传递的版本使用点运算符(p.name),而指针版本使用箭头运算符(p->name)。两个函数的打印格式应相同。
  • main.c:创建一个 Product,然后调用这两个显示函数,证明它们虽然使用了不同的参数形式,但输出完全相同。

你将收到三个输入:产品名称(字符串)、价格(double)和数量(整数)。

在主文件中,使用这些值初始化一个 Product,然后先调用 display_by_value,再调用 display_by_pointer。

两个函数都应按以下格式打印:

Product: {name}, Price: {price}, Qty: {quantity}

价格使用 %.2f,以显示两位小数。

例如,输入 Laptop、999.99 和 5 时,输出如下:

Product: Laptop, Price: 999.99, Qty: 5
Product: Laptop, Price: 999.99, Qty: 5

亲手试试

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

int main() {
    char name[50];
    double price;
    int quantity;
    
    // 读取输入
    scanf("%s", name);
    scanf("%lf", &price);
    scanf("%d", &quantity);
    
    // TODO: 创建一个 Product 变量,并用输入的值初始化它
    // 提示:使用 strcpy 将 name 复制到结构体的 name 字段中
    
    // TODO: 将 Product 作为参数调用 display_by_value
    
    // TODO: 将指向 Product 的指针作为参数调用 display_by_pointer
    
    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C 在线编译器