1

当一个函数需要一个指针作为参数(而不是指针引用的变量)时,这仅仅是因为将传递给函数的值的大小吗?

我可以理解有人想要传递指向数组或结构的指针,而不是传递整个数组或结构,但他们做出这个决定的其他原因是什么?例如,一个函数需要一个指向int(4 字节)而不是int(4 字节)本身的指针。

4

5 回答 5

6

如果您希望您的函数更改参数的值(例如int),那么您必须传入一个指向它的指针。否则,您的函数所做的任何更改都将在副本上进行。

一般而言,C 和 C++ 中所谓的“输出参数”通常是指向受函数影响的任何变量的指针。

至于数组,C 语言实际上不允许将一大块内存传递给函数,因此我们别无选择,只能传递一个指针。

(编辑:如评论中所述,此答案仅适用于指针。在 C++ 中,也可以使用引用)

于 2013-07-17T23:58:38.180 回答
1

一句话的答案是:如果您正在处理非基本类型的输入参数,则传递(指针/引用)到常量,如果您正在处理基本类型的输入参数,则传递值,传递-否则按(指针/引用)。正如评论中所指出的(感谢 TonyD),最后一条“规则”是对使用 pass-by-(pointer/reference)-to-const 的优化;这可能是不必要的,但值得一提。请注意,通过引用传递给 const 不会影响使用临时参数(无论是文字还是函数调用的结果)调用函数的能力。

为了恰当地回答这个问题,必须做出一些区分。首先,C 和 C++ 是两种不同的野兽:C 中的唯一选项是按值传递 (pbv)、按指针传递 (pbp) 和按指针传递到常量 (pbptc)。在 C++ 中,您还可以选择传递引用 (pbr) 和传递引用到常量 (pbrtc)。其次,输入参数和(输入/)输出参数之间存在区别;当参数属于第二类时,除了 pbp 或 pbr(如果适用,即如果使用 c++),您别无选择。至于输入参数,需要考虑的因素更加微妙。Alexandrescu 在他的《现代 C++》一书中解决了这个问题

您有时需要回答以下问题:给定任意类型 T,将 T 类型的对象作为函数参数传递和接受的最有效方法是什么?一般来说,最有效的方法是通过引用传递复杂类型,通过值传递标量类型。(标量类型由前面描述的算术类型以及枚举、指针和指向成员的指针组成。)对于复杂类型,您可以避免额外临时(构造函数加析构函数调用)的开销,而对于标量类型,您可以避免引用产生的间接开销。

(当然,对于输入参数,他指的是pbrtc)。同样,您应该选择 pbptc 用于 C 中的“详细”类型。

最后,如果您使用的是 C++,您可以通过使用“类型特征”(标准特征或自定义编写的特征,请参阅现代 C++ 了解更多信息)自动执行此选择。类型特征允许你自动知道一个类型是否是一个基本类型,它是否已经是一个引用(在这种情况下你不能通过引用传递它,因为 C++ 不允许引用引用)和所有有意义的东西。例如,通过type_traits,您可以编写类似这样的内容

#include <type_traits>

typedef int& my_type;

void f(const std::add_lvalue_reference<my_type> a){
}

typedef int my_type2;

void g(const std::add_lvalue_reference<my_type2> a){
}

int main() {

}

当然,这是一个虚构的示例,但您可以看到该方法的实用性,如果您使用模板,则效果会更好。请注意,这type_traits是 c++11 标准库的一部分,如果您不使用 c++11,则必须自己制作(或使用某些库作为loki

于 2013-07-18T04:53:52.817 回答
1

在 C++ 中,您将按值传递内置类型,除非您想在方法或函数中修改它们并将修改应用于原始变量。

您可以通过引用或指针传递。如果要修改输入,有些人更喜欢通过指针传递,因为它更明确,因为您必须取消引用指针。

IE:

void foo(int& a, int* b)
{
    a = 1; // This modifies the external variable, but you can't see that just looking at this line
    *b = 1; //explicitly modifying external variable
}

int z = 0;
int y = 0;
foo(y, &z); //z is explicitly being allowed to be modified, that y can be too isn't apparent until you look at the function declaration.

其他人认为这种传递指针很丑陋并且不喜欢它。

传递大型类型的最佳实践是通过 const 引用,这表示您不会修改实例。

于 2013-07-18T04:16:10.010 回答
0

当你想改变int变量时,你也可以使用引用。

对于数组来说,数组名只是一个指向第一个元素的指针,当它作为参数传递给函数时,它会变成普通的指针,所以必须将数组中元素的个数作为参数传递。

于 2013-07-18T03:41:31.450 回答
0

使用变量与指向变量的指针作为函数的参数

一般建议:

  1. 如果函数不更改参数,则按值传递。

      #include <iostream>
      int test(int arg){
          std::cout << arg;
      }
    
      int main(int argc, char** argv){
          int a = 6;
          test(a);
          return 0;
      }
    
  2. 如果函数需要更改传递的参数,请通过引用传递。

      #include <iostream>
      int test(int &arg){
          arg = 6;
      }
    
      int main(int argc, char** argv){
          int a = 0;
          test(a);
          std::cout << arg;
          return 0;
      }
    
  3. 如果一个函数不需要更改参数,但参数是 BIG,则通过 const 引用传递。
  4. 如果函数需要更改传递的参数并且此参数是可选的,则通过指针传递。

      #include <iostream>
      int test(int *arg){
          if (arg)
              *arg = 6;
      }
    
      int main(int argc, char** argv){
          int a = 0, b = 1;
          test(0);
          test(&b);
          std::cout << a << std::endl << b << std::endl;
          return 0;
      }
    
  5. 如果函数不需要更改传递的参数,参数很大并且参数是可选的,则通过指针传递给 const。

推理:引用和指针可用于修改函数“外部”的值,但引用不能设置为 0/NULL。

指向 int 的指针(4 个字节)

根据平台,指向 int 的指针可能不是 4 个字节大。例如,在 64 位系统上,它将是 8 字节大。

如果该函数分配内存块,则返回指向 int 的指针是有意义的。如果此函数用作“选择器”并且您需要写入返回值,则返回对 int 的指针/引用是有意义的。

#include <iostream>
int& getMaxVal(int &a, int &b){
     return (a > b)? a: b;
}

int main(int argc, char** argv){
      int i = 3, j = 4;
      std::cout << i << " " << j << std::endl;
      getMaxVal(i, j) /= 2;
      std::cout << i << " " << j << std::endl;
      return 0;
}
于 2013-07-18T07:08:41.843 回答