一、值傳遞
例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轉成一個字符串