【问题标题】:Why should I target the address and not the actual variable name when swapping values of two variables using functions? [duplicate]使用函数交换两个变量的值时,为什么我应该以地址而不是实际变量名为目标? [复制]
【发布时间】:2021-04-29 19:01:20
【问题描述】:

我是 C 编程的新手,我不明白为什么在使用函数时交换两个变量的值不应该与不使用指针的正常方式相同。

#include <stdio.h>
void swap(int*, int*); //Swap function declaration

int main()
{
   int x, y;

   printf("Enter the value of x and y\n");
   scanf("%d%d",&x,&y);

   printf("Before Swapping\nx = %d\ny = %d\n", x, y);

   swap(&x, &y);

   printf("After Swapping\nx = %d\ny = %d\n", x, y);

   return 0;
}
//Swap function definition
void swap(int *a, int *b)
{
   int t;

   t  = *b;
   *b = *a;
   *a = t;
}

为什么不应该这样:

t = b;
b = a;
a = t;

【问题讨论】:

  • 因为这只是交换本地指针,而不是它们指向的内存中的数据。
  • @Barmar 那么你的意思是那些交换的变量只能在函数内访问,而不是在全局范围内?
  • 没错,但不是重点。交换指针不会交换它们指向的变量的内容。
  • 打个比方:假设你的左手有一个蓝色的盒子,右手有一个红色的盒子,你想交换它们的内容。交换他们的手不会那样做。手就像指针。
  • 因为有了指针,你总是要记住指针它指向的东西之间的区别。 b = a 复制指针。 (但这不是你想要的。)*b = *a 复制指向的值:这就是你想要的。

标签: c pass-by-reference swap pass-by-value function-declaration


【解决方案1】:

b = a 将 a 的值复制到 b。

*b = *a将a指向的内存中的值复制到b指向的内存中。

当 a 和 b 是int * 时,它们包含一个整数的内存地址,一个指针。在这种情况下,b = a 将简单地使 b 指向与 a 相同的内存。 *b 说“取消引用” b 并使用它指向的值。所以*b = *a 表示将 a 指向的值复制到 b 指向的内存中。

这都是必要的,因为您在一个与其余代码隔离的函数中工作。该函数想要更改其范围之外的两个变量的值,因此它必须通过操作它们的内存来实现。

int *a, int *b 就像有两个名为 a 和 b 的存储桶。 b = a 使存储桶 a 和 b 相同。 *b = *a 将存储桶 a 中的内容复制到存储桶 b。 swap 想要交换 x 和 y 的存储桶中的内容。


你是否像这样按值传递...

swap(x, y);

void swap(int a, int b)
{
   int t;

   t = b;
   b = a;
   a = t;
}

x 和 y 的值将被复制到 a 和 b。 a 和 b 的值将被交换,对 x 和 y 没有影响。

你是否传递了指针,但没有取消引用,就像这样......

swap(&x, &y);

void swap(int *a, int *b)
{
   int *t;

   t = b;
   b = a;
   a = t;
}

现在 x 和 y 的内存地址被复制到 a 和 b。 a 指向与 x 相同的内存,b 指向与 y 相同的内存。但是b = a 在 a 和 b 之间交换这些地址,对 x 和 y 没有影响。

swap(&x, &y);

void swap(int *a, int *b)
{
   int t;

   t = *b;
   *b = *a;
   *a = t;
}

x 和 y 的内存地址仍然复制到 a 和 b。 a 有 x 的地址,b 有 y 的地址。 *b = *a 改变它们指向的内存的值,与y和x相同。它实际上是y = x。 x 和 y 看到了变化。

【讨论】:

  • 在“传递指针但不取消引用”(倒数第二个示例)中,int t; --> int *t; [或允许 t = b; 编译的内容]。
  • @CraigEstey 谢谢。
【解决方案2】:

考虑以下程序

#include <stdio.h>

void f( int x )
{
    x = 20;
    
    printf( "Within f( int ) x = %d\n", x );
}

int main(void) 
{
    int x = 10;
    
    printf( "Before call of f( int ) x = %d\n", x );
    
    f( x );
    
    printf( "After  call of f( int ) x = %d\n", x );
    
    return 0;
}

程序输出是

Before call of f( int ) x = 10
Within f( int ) x = 20
After  call of f( int ) x = 10

如您所见,在 main 中声明的变量 x 并没有通过调用函数来更改。

变量x按值传递给函数f。即函数参数x(另一个具有函数块作用域的变量)被main中声明的变量x的值初始化。

所以函数改变了它的局部变量(参数)x。 main 中声明的变量x 保持不变。

你可以想象函数定义及其调用方式如下

f( x );

//...

void f( /*int parameter_x*/ )
{
    int parameter_x = x;

    patameter_x = 20;
    
    printf( "Within f( int ) patameter_x = %d\n", patameter_x );
}

要更改在 main 中声明的变量 x,您必须通过引用传递它。 在 C 中,通过引用传递意味着通过指向对象的指针间接传递对象。

这是一个演示程序。

#include <stdio.h>

void f( int *px )
{
    *px = 20;
    
    printf( "Within f( int ) x = %d\n", *px );
}

int main(void) 
{
    int x = 10;
    
    printf( "Before call of f( int ) x = %d\n", x );
    
    f( &x );
    
    printf( "After  call of f( int ) x = %d\n", x );
    
    return 0;
}

程序输出是

Before call of f( int ) x = 10
Within f( int ) x = 20
After  call of f( int ) x = 20

取消引用指针px

    *px = 20;

该函数可以直接访问指向的对象,即指向 main 中声明的对象 x

因此,如果您想在 swap 之类的函数中交换 main 中声明的两个变量的值,您需要通过引用该函数来传递相应的对象。否则,该函数将处理 main 中声明的变量值的副本。

【讨论】:

    【解决方案3】:

    从欺骗中抽象出来这个交换意义不大。使用宏:

    #define SWAP(a,b,type) do{type c__c__c; c__c__c = (a); (a) = (b); (b) = c__c__c;}while(0)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-20
      • 2019-08-30
      • 2018-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-15
      • 2017-06-18
      相关资源
      最近更新 更多