带/不带指针的函数原型使用区别

Posted

技术标签:

【中文标题】带/不带指针的函数原型使用区别【英文标题】:Difference in the usage of function prototype with / without pointers 【发布时间】:2020-08-24 23:35:54 【问题描述】:

我正在学习简单的 C++ 教程。

#include <iostream>
using namespace std;

int main()

  int a = 1, b = 2;

  cout << "Before swapping " << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  swap(a,b);

  cout << endl;
  cout << "After swapping " << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  return 0;


void swap(int &n1, int &n2)

  int temp;
  temp = n1;
  n1 = n2;
  n2 = temp;

上面的代码可以正常工作(g++ 和 icc),但是如果我在函数中使用指针,如果我没有在程序开头包含原型,代码就会失败。

#include <iostream>
using namespace std;

void swap(int*, int*);  // The code fails if I comment this line.

int main()

  int a = 1, b = 2;

  cout << "Before swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  swap(&a, &b);

  cout << endl;
  cout << "After swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  return 0;


void swap(int* n1, int* n2)

  int temp;

  temp = *n1;
  *n1 = *n2;
  *n2 = temp;


据我所知,C++编译过程是自上而下的,所以第二段代码似乎更合理,在遇到int main()之前提供函数的信息。我的问题是,为什么在int main() 之前没有函数知识的情况下,第一个代码也能正常工作?

【问题讨论】:

另见Why is “using namespace std;” considered bad practice? 如果您想要另一个惊喜,请从第一个示例中完全删除 swap() 函数。你会发现没有它,代码也能构建和运行。 @MilesBudnek 啊哈!我什至没有想到 std 是问题的原因。谢谢你:) 【参考方案1】:

第一个程序的问题是您实际上并没有调用自己的swap 函数。在文件的顶部,您有:

using namespace std;

这会将std::swap 带入范围,这就是您实际调用的函数。如果您将cout 语句放在您自己的swap 中,您会发现它实际上从未被调用过。或者,如果你在main 之前声明你的swap,你会得到一个模棱两可的电话。

请注意,此代码并非必需,因为iostream 不一定会将std::swap 带入作用域,在这种情况下,您将收到没有swap 来电。

在第二个程序中,对 swap(&amp;a, &amp;b) 的调用失败,因为没有接受 2 个临时指针的 std::swap 重载。如果您在调用main 之前声明了您的swap 函数,那么它会调用您自己的函数。

您的代码中真正的错误是using namespace std;。永远不要那样做,你会避免这种性质的问题。

【讨论】:

"将 std::swap 带入范围" ...但可能不是在每个编译器上。仍然建议当您希望使用 std::swap 时,您应该始终#include 适当的标头。您所拥有的可能还包括交换,但不能保证。就在今天,我看到 std::swap() 现在在 3 个标题中:(我期望的地方)、【参考方案2】:

第一个版本有效的原因是它根本不调用您的swap(...) 函数。命名空间 std 提供 - Edit: 取决于您(以及标准标题本身)包含的标题 - swap(...) 各种类型和整数的函数就是其中之一.如果要删除 using namespace std,则必须键入 std::swap(...) 才能达到相同的效果(std::coutstd::endl 也是如此)。

这就是为什么using namespace 在我看来对初学者来说是一把双刃剑的原因之一,但这是另一个话题。

【讨论】:

"命名空间std提供了swap(...)函数..."。不,std::namespace 不提供库......库为 std::namsepace 提供了贡献。 std::swap 保证在特定库中提供,但并非所有作为 std::namespace 贡献者的库都会提供 std::swap。例如,cppreference.com 报告说 std::swap() 可以直接从 3 个标头中获取:、。根据工具套件,它可能会间接包含在其他库中。 @2785528 你说得对,我编辑了我的答案以纳入你的提示。【参考方案3】:

您的代码很好;但你是对的,如果你对你指向的行发表评论,它会失败。 但实际上,正如其他人告诉你的那样,c ++中有一个 Swap 函数,所以你创建一个函数的原型然后再做也没关系,因为编译器会调用自己的 swap 函数。

但由于 swap 适用于除指针以外的任何数据类型,那么您就会明白问题的原因,因为在这种情况下,您必须创建自己的 swap 函数来接受指针作为参数。

只需将您的函数移到 main 上方即可使其正常工作,仅此而已:

#include <iostream>
using namespace std;

//void swap(int*, int*);  // The code fails if I comment this line.
void swap(int* n1, int* n2)

  int temp;

  temp = *n1;
  *n1 = *n2;
  *n2 = temp;


int main()

  int a = 1, b = 2;

  cout << "Before swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  swap(&a, &b);

  cout << endl;
  cout << "After swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  return 0;

【讨论】:

"因为编译器调用了它自己的交换函数。"不会。编译器将仅搜索列出的包含库(以及它们包含的库,即间接的)。 std::swap 仅在 a) 在您的代码中使用(引用),并且 b) 在包含的库中找到时才链接。如果在您的构建套件中,库 不(直接或间接)包含 std::swap,编译器将放弃,并报告未定义的函数。

以上是关于带/不带指针的函数原型使用区别的主要内容,如果未能解决你的问题,请参考以下文章

带/不带功能的指针

JavaScript 函数调用时带括号和不带括号的区别

JavaScript错题记录变量定义提升this指针指向运算符优先级原型继承全局变量污染对象属性及原型属性优先级

如何定义一个函数指针?

JavaScript ES6 箭头函数 匿名函数 普通函数

一文带你彻底理解 JavaScript 原型对象