在 C 中传递指向函数的指针的混淆

confusion in passing a pointer to function in C

我试图理解 C 中的指针并编写了这段代码

#include <stdio.h>

int swap(int *fa,int *fb){
    int temp = *fa;
    *fa = *fb;
    *fb = temp;
}

int main(){
    int a=5,b=7;

    int *pa = &a;
    int *pb = &b;

    swap(pa,pb);

    printf("%d\n",*pa);
    printf("%d\n",*pb);

    printf("%d\n",a);
    printf("%d",b);
}

现在输出(如预期)是

7
5
7
5

我对正在发生的事情有了一些了解,但我有一个困惑

  1. 在我调用交换函数后,就发生了这种情况
fa = pa // fa points to what pa points to which means a
fb = pb // fb points to what pb points to which means b
  1. 我们交换 fa 和 fb 的值,进而交换 a 和 b 的值,因为 pa 和 pb 指向 a 和 b,它们现在指向这些新值。

这是怎么回事

或者是fa和fb先影响pa和pb,再影响a和b

对于初学者,请注意您的函数 swap 具有 return 类型 int return 什么都没有。

int swap(int *fa,int *fb){

return 类型 int 没有意义。

函数可以这样声明

void swap(int *fa,int *fb);

函数 swap 不交换其参数的值。

int swap(int *fa,int *fb){
    int temp = *fa;
    *fa = *fb;
    *fb = temp;
}

它交换参数对象指向的指针,因为在函数中使用了取消引用指针的表达式,例如

*fa*fb.

这是一个演示程序,显示指针 fafb 的值没有改变。

#include <stdio.h>

void swap(int *fa,int *fb){
    printf( "fa = %p, fb = %p\n", ( void * )fa, ( void * )fb );
    int temp = *fa;
    *fa = *fb;
    *fb = temp;
    printf( "fa = %p, fb = %p\n", ( void * )fa, ( void * )fb );
}

int main(void) 
{
    int a=5,b=7;

    int *pa = &a;
    int *pb = &b;

    swap(pa,pb);
    
    return 0;
}

程序输出可能看起来像

fa = 0x7ffff85444f0, fb = 0x7ffff85444f4
fa = 0x7ffff85444f0, fb = 0x7ffff85444f4

正如所见,指针在函数的开头和结尾具有相同的值。交换的是指向对象的值。

并且指针fafb不影响main中声明的指针papb。因为指针 fafb 作为函数的局部变量获取存储在指针 papb.

中的值的副本
  1. right after I call the swap function, this happens
fa = pa // fa points to what pa points to which means a
fb = pb // fb points to what pb points to which means b

如果你的意思是在输入 swap 之后,那么是的。那是对的。参数作为副本传递,这意味着在该函数内部 fafb 从调用者那里获得 papb 的副本。

  1. we swap values of fa and fb, which in turn swap values of a and b, since pa and pb points to a and b they also point to these new values.

没有,fafb根本没动过。它们被取消引用。这意味着,它们指向的地址受到影响。您可以使用 printf 打印那些指针变量的内容。他们不会改变。 相反,ab 的内容已更改。

顺便说一句:您的 printf 陈述没有多大意义。您应该在函数调用之前和之后打印以查看效果。

当您将指针传递给您的函数时,您传递的是一个包含地址的变量。当您取消引用 fa(或 fb)时,您将获得该地址的实际值。所以当你修改它时,你修改了两个指针的值,因为它们指向同一个地址。

要更好地理解指针,您可以使用实际的假地址。假设变量 'a' 存储在 RAM 中的地址 0x9000,变量 'b' 存储在地址 0x10000.

#include <stdio.h>

int swap(int *fa,int *fb){  //fa and fb are variables of type pointer which contain 0x9000 and 0x10000 respectively
    int temp = *fa;  //temp contains the content of address 0x9000 (a)
    *fa = *fb; //address 0x9000 contains content of address 0x10000 (b)
    *fb = temp; //address 0x10000 contains content of temp (a)
}

int main(){
    int a=5,b=7;

    int* pa = &a; //pa is a variable of type pointer which contains 0x9000
    int* pb = &b; //pb is a variable of type pointer which contains 0x10000

    swap(pa,pb);
}

不要忘记 int* 是一个指向 int 的指针类型的变量。它的意思是该变量包含一个int类型变量的地址。实际上它只是指向内存。你可以这样写

int* a = 0x9000;

你会有一个指向地址 0x9000 的 int 类型的指针。那将是有效的语法,但您的 OS 会抱怨您无权访问该地址。如果你写

long* a = 0x9000;

唯一的区别是取消引用时获得的字节数。当你取消引用一个指针时,你会得到该类型包含的字节数。对于 int* 类型,当您取消引用时,您将获得从地址 0x9000 开始的 4 个字节(32 位)。使用 long* 类型,您将获得从地址 0x9000 开始的 8 个字节(64 位)。

int* 或 long* 类型变量的大小是相同的,因为这仅取决于您的架构 CPU。因此,对于这两者,您将获得一个具有相同大小的指针类型变量。唯一的区别是取消引用时获得的字节数。

we swap values of fa and fb, which in turn swap values of a and b, since pa and pb points to a and b they now point to these new values.

否 - 您交换 fafb 指向 的值,即 ab分别。 fafb(以及 papb)的值永远不会改变。

我修改了你的代码如下:

#include <stdio.h>
#include <stdlib.h>

void swap(int *fa,int *fb){
    printf( "Entering swap: fa = %p, fb = %p, *fa = %d, *fb = %d\n", (void *) fa, (void *) fb, *fa, *fb );
    int temp = *fa;
    *fa = *fb;
    *fb = temp;
    printf( "Leaving swap: fa = %p, fb = %p, *fa = %d, *fb = %d\n", (void *) fa, (void *) fb, *fa, *fb );
}

int main(){
    int a=5,b=7;

    int *pa = &a;
    int *pb = &b;

    printf( "Before swap: a = %d, b = %d, pa = %p, &a = %p, pb = %p, &b = %p, *pa = %d, *pb = %d\n", 
      a, b, (void *) pa, (void *) &a, (void *) pb, (void *) &b, *pa, *pb );

    swap(pa,pb);

    printf( "After swap: a = %d, b = %d, pa = %p, &a = %p, pb = %p, &b = %p, *pa = %d, *pb = %d\n", 
      a, b, (void *) pa, (void *) &a, (void *) pb, (void *) &b, *pa, *pb );

    return EXIT_SUCCESS;
}

当运行时,它给出输出1:

Before swap: a = 5, b = 7, pa = 0x7ffee8f43a60, &a = 0x7ffee8f43a60, pb = 0x7ffee8f43a5c, &b = 0x7ffee8f43a5c, *pa = 5, *pb = 7
Entering swap: fa = 0x7ffee8f43a60, fb = 0x7ffee8f43a5c, *fa = 5, *fb = 7
Leaving swap: fa = 0x7ffee8f43a60, fb = 0x7ffee8f43a5c, *fa = 7, *fb = 5
After swap: a = 7, b = 5, pa = 0x7ffee8f43a60, &a = 0x7ffee8f43a60, pb = 0x7ffee8f43a5c, &b = 0x7ffee8f43a5c, *pa = 7, *pb = 5

所以,我们可以看到以下都是正确的:

 fa ==  pa == &a
*fa == *pa ==  a == 5 // before swap, 7 after swap

 fb ==  pb == &b
*fb == *pb ==  b == 7 // before swap, 5 after swap

  1. 地址值可能会从 运行 变为 运行 - 重要的是 fapa 以及 &a 都是 相同 值。