值傳遞與地址傳遞(C語言)

一、值傳遞

例1:

// swap.c
#include <stdio.h>

int main()
{
    int a = 20;
    int b = 30;
    int c = 0;
    printf("a is %d, b is %d\n", a, b);

    c = a;
    a = b;
    b = c;

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

思考:
兩個變量交換值,經常會用到,可以把它提煉成一個函數,供復用。

例2:

// swap.c
#include <stdio.h>

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

int main()
{
    int a = 20;
    int b = 30;
    printf("a is %d, b is %d\n", a, b);
    swap(a, b);     // 將a和b的副本傳遞過去
    // 函數調用完后,swap的空間就出棧了,a和b做的那么多操作也沒用了
    printf("now, a is %d, b is %d\n", a, b);
}
值傳遞后,a和b的值并沒有交換成功
值傳遞

值傳遞:傳遞的只是一份副本。(只是給你看一下)

特點:調用者可以保護自己空間值不被修改?!颈Wo】

缺點:因為每次調用都會傳遞一份副本,因此內存消耗很大,工程中不建議使用。

main函數調用swap函數,只是告訴swap函數a和b的值,但是不希望swap函數對main函數內的a和b的值進行修改。

二、地址傳遞

例3:

// swap.c
#include <stdio.h>

void swap(int *a, int *b)  // 通過*讀門牌號里面的內容
{
    int c = 0;
    c = *a;
    *a = *b;
    *b = c;
}

int main()
{
    int a = 20;
    int b = 30;
    printf("a is %d, b is %d\n", a, b);
    swap(&a, &b); // 將a和b的門牌號傳遞過去
    printf("now, a is %d, b is %d\n", a, b);
}
地址傳遞后,a和b的值交換成功了
地址傳遞

地址傳遞:傳遞的門牌號

特點:調用者讓被調者修改自己的空間值?!靖摹?/strong>

用處:

  • 調用者讓被調者修改自己的空間值
  • 連續空間的傳遞

優點:不用拷貝副本,可以節約空間。

// scanf函數:
int a = 0;
scanf("%d", a);    // 如果是這樣寫,屬于值傳遞。當鍵盤輸入值后,a的值仍然不會改變
scanf("%d", &a);    // 如果是這樣寫,屬于地址傳遞。當鍵盤輸入值后,a的值才會改變

三、連續空間只讀性

當看到函數聲明時,能否大概猜出其功能呢?

因為在看代碼時,函數非常多,不可能把所有代碼一行一行都讀完。因此要能看到函數聲明,大體猜測到其功能。

void fun(char a);    // 值傳遞。fun函數只想拿到一個1字節/8bit的副本,只是拿來看一下,不會去影響調用者。

void fun(char *b);    // 地址傳遞。該空間可能會被修改。

void fun(const char *b);    // 地址傳遞。只讀空間,只是看看。
// const告訴實現fun函數的程序員:fun函數里面絕對不能修改門牌號b的內容。
// const也告訴調用fun函數的程序員:放心大膽地傳遞常量區的東西吧!不會出現段錯誤的!

例4:

// 004.c
#include <stdio.h>
void fun(char *p)
{
    p[1] = '2';    // 只看fun函數,傳遞過來一個指針,是可以對其內容進行修改的。
    // 但因為修改的是常量區的東西,因此會出現段錯誤
}

int main()
{
    fun("hello");    // fun傳遞的是常量區的東西
    return 0;
}

若函數聲明是void fun(char *p);時,則看到它的程序員,在實現時,很可能會在里面寫p[1] = '2';。而且,調用該函數時,另一個程序員很可能會把hello傳遞出去。因此,很容易出現錯誤。

出現段錯誤

修改:

#include <stdio.h>
void fun(char *p)
{
    p[1] = '2';
}

int main()
{
    char buf[] = "hello";
    fun(buf);
    return 0;
}
沒有錯誤

1、strcpy

// man strcpy
char *strcpy(char *dest, const char *src);
// 原地址的內容不改變,目的地址的內容會改變!

2、sprintf

// man sprintf
#include <stdio.h>

int printf(const char *format, ...);    // 打印到屏幕上
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);    // 打印到內存中。打印前不能變,打印后,內存改變了!
int snprintf(char *str, size_t size, const char *format, ...);

例5:

char buf[100];
sprintf(buf, "hello world");    // 打印到內存的buf數組中

例6:在格式化處理的時候,sprintf用得非常普遍

int a = 12;
printf("%d", a);
char buf[10];
sprintf(buf, "%d", a);    // 把整數12轉成一個字符串
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容