【C 語言入門】158.該傳變數值還是址

在介紹指標和函式之後,我們會遇到一個有趣的問題,那就是我們該傳數值本身還是應該傳儲存數值的位址。

#include <stdio.h>
void swap(int, int);

int main()
{
    int a = 3, b = 5;
    swap(a,b);
    
    printf("a: %d\n", a);
    printf("b: %d\n", b);

    return 0;
}

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

呼叫 swap 的時候,a 的值 3 和 b 的值 5 會被複製一份到 swap 裡,我們傳的是資料的值本身,swap 得到的是 main 裡面 a 和 b 的複製品。

在以上的程式中,即使呼叫 swap ,main 裡面的值也不會改變。

然後我們就踢到了可以通過傳位址,把 main 裡面的位址複製一份到 swap。

swap 裡的 a 是 main 裡面的 a 的複製品,swap 裡的 b 是 main 裡面的 b 的複製品,這些我們都在這篇文章有詳細介紹。

#include <stdio.h>
void swap(int *, int *);

int main()
{
    int a = 3, b = 5;
    swap(&a,&b);
    
    printf("a: %d\n", a);
    printf("b: %d\n", b);

    return 0;
}

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

傳了位址的複製品,我們就可以通過間接運算子(*) 取得位址上面的變數。

swap 函式裡的 *a 和 *b 指的就是 main 裡面的 a 變數和 b 變數。

透過傳位址的方式,我們就可以把數值做交換。

所以我們有兩個方法,一個是直接複製變數值(第一個程式碼),一個是複製變數的位址(第二個程式碼)。

複製變數的位可以改變變數的值,直接複製變數值則無法改變變數的值。

#include <stdio.h>
int max2(int *, int *);

int main()
{
    int a = 3, b = 5;
    printf("Max: %d\n", max2(&a, &b));
    printf("%d", a);
    return 0;
}

int max2(int *a, int *b){
    if (*a > *b){
        return *a;
    } else {
        return *b;
    }
}

看到這裡你可能會想,那以後我們都傳變數的位址不就好了嗎?

如果不小心把 *a 或 *b 的值改掉了,那 main 裡面的 a 和 b 的值也會被修改,但我們並不打算更改 main 裡面 a 和 b 的值。

#include <stdio.h>
int max2(int, int);

int main()
{
    int a = 3, b = 5;
    printf("Max: %d\n", max2(3, b));
    printf("%d", a);
    return 0;
}

int max2(int a, int b){
    if (a > b){
        return a;
    } else {
        return b;
    }
}
#include <stdio.h>
int max2(int *, int *);

int main()
{
    int a = 3, b = 5;
    printf("Max: %d\n", max2(&3, &b));
    printf("%d", a);
    return 0;
}

int max2(int *a, int *b){
    if (*a > *b){
        return *a;
    } else {
        return *b;
    }
}

我們來看程式細節。

printf("Max: %d\n", max2(&3, &b));

3 不是變數,是常數,沒辦法取位址,會導致程式編譯失敗。

也就是說傳位址沒辦法放常數,只能放變數,這樣會造成不方便,只能用以下的方式寫程式。

#include <stdio.h>
int max2(int *, int *);

int main()
{
    int a = 3, b = 5;
    printf("Max: %d\n", max2(&a, &b));
    printf("%d", a);
    return 0;
}

int max2(int *a, int *b){
    if (*a > *b){
        return *a;
    } else {
        return *b;
    }
}

如果在意的是值本身,複製值是比較安全的,不用擔心函式會被修改到。

當我們是用複製位址的時候有兩個含意,

  1. 被呼叫的函式裡,有可能會改到位址的函數本身,所以它是有風險的。
  2. 引數不會是常數,只會是變數

我們可以記住以下的基本原則:

基本原則:

可以傳值就傳值,如果可以傳 int ,就不要傳 int 的位址。因為複製一份比較安全,不怕被偷改,也可以確保函式間乾淨的關係。

如果在意的是值本身,複製值是比較安全的,不用擔心函式會被更改。

用起來比較方便,可以傳一般的常數,eg 我們剛提到的 3,而不需要將 3 存在變數。

例外規則:

  • 如果我們希望呼叫後的函式會被改,這時候則需要傳 a 和 b 的位置。
  • 無法直接複製值的時候(例如陣列和字串)
  • 複製的成本太高的時候(例如較複雜的結構)

Leave a Comment

Your email address will not be published. Required fields are marked *