使用struct与使用指向struct的指针之间的区别

3
我正在以以下内容作为示例,以了解直接传递对象和传递指向该对象的指针之间的差异:
#include "stdio.h"

// Car object
typedef struct Car {
    char*           name;
    unsigned int    price;
} Car;

void print_car(Car car) {
    printf("<Car: %s, Price: $%d>", car.name, car.price);
};

void print_car2(Car *car) {
    printf("<Car: %s, Price: $%d>", car->name, car->price);
};

int main(int argc, char* argv[]) {

    Car chevy = {chevy.name = "Chevy", chevy.price = 45000};
    print_car(chevy);

    Car mazda = {chevy.name = "Mazda", chevy.price = 30000};
    print_car2(&mazda);

    return 1;

}

除了第一种方法对我来说更易读和理解之外,它们两者之间有什么区别?什么情况下传递指针将是唯一的选择,为什么在上述情况下两种方法都可以工作?


1
第一个例子复制整个结构体,因此效率较低。此外,如果调用者变量的结构字段需要被函数修改,则只有第二个选项可行。 - kaylum
在C++中,你可以通过引用传递参数,在底层实际上是通过指针来传递的,但语法更加简洁。 - Blastfurnace
@Blastfurnace 好的,但是有一个答案说C语言中有按引用传递 -- 这是错误的吗? - David542
在 C 中,传递引用意味着显式地使用指针,并使用 & 语法获取对象的地址并使用 * 解除指针。C++ 可以在调用站点不使用 &* 语法的情况下完成此操作,从而减少了语法混乱。 - Blastfurnace
“有一个答案说C语言中有传递引用的方法,那是不正确的吗?”-- 是的,那是错误的。 - Chris Dodd
显示剩余6条评论
3个回答

5

使用第二种方法有两个原因:

  1. 如果你想要避免复制整个结构。如果结构体很大,这会影响性能。
  2. 如果你想修改正在传递的结构体。

3

一般而言(不仅仅是对结构体),将变量传递给函数会创建该变量的副本,因此如果要修改该变量,则必须返回已更改的副本的值,但有时您可能想要修改该变量并返回其他内容,在这种情况下,您只能通过传递指针作为参数来实现。

第一个示例,使用变量传递:

int useless_func(int nb) /*nb is actually a copy of the variable passed as argument */
{
    nb++; /* the copy was incremented, not the real variable */
    return nb; /* the new value is returned */
}
int main()
{
    int nb = 1;

    useless_func(nb); /* here nb is still = 1 cause it wasn't altered by the function */
    nb = useless_func(nb); /* here nb is = 2 cause it took the return value of the func */
}

现在举一个关于指针的第二个愚蠢例子:

char *useless_func(int *nb) /* nb is now a pointer to the variable */
{
    *nb++; /* the derefencement of the pointer (so the variable value) was incremented */
    return strdup("This is a useless return"); /* we return some other stupid stuff */
}
int main()
{
    int nb = 1;
    char *str = useless_func(&nb); /* now nb is = 2 and str is an allocated useless string woohoo */
}

我忘记在最后一行放&符号了^^我真笨 - Tsak

2

当调用函数时,函数中的参数可以按值传递或按引用传递。

void print_car(Car car)

在这里,您直接将一个对象传递给函数,这意味着它将被复制到函数的堆栈中,并在函数调用结束后被销毁。应避免使用此方法,因为复制是昂贵且不必要的。而且,如果您的对象很大,这个操作将需要很长时间。

void print_car2(Car *car) {

在这种情况下,你传递的是一个指向对象的指针,这被称为按引用传递,这意味着你正在使用原始对象,并且你所做的更改将直接影响它。这样做速度更快,因为你不需要移动对象,但你应该小心修改原始数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接