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

时间:2013-07-17 23:52:35

标签: c++ c pointers parameters

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

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

5 个答案:

答案 0 :(得分:6)

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

通常,C和C ++中所谓的“输出参数”通常是指向函数影响的变量的指针。

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

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

答案 1 :(得分: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引用,它表示您不会修改实例。

答案 2 :(得分:1)

一行中的答案是:如果要处理非基本类型的输入参数,则传递给(指针/引用)-to-const,如果要处理基本类型的输入参数,则按值传递,否则传递(指针/参考)。正如评论中指出的那样(感谢TonyD),这个最后的“规则”意味着优化使用pass-by-(指针/引用)-to-const;它可能是不必要的,但它值得现在。请注意,通过引用传递给const并不会使用临时(无论是文字还是函数调用的结果)参数来调用函数。

必须做出一些区分才能恰当地回答这个问题。首先,C和C ++是两种不同的动物:C中唯一的选项是值传递(pbv),传递指针(pbp)和传递指针传递给const(pbptc)。在C ++中,您还可以选择pass-by-reference(pbr)和pass-by-reference-to-const(pbrtc)。其次,输入参数和(输入/)输出参数之间存在区别;当一个参数属于第二个类时,你没有选项,只有pbp或pbr(如果可以应用,即使用c ++)。至于输入参数,要考虑的因素更加微妙。 Alexandrescu在他的“Modern C ++”一书中解决了这个问题

  

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

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

最后,如果您使用的是C ++,则可以使用“类型特征”(standard ones或自定义编写的特性)自动执行此选择,有关详细信息,请参阅Modern 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 std库的一部分,如果你不使用c ++ 11,你必须自己制作(或使用某些库作为loki

答案 3 :(得分:0)

如果您想更改int变量,也可以使用参考。

对于数组,数组名称只是指向第一个元素的指针,当它用作传递给函数的参数时,它将更改为普通指针,因此必须将数组中的元素数传递给一个参数。

答案 4 :(得分: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。

  6. 推理:引用和指针可用于修改函数“外部”的值,但引用不能设置为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;
    }