一、普通變量作為函數(shù)形參
- 普通變量作為函數(shù)形參時,形參和實參名字可以相同也可以不同。實際上都是用實參來替代相對應(yīng)的形參。
- 在子函數(shù)內(nèi)部,形參的值等于實參。原因是函數(shù)調(diào)用時把實參的值復(fù)制給了形參。
- 這就是很多書上寫的傳值調(diào)用。(相當(dāng)于實參做右值形參做左值)。
#include <stdio.h>
#include <string.h>
//&a和&b不同,說明a和b不是同一個變量 (內(nèi)存中a和b是獨立的兩個內(nèi)存空間)
//實際上a和b是有關(guān)聯(lián)的,a是b賦值得到的
void func1(int b)
{
//在
printf("b=%d.\n",b);
printf("in func1 &b=%p.\n",&b);
}
int main(void)
{
int a=4;
printf("&a=%p.\n",&a);
func1(a); //把普通變量a傳入函數(shù)func1內(nèi)
ruturn 0;
}
二、數(shù)組作為函數(shù)形參
- 數(shù)組名作為形參傳遞時,實際傳遞的不是整個數(shù)組,而是數(shù)組的首元素的首地址(也就是整個數(shù)組的首地址。因為傳參時是傳值,所以這兩個沒區(qū)別。)所以在子函數(shù)內(nèi)部傳進(jìn)來的數(shù)組名就等于是一個指向數(shù)組首元素地址的指針。所以sizeof得到的是4。
- 在子函數(shù)內(nèi)傳參得到的數(shù)組首元素首地址,和外面得到的數(shù)組首元素首地址的值是相同的。很多人把這個特性叫做“傳址調(diào)用”(調(diào)用子函數(shù)時傳了地址,也就是指針。此時可以通過傳進(jìn)去的地址可以訪問實參)。
- 數(shù)組名作為形參時,[ ]里面是可有可無的。因為數(shù)組名做形參傳遞的實際只是個指針,根本沒有數(shù)組長度信息。
#include <stdio.h>
void func2(int a[])
{
printf("sizeof(a)=%d.\n",sizeof(a)); //4
printf("in func2 a=%p.\n",a); //
}
int main(void)
{
int a[5];
func2(a);
printf("a=%p.\n",a);
}
三、指針作為函數(shù)形參
- 和數(shù)組作為函數(shù)形參是一樣的。
- 就好像指針方式訪問數(shù)組元素和數(shù)組方式訪問數(shù)組元素是一樣的。
#include <stdio.h>
void func3(int *a)
{
printf("sizeof(a)=%d.\n",sizeof(a));
printf("in func2 a=%p.\n",a);
}
int main(void)
{
int a[5];
func3(a);
printf("a=%p.\n",a);
}
四、結(jié)構(gòu)體變量作為函數(shù)形參
- 結(jié)構(gòu)體變量作為函數(shù)形參時,實際上和普通變量傳參時表現(xiàn)是一模一樣的。結(jié)構(gòu)體變量實際也是普通變量。
- 因為結(jié)構(gòu)體一般都很大,如果直接用結(jié)構(gòu)體變量進(jìn)行傳參,那么函數(shù)調(diào)用效率就會很低(因為函數(shù)傳參的時候需要將實參賦值給形參,所以當(dāng)傳參變量越大調(diào)用效率就會越低)。解決的方法就是傳遞結(jié)構(gòu)體的指針進(jìn)去。
- 結(jié)構(gòu)體由于自身太大,所以傳參應(yīng)該由指針傳。(但是程序員可以自己決定傳遞整個結(jié)構(gòu)體變量)。為什么c語言數(shù)組默認(rèn)只能傳指針呢?c語言給數(shù)組做了決定。
#include <stdio.h>
struct A
{
char a;
int b;
};
void func4(struct A a1)
{
printf("sizeof(a1)=%d.\n",sizeof(a1));
printf("&a1=%d.\n",&a1);
printf("a1.b=%d.\n",a1.b);
}
int main(void)
{
struct A a=
{
.a=A,
.b=555,
}; //給結(jié)構(gòu)體賦初值
printf("sizeof(a)=%d.\n",sizeof(a));
printf("&a=%d.\n",&a);
printf("a.b=%d.\n",a.b);
func4(a);
}
#include <stdio.h>
struct A
{
char a;
int b;
};
void func5(struct A *a1)
{
printf("sizeof(a1)=%d.\n",sizeof(a1)); //4
printf("&a1=%d.\n",a1);
printf("&a1=%d.\n",&a1);
printf("a1.b=%d.\n",a1->b); //訪問結(jié)構(gòu)體是變量是.是指針時用箭頭
}
int main(void)
{
struct A a=
{
.a=A,
.b=555,
}; //給結(jié)構(gòu)體賦初值
printf("&a=%d.\n",&a);
printf("a.b=%d.\n",a.b);
func5(&a);
}
五、傳值調(diào)用與傳址調(diào)用
- 傳值調(diào)用指的是:x,y作為實參,自己真身并沒有進(jìn)入swap1函數(shù)內(nèi)部,而只是拷貝了一份自己的副本,但是是不同的變量,進(jìn)入了子函數(shù)是swap1中交換的實際只是副本而不是真身。內(nèi)部確實交換了,外部x,y卻沒有影響。
- 在swap2中真的被改變了。(但是x,y真身也沒有被改變。而是swap2函數(shù)內(nèi)部跑出來把外面的x和y真身改變了。)實際上實參永遠(yuǎn)無法進(jìn)入子函數(shù)內(nèi)部,但是在swap2實參的地址傳遞給子函數(shù)。于是子函數(shù)內(nèi)可以通過指針解引用的方法從函數(shù)內(nèi)部訪問到外部x和y的真身,從而改變x,y。
- 結(jié)論:c語言函數(shù)調(diào)用一直是傳值的,只是傳的值可以是變量名,也可以是指針。
#include <stdio.h>
void swap1(int a, int b)
{
int tmp;
tmp=a;
a=b;
b=tmp;
printf("a=%d,b=%d.\n",a,b);
}
int main(void)
{
int x=3,y=5;
swap1(x,y);
printf("x=%d,y=%d.\n",x,y); //沒有交換
}
#include <stdio.h>
void swap2(int *a, int *b)
{
int tmp;
tmp=*a;
a=*b;
*b=tmp;
printf("*a=%d,*b=%d.\n",*a,*b);
}
int main(void)
{
int x=3,y=5;
swap1(&x,&y);
printf("x=%d,y=%d.\n",x,y); //交換成功
}