当一个函数需要一个指针作为参数(而不是指针引用的变量)时,这仅仅是因为传递给函数的值的大小?
我可以理解有人想要将指针传递给数组或结构,而不是传递整个数组或结构,但这是他们做出这个决定的其他原因吗?例如,一个需要指向int
(4个字节)而不是int
(4个字节)本身的指针的函数。
答案 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)
使用变量与变量指针作为函数的参数
一般建议:
如果函数未更改参数,则按值传递。
#include <iostream>
int test(int arg){
std::cout << arg;
}
int main(int argc, char** argv){
int a = 6;
test(a);
return 0;
}
如果某个函数需要更改传递的参数,请按引用传递。
#include <iostream>
int test(int &arg){
arg = 6;
}
int main(int argc, char** argv){
int a = 0;
test(a);
std::cout << arg;
return 0;
}
如果函数需要更改传递的参数,并且此参数是可选的,则通过指针传递。
#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;
}
如果函数不需要更改传递参数,则参数为大且参数是可选的,通过指针传递给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;
}