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

     2023-02-22     120

关键词:

【中文标题】使用变量与指向变量的指针作为函数的参数【英文标题】:Using variables versus pointers to variables as parameters for a function 【发布时间】:2013-07-17 23:52:35 【问题描述】:

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

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

【问题讨论】:

尝试编写一个交换两个值的函数,例如int a = 1, b = 2; "swap(a, b);",然后是a == 2 && b == 1 哪种语言,C 或 C++?例如,在 C++ 中,您可以通过引用传递参数,而在 C 中则不能。 在 64 位机器上传递一个指向任何东西的指针实际上是 8 个字节 【参考方案1】:

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

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

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

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

【讨论】:

Small nit:structs 可以是相当大的内存块,structs 可以是函数参数,因此 C 确实允许将一大块内存传递给函数。它只是不允许传递数组。 啊,是的,谢谢。由于这样做几乎总是一个坏主意,所以我没有考虑过。 如果函数要改变参数的值,可以通过引用传递参数吗? @ThomasMatthews:如果函数需要改变调用函数中的变量,那么变量必须通过引用传递给函数。如果函数所做的更改不应更改调用函数中的变量,则应将变量(的副本)按值传递给函数。 @JonathanLeffler:这个答案说“你必须传入一个指针”,但在 C++ 中也有通过引用传递的选项。我希望奈杰尔能回答我的评论。【参考方案2】:

在 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 引用,这表示您不会修改实例。

【讨论】:

【参考方案3】:

答案是:pass-by-(pointer/reference)-to-const 如果你处理的是非基本类型的输入参数,pass-by-value 如果你处理的是基本类型的输入参数, 否则传递(指针/引用)。正如 cmets 中所指出的(感谢 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++,您可以通过使用“类型特征”(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 标准库的一部分,如果您不使用 c++11,则必须自己制作(或使用某些库作为 loki)

【讨论】:

“如果您正在处理基本类型的输入参数,则按值传递”在几年前很流行,最终导致人们对类型特征产生了兴趣以在模板中实现它,但在练习当函数参数类型通过模板参数可变时会很痛苦,即使对于基本类型,使用const T&amp;非常很少出现性能问题(尤其是启用了优化)。因此,作为选择性使用,整个类型特征值得了解,但不作为标准做法:太繁琐、容易出错且令人困惑。 @TonyD 你可能是对的,额外的间接(承认它确实到达编译的代码)很可能不会成为瓶颈。我正在编辑答案以反映这一点。【参考方案4】:

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

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

【讨论】:

【参考方案5】:

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

一般建议:

    如果函数不改变参数,则按值传递。

      #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;
      
    
    如果函数不需要更改参数,但参数很大,则通过 const 引用传递。

    如果函数需要更改传递的参数并且该参数是可选的,则通过指针传递。

      #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;

【讨论】:

c语言结构体(结构体作为函数参数|结构体指针作为函数参数)(代码片段)

...数参数三、完整代码示例一、结构体作为函数参数结构体变量作为函数形参,在函数中,只能访问该函数形参,无法修改结构体内存的值;结构体变量通过形参形式传入,会在该printf_student方法的栈内存中,重新为该结构体变量分配内存,... 查看详情

c言语指针变量作为函数参数

...、字符等详细的数据,还可所以指向它们的指针。用指针变量作函数参数可以将函数内部的地址传递到函数外部,使得在函数外部可以操作函数内部的数据,而且这些数据不会跟着函数的完毕而被烧毁。像数组、字符串、静态分... 查看详情

使用指针做形参来解决函数的副本机制

/*在函数里面改变一个外部变量,就需要变量的地址  如果是数据,需要指向数据的指针存储数据的地址如果是指针,就需要指向指针的指针存储指针的地址//二级指针一般用于改变一个字符串指针的指向,指向不同的字... 查看详情

函数指针(函数指针作为函数形参/函数类型作为函数返回类型)

函数指针是指向函数的指针变量。因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个... 查看详情

数组名作函数参数时,实参与形参变量之间的数据传递是?

...于该变量p无法像真正的数组名一样得到数组长度,所以使用数组名作为参数传值给函数的同时,还要将数组的长度一并传给函数。以上,希望对你有所帮助参考技术A数组名做参数时,相当于指针传递,传的是地址本回答被提问... 查看详情

c语言数据类型本质(void关键字作用|数据类型封装|作为参数或返回值代表无|void*指针赋值与被赋值|void类型变量不存在)(代码片段)

...数或返回值代表无三、void*指针赋值与被赋值四、void类型变量不存在一、数据类型封装实现函数的底层函数开发者,不想将底层的数据结构暴露给函数调用者;如:定义一个函数,intinitEnv(void**handle)该函数被暴露给调用者,但是函数的v... 查看详情

函数指针及其定义和用法,c语言函数指针详解(代码片段)

...示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。那么这个指针变量怎么定义呢?虽然同样是指向一个地址,但指向函数的指针变量同我们之前讲的指向变... 查看详情

指针本质分析(代码片段)

...一段存储空间的别名,那么是不是必须通过这个别名才能使用这段存储空间?可以通过指针改变另一个变量的值指针的本质为变量(只要是变量,就有地址),不过说这种变量很特殊,它存储的是变量的地址值在指针声明时,*... 查看详情

11.9c++对象指针(代码片段)

...空间的起始地址就是对象的指针,可以定义一个指针变量,用来存放对象的指针。定义指向类对象的指针变量的一般形式为 类名*对象指针名;可以通过对象指针访问对象和对象的成员C++指向对象成员的指针在C... 查看详情

go-指针与函数

...址,这个地址存的才是值4、获取指针类型所指向的值,使用:*,比如:varp*int,使用*p获取p指向的变量的值varaint=5 varp*int=&a  0xefefefe指向变量a的值是55、指 查看详情

函数指针

函数指针是指向函数的指针变量。通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。函数指针可以像一般函数一样,用于调用函数、传递参数。函数指针变量的声明: typedefint(*func)(inta,i... 查看详情

指针问题

1.普通变量的指针指向  2.指针对数组元素的访问 3.指针作为形参 4.指向结构体的指针变量作为函数参数 5.函数指针 6.指针函数(返回的类型为指针,具体返回什么类型的指针还要看返回值,下面列举的为字... 查看详情

c语言_18函数指针与函数指针数组

...向print函数//函数在表达式中将转换为该函数的指针(2).使用函数指针#include<stdio.h>intmain()int 查看详情

函数指针(代码片段)

函数指针函数指针是指向函数的指针变量。通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。函数指针可以像一般函数一样,用于调用函数、传递参数。函数指针变量的声明:typedefint(*fun_pt... 查看详情

指针实验(代码片段)

...实验练习8.3.11问题的简单描述:(1)定义一个整型指针变量p,使它指向一个整型变量a,定义一个浮点型指针q,使它指向 查看详情

结构体指针与结构体变量用作函数参数时有啥区别,在用法上

参考技术A结构体指针与结构体变量用作函数参数区别:(1)结构体指针作为函数参数时,调用时传递的是指向一个结构体变量的指针(即结构体变量的地址);结构体变量作为函数参数时,调用时传递的结构体变量本身。(2)... 查看详情

《c语言程序设计》指针(代码片段)

...针1.2.1多维数组元素的地址1.2.2指向多维数组元素的指针变量1、指向数组元素的指针变量2、指向由m个元素组成的一维数组的指针变量3、指向数组的指针作为函数参数二、指针引用字符串2.1引用字符串的两种方式2.1.1字符数组2.1.2... 查看详情

c_函数指针详解(代码片段)

...示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。那么这个指针变量怎么定义呢?虽然同样是指向一个地址,但指向函数的指针变量同我们... 查看详情