簡體   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