将结构体传递给函数

9

我正在尝试不同的方法来给结构变量赋值。但是,当我尝试这个时候,我得到了一些垃圾值。以下是代码。

#include<iostream>
using namespace std ;

struct Distance{
    int feet ;
    int inches;
};

void get_val(Distance );               
void disp(Distance);

int main(){

    Distance l, m ;                   //Objects 
    get_val(l);
    get_val(m);
    disp(l);
    disp(m);
    return 0  ;
}

void get_val(Distance length){
    cout<<"\nEnter Length "
        <<"\nFeet  : ";
    cin>>length.feet;
    cout<<"\nInches : ";
    cin>>length.inches;
}
void disp(Distance length){
    cout<<"\nLength : \n"
        <<"Feet : "<<length.feet
        <<"\nInches : "<<length.inches ;
}

为什么我的输出结果是垃圾值?

哪个输出返回垃圾?lm没有初始化! - user3165438
在disp()函数内部 - Tasdik Rahman
1
通过引用传递您的结构实例:void get_val(Distance& ); - πάντα ῥεῖ
你为什么不检查 cin >> length.feet 是否成功? - Ed Heal
有人能解释一下原因吗?谢谢 :) - Tasdik Rahman
@prodicus 我已经这样做了。你现在只是用那个函数修改了该对象的副本。 - πάντα ῥεῖ
6个回答

9
到目前为止,评论告诉您该怎么做,但似乎没有解释为什么需要这样做。
在C++(以及C)中,当您将数据传递给函数时,它会复制该数据并将其存储在该函数的本地-它不是原始数据!更不用说它占用内存并增加了一点执行时间(尽管在进入较大结构之前这并不重要)。
因此,解决方案是传递数据的内存位置-引用它。引用是“复制”的,因为它只获取位置(可能是一个可以表示内存位置的size_t或其他内容),但使用该位置来“引用”实际数据。它消除了复制的一些开销,并允许您修改原始数据。
在C中,您将使用指针而不是引用,在C ++中,通常最好使用引用(因为它意味着您传递的内容已经初始化且不会导致段错误)。您可能已经看到过语法并已经使用它,但我在此处复制它以增加明确性:
void get_val(Distance&);
void disp(const Distance&);
//...


void get_val(Distance& length){
    cout<<"\nEnter Length "
        <<"\nFeet  : ";
    cin>>length.feet;
    cout<<"\nInches : ";
    cin>>length.inches;
}

void disp(const Distance& length){
    cout<<"\nLength : \n"
        <<"Feet : "<<length.feet
        <<"\nInches : "<<length.inches ;
}

你可以像使用普通变量一样使用引用(提示一下,变量本身就是引用的一种类型!你以同样的方式调用函数- get_val(l);disp(l);)。一个const引用只是一个你无法更改的引用。通常你会在只读取值而不做其他操作的函数中使用它们。

3
你对引用的描述听起来像是它们可能被实现的方式。但请注意,从正式上讲,引用是对象的别名。这个对象甚至可以是一个右值,所以“取地址”类比不适用。编译器可能能够为引用和指针执行不同的优化集合。 - juanchopanza
1
我得出了一个结论,以指针的方式思考引用是适得其反的。关于引用,我曾经读过最聪明的一句话(不记得在哪里读到的)是“引用就是对象本身”。我认为如果你理解了这句话,那么你就理解了引用。 - Christian Hackl
@juanchopanza 您是正确的,它绝对不仅仅只是存储位置。我选择这个解释是因为当我学习时它对我来说是最有意义的,但它并非适用于所有情况。为了给您的解释提供一些背景并保持一致,我不会编辑我的回答。 - Cave Dweller

9
将它们通过引用传递。
void get_val(Distance&);


void get_val(Distance &length){}

当你在另一个函数中更改在主函数中创建的结构体的值时,你需要通过引用传递它们或使用指针。

编辑:

感谢 Benjamin Lindley。


3
get_val函数应该通过引用获取它们。disp函数应该通过值或常量引用获取它们。 - Benjamin Lindley

5

您需要通过引用传递一个Distanceget_val。 然后,get_val的签名需要是:

void get_val(Distance& length);

在你实现的过程中,存在两个问题:

  1. 你正在修改 get_val 中的本地副本 Distance
  2. 你没有初始化 l 或者 m

5

使用传递引用的方式(使用const),例如:

void get_val(Distance &length)
void disp(const Distance &length){

你为什么在disp()函数中使用了const?我不能只使用void disp(Distance length)吗? - Tasdik Rahman
1
是的 - 但在这种情况下使用 const 更好。 - Ed Heal
1
@prodicus 传递一个const引用是很好的风格。按值传递会创建一个额外的副本,而使用普通引用则不表示函数不会改变对象。 - πάντα ῥεῖ

3

你应该通过引用传递结构的对象。使用:

get_val (Distance& l);

在您的情况下,对象是按值传递的。因此,当您调用函数get_val(Distance l)时,该值被存储在l的成员变量中,但是当控制返回到主函数时,您存储的值没有反映出来,因为它们存储在对象的“副本”中而不是实际对象中。
使用引用的一些优点包括防止创建新对象的副本,减少调用复制构造函数和减少内存占用等开销。其次,您可以修改原始对象。

1
当您以这种方式传递时,您只是传递了Distance的副本。因此,在get_val内部的Distance对象仅是lm的副本,lm都不会得到更新。
相反,您要做的是传递lm的指针:
void get_val(Distance *length) {
    cout<<"\nEnter Length "
        <<"\nFeet  : ";
    cin>>length->feet;
    cout<<"\nInches : ";
    cin>>length->inches;
}

然后像这样调用它:
get_val(&l);
get_val(&m);

要么这样,要么编写函数以通过引用传递(请参见R Sahu的答案)。

都可以。需要意识到的一点是,C++ 严格按值传递。它总是会复制进入函数的内容。因此,必须传递一个指针或引用,这将被复制到函数中但指向同一对象。另外,上次我使用 C++ 时,引用不存在,因此不知道语法。 - slebetman
你在1983年之前就开始学习C++了? - Benjamin Lindley
好的。我刚刚读了更多关于按引用传递(我从未使用过,因为当我编写C++时它不可用),看起来如果您将参数声明为引用,C++确实支持按引用传递语义。 - slebetman
@BenjaminLindley :1999年。我的编译器没有这个功能,或者我只是不知道它。我在大学里学到的只有指针和引用是为Java准备的。 - slebetman
除了Java是按值传递之外。传递Java“引用”在语义上更接近于传递C++指针而不是C++引用。 - juanchopanza
通过指针传递“Distance”在这里是不好的编程风格。Java使用单词“引用”具有不同的含义。在大多数情况下,Java引用是一个没有指针算术的C++指针。除此之外,它共享所有问题,例如当您不需要该功能时“引用”可能为null(通常导致奇怪但正确命名的“NullPointerException”)。Java没有像C++引用那样的东西。 - Christian Hackl

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