在C++中交换指针的地址

5

如何在带有函数签名的函数中交换指针地址?

假设:

int weight, height;
void swap(int* a, int* b);

那么,在退出此函数后,实际参数(weightheight)的地址会发生更改。这有可能吗?


我不明白这个问题。你想交换哪些地址? - sharptooth
4
可以交换体重和身高的值,但不能交换它们的地址。 - Andreas Brinck
6个回答

25
如果你想交换指针所指向的地址,而不仅仅是交换存储在该地址中的值,那么你需要通过引用(或指向指针的指针)传递指针。
#include <cassert>
void swap(int*& a, int*& b)
{
    int* c = a;
    a = b;
    b = c;
}

int main()
{
    int a, b;
    int* pa = &a;
    int* pb = &b;

    swap(pa, pb);

    assert(pa == &b);  //pa now stores the address of b
    assert(pb == &a);  //pb now stores the address of a
}

或者你可以使用STL的swap函数,并将指针传递给它。

#include <algorithm>

std::swap(pa, pb);
你的问题似乎不是很清楚。

非常感谢您提供的宝贵答案。如果我的问题没有表达清楚,我很抱歉。这个答案(*&)是我正在寻找的解决方案。再次感谢。 - There is nothing we can do
1
这是不良实践和误导性代码。1)过于复杂。2)混合使用指针和引用(不良实践)。如果有程序员向我提交这样的代码,我会拒绝它。 - RED SOFT ADAIR
1
我不同意(但我对C++还很新,所以我可能错了)。1)为什么这是不好的实践?我们不是一直在使用通过引用传递对象吗?指针也是一个对象,因此有权像其他对象一样被处理。2)这有什么复杂的,我真的说不清楚。3)我没有看到这是混合指针和引用 - 我只是看到这是通过引用传递对象,这是我的常规做法。4)不好的实践?在B.S的书《C++程序设计语言》中有指向指针的引用的例子,并且它们没有被标记为不好的实践,所以我认为如果B.S这样做,我也可以这样做。 - There is nothing we can do
一般来说:1)最好使用指针或引用。混合使用它们通常会导致混淆和错误。2)该代码仍然可以被std::swap替换。3)如果您使用swap(&width, &height)这样的参数调用swap(int*& a, int*& b),则该调用可能会导致编译器或运行时错误。整个事情就是奇怪而已。 - RED SOFT ADAIR
1
  1. 这真的取决于情况。将 new 的解引用结果存储到引用中自然会令人困惑。但这是另一回事。通过引用传递东西是一件很自然的事情(例如,明确表明不欢迎 NULL 指针)。
  2. 是的,这个想法是要展示如何自己做。猜猜 std::swap 使用了什么 - 正确,引用。
  3. 编译器错误,因为这没有意义。如果您尝试通过指向指针的指针进行操作,也会导致编译器错误。swap(&(&a), &(&b));
- UncleBens
为什么使用简单的swap(int * weight,int * height)不能交换两个变量height和weight?你能解释一下吗?这真的很令人困惑。 - Umer iqbal

9

在C++中,您将编写以下代码:

 void swap(int *a, int *b)
 {
    std::swap(*a, *b);
 }

或者只需使用:
 std::swap(a, b);

1
但这并没有解决问题,至少我是这样理解的。变量的地址应该改变,而不是值? - unwind
你的解决方案是可行的,但不像MSalters的例子那样直观。 - user195488
这样一个简单的问题竟然能引起如此多的冲突,真是令人惊讶。请不要开枪! - RED SOFT ADAIR

7

新答案(由于问题已经重新定义)

是,变量的地址在编译时确定,因此无法交换。但是,指向变量的指针可以被交换。

旧答案:这是当问题仍然涉及通过函数交换2个变量的值时的答案:

函数调用:

 int width=10, height=20;
 swap(&width, &height)

实现:

 void swap(int *a, int *b)
 {
      int temp;
      temp=*a;
      *a = *b;
      *b = temp;
 }

或者...不使用临时变量:;^)

 void swap(int *a, int *b)
 {
      *a ^= *b;
      *b ^= *a;
      *a ^= *b;
 }

请注意,最后一种方法在交换 (&a, &a) 的情况下会出现问题。这一点由用户9876在评论中指出。

1
那是C语言,不是C++,如果我可以评论一下的话,最后一种方法不太直观。 - RED SOFT ADAIR
redsoft:他已经给这个问题打了C和C++的标签 - Toad
14
那个异或(XOR)技巧不过是一帮自以为聪明却并没有成功的人在耍花招。由于没有指定它将被编译成什么(任何一个还算不错的编译器都会将其放入寄存器中,使速度差异变得无关紧要,并且使变量的节省变得无关紧要),所以你不能说它的速度如何。对程序员犯下的最大罪行就是牛仔式地编写难以维护的软件。不管怎样,谢谢你听我发牢骚 :-) 我不会投票支持或反对任何观点,因为这既不重要,而且已经被重复多次了。 - paxdiablo
4
我不理解为什么有人会在现代处理器上使用XOR技巧。这会导致速度变慢。如果处理器执行的恰好是您编写的内容,那么XOR技巧需要9次内存访问,而简单方法只需要4次。在现代CPU上,内存访问比其他任何操作都要慢得多。如果编译器优化XOR技巧以在寄存器中存储中间值,从而只有4次内存访问,那么您仍然需要进行3次不必要的XOR运算。此外,一个非常聪明的编译器可以将简单的解决方案内联,并且可能根本不生成代码。 - user9876
1
另外:使用简单的解决方案swap(&a, &a)是一个无操作,但如果您使用XOR技巧,则会将a设置为0。 - user9876
显示剩余5条评论

6

看起来您可能对一些术语感到困惑。

通常,一个对象都有一个地址。这是对象在内存中的位置。一些临时对象没有地址,因为它们不需要被存储。例如,在表达式 (2+2)*3 中,临时的“4”对象就是这样一个例外。

指针是一种存储另一个对象地址的对象。因此,对于每种类型,都有相应的指针。例如,intint*std::stringstd::string*,等等。

现在,您写了关于“指针地址”的内容。它们确实存在。毕竟,我写过指针是一个对象,因此它有自己的地址。而且您可以将该地址存储在另一个指针中。例如,您可以将 int* 的地址存储在 int* * 中。但是您真的想要那样做吗?还是您的意思是“指针引用的地址”?

现在,您以身高和体重作为示例。在 C++ 中交换它们的标准方式只是 std::swap(width, height)。注意前缀 std::,它是 C++ 标准库函数的前缀。 std::swap 几乎可以交换任何东西。整数、浮点数、妻子。(开玩笑)。

您似乎还有另一个交换函数。它接受两个指向整数的指针,这意味着它想要两个整数的地址。在这种情况下,这些很容易提供。 width 是一个整数,&width 是它的地址。这可以存储在指针参数 int* a 中。同样,您可以将地址 &height 存储在参数 int*b 中。将它们组合起来,您就得到了调用 swap(&width, &height);

这是如何工作的呢? swap(int*a, int*b) 函数有两个指针,它们持有内存中两个整数的地址。因此,它可以做的是 [1] 置备第一个整数的一份副本,[2] 将第二个整数复制到第一个整数所在的内存中,以及 [3] 将第一个整数复制回第二个整数所在的内存中。代码如下:

 void swap(int *a, int *b)
 {
      int temp = *a; // 1
      *a = *b;       // 2
      *b = temp;     // 3
 }

3

如果您想更改指针的地址,则必须将这些指针的指针作为参数传递:

void swap(int **a, int **b); //as prototype

这些例子只是改变指针的值。


1
一个好的解决方案将是:

void swapPointers(int** first, int** second) {
    int* temp = *first;
    *first = *second;
    *second = temp;
    return; 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接