繁体   English   中英

在 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。

  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

如果您的意思是在进入swap之后,那么是。 那是正确的。 参数作为副本传递,这意味着在函数fafb内部从调用者那里获取papb的副本。

  1. 我们交换 fa 和 fb 的值,然后交换 a 和 b 的值,因为 pa 和 pb 指向 a 和 b,它们也指向这些新值。

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

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

对于初学者,请注意您的返回类型为int函数swap返回任何内容。

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

返回类型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中的值的副本。

当您将指针传递给您的函数时,您传递了一个包含地址的变量。 当您取消引用 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;

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

long* a = 0x9000;

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

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

我们交换 fa 和 fb 的值,然后交换 a 和 b 的值,因为 pa 和 pb 指向 a 和 b,它们现在指向这些新值。

不 - 你交换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都是相同的值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM