找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 3133|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

C語(yǔ)言函數(shù)使用

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:655274 發(fā)表于 2019-12-3 17:12 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
一、函數(shù)基礎(chǔ)知識(shí)

1、函數(shù)的聲明

函數(shù)只能定義一次,但可以聲明多次。建議在頭文件中聲明而在源文件定義。函數(shù)的聲明和函數(shù)的定義非常類似,唯一的區(qū)別是函數(shù)的聲明無(wú)須函數(shù)體,用一個(gè)分號(hào)替代即可。

2、函數(shù)的定義

函數(shù)包括以下部分:返回類型、函數(shù)名字、由0個(gè)或多個(gè)形參組成的列表以及函數(shù)體。

returntype  functionname (type parameter1,type parameter2…) {……}

函數(shù)的形參列表:函數(shù)的形參列表可以為空,但是不能省略。void f1()、voidf2(void)

3、形參的基礎(chǔ)知識(shí)

形參和實(shí)參:實(shí)參是形參的初始值。第一個(gè)實(shí)參初始化第一個(gè)形參,第n個(gè)實(shí)參初始化第n個(gè)形參。

局部變量:形參和函數(shù)體內(nèi)部定義的變量統(tǒng)稱為局部變量,僅在函數(shù)的作用域內(nèi)可見(jiàn)。

自動(dòng)對(duì)象:把只存在于塊執(zhí)行期間的對(duì)象稱為自動(dòng)對(duì)象。形參是一種自動(dòng)對(duì)象,所以函數(shù)一旦結(jié)束,形參也就被銷(xiāo)毀。

局部靜態(tài)變量:有時(shí)有必要令局部變量的生命周期貫穿函數(shù)調(diào)用及之后的時(shí)間?梢詫⒕植孔兞慷x成static從而獲得這樣的對(duì)象。局部靜態(tài)對(duì)象在程序的執(zhí)行路徑第一次經(jīng)過(guò)對(duì)象定義語(yǔ)句時(shí)初始化,并且直到程序終止才被銷(xiāo)毀,在此期間即使對(duì)像所在的函數(shù)結(jié)束執(zhí)行也不會(huì)對(duì)它有影響。


二、參數(shù)傳遞

1、函數(shù)傳參的三種方式:傳值傳遞、地址傳遞、引用傳遞

(1)傳值傳遞

(1)傳值傳遞即將實(shí)參的值拷貝給形參。形參和實(shí)參是兩個(gè)相互獨(dú)立的對(duì)象,各占一個(gè)獨(dú)立的存儲(chǔ)空間。

(2)形參的存儲(chǔ)空間是函數(shù)被調(diào)用時(shí)才分配的,調(diào)用開(kāi)始,系統(tǒng)為形參開(kāi)辟一個(gè)臨時(shí)的存儲(chǔ)區(qū),然后將各實(shí)參傳遞給形參,這是形參就得到了實(shí)參的值。

示例代碼:

#include<stdio.h>

void swap1(int x, inty)//定義中的x,y變量是swap函數(shù)的兩個(gè)形參

{

       int tmp;

       tmp = x;

       x = y;

       y = tmp;

       printf("x=%d,y=%d\n", x, y);

}

int main()

{

       int a = 2;

       int b = 3;

       swap1(a, b);//a,b變量為swap函數(shù)的實(shí)際參數(shù)

       printf("a=%d,b=%d", a, b);

       return 0;

}

輸出結(jié)果為:x=3,y=2; a=2,b=3

代碼分析:a雖然賦值給x,但是a的值并沒(méi)有改變,對(duì)x的任何修改都不會(huì)改變a的值。函數(shù)是通過(guò)賦值把a(bǔ),b賦給x,y,這是一個(gè)隱含操作,我們不能把它顯式的寫(xiě)出來(lái),進(jìn)行函數(shù)中變量的值進(jìn)行交換時(shí)只是形參x,y的交換,并沒(méi)有對(duì)實(shí)參進(jìn)行真正交換,所以a,b值不變。


(2)地址傳遞

因?yàn)橹羔樖刮覀兛梢蚤g接地訪問(wèn)它所指的對(duì)象,所以通過(guò)指針可以修改它所指對(duì)象的值。

地址傳遞與值傳遞的不同在于,它把實(shí)參的存儲(chǔ)地址傳送給形參,使得形參指針和實(shí)參指針指向同一塊地址。因此,被調(diào)用函數(shù)中對(duì)形參指針?biāo)赶虻牡刂分袃?nèi)容的任何改變都會(huì)影響到實(shí)參。

示例代碼:

void swap2(int *px, int*py)

{

    int tmp;

    tmp = *px;

    *px = *py;

    *py = tmp;

    printf("px=%d,py=%d\n", *px, *py);

}

int main()

{

    int a = 2;

    int b = 3;

    swap2(&a, &b);/*調(diào)用了swap函數(shù),同樣也有隱含動(dòng)作px=&a;py=&b;*/

    printf("a=%d,b=%d", a, b);

    return 0;

}

運(yùn)行結(jié)果為px=3,py=2;a=3,b=2;

代碼分析:有了兩行隱含賦值操作,我們可以清晰的看出指針*px,*py是對(duì)變量a,b的值操作。函數(shù)里面對(duì)a和b的值進(jìn)行了交換。這就是傳址。


(3)引用傳遞

引用傳遞是以引用為參數(shù),則既可以使得對(duì)形參的任何操作都能改變相應(yīng)數(shù)據(jù),又使函數(shù)調(diào)用方便。引用傳遞是在形參調(diào)用前加入引用運(yùn)算符“&”。引用為實(shí)參的別名,和實(shí)參是同一個(gè)變量,則他們的值也相同,該引用改變則它的實(shí)參也改變。

代碼示例:

#include<stdio.h>

void  swap3(int &x,int &y)

{

    int tmp = x;

    x = y;

    y = tmp;

    printf("x=%d,y=%d\n", x, y);

}

int main()

{

    int a = 2;

    int b = 3;

    swap3(a, b);//調(diào)用方式與傳值一樣

    printf("a=%d,b=%d", a, b);

    system("pause");

    return 0;

}

輸出結(jié)果:x=3,y=2; a=3,b=2;

代碼分析:我們看到該代碼只與傳值中swap函數(shù)定義不同,swap3中參數(shù)都加了取地址符號(hào)&,有了這個(gè)函數(shù)會(huì)將a,b分別替代了x,y,這樣函數(shù)里面操作就是a,b本身了。


2、結(jié)論

(1)除非實(shí)參是具體數(shù)值(5等)或者實(shí)參和形參是相同的名字外,避免使用傳值傳遞。

(2)當(dāng)某種類型不支持拷貝時(shí),函數(shù)只能通過(guò)引用形參訪問(wèn)該類型的對(duì)象。

(3) 一個(gè)函數(shù)只能返回一個(gè)值,然而有時(shí)候函數(shù)需要同時(shí)返回多個(gè)值,引用形參為我們一次返回多個(gè)結(jié)果提供了有效的途徑。


三、數(shù)組形參

1、數(shù)組的兩個(gè)特殊性質(zhì):

①不允許拷貝數(shù)組(arry1=arry2):因?yàn)椴荒芸截悢?shù)組,所以無(wú)法以值傳遞的方式使用數(shù)組參數(shù)。

②使用數(shù)組時(shí)會(huì)將其轉(zhuǎn)換成指針:因?yàn)閿?shù)組會(huì)被轉(zhuǎn)換成指針,所以當(dāng)為函數(shù)傳遞一個(gè)數(shù)組時(shí),實(shí)際傳遞的是只想數(shù)組首元素的指針。


2、數(shù)組數(shù)據(jù)的傳送

要確定一個(gè)一維數(shù)組只需要知道:一個(gè)是數(shù)組的首地址,另一個(gè)是數(shù)組的長(zhǎng)度,這樣就可以唯一地確定一個(gè)一維數(shù)組。因此,要想通過(guò)實(shí)參和形參將一個(gè)數(shù)組從主調(diào)函數(shù)傳到被調(diào)函數(shù),那么只需要傳遞這兩個(gè)信息即可。

因?yàn)閿?shù)組是連續(xù)存放的,只要知道數(shù)組的首地址和數(shù)組的長(zhǎng)度就能找到這個(gè)數(shù)組中所有的元素。對(duì)于一維數(shù)組來(lái)說(shuō),其數(shù)組名就表示一維數(shù)組的首地址。所以只需要傳遞數(shù)組名和數(shù)組長(zhǎng)度這兩個(gè)參數(shù)就可以將數(shù)組從主調(diào)函數(shù)傳入被調(diào)函數(shù)中。

當(dāng)數(shù)組名作為函數(shù)的實(shí)參時(shí),形參列表中也應(yīng)定義相應(yīng)的數(shù)組(或用指針變量),且定義數(shù)組的類型必須與實(shí)參數(shù)組的類型一致,如果不一致就會(huì)出錯(cuò)。但形參中定義的數(shù)組無(wú)須指定數(shù)組的長(zhǎng)度,而是再定義一個(gè)參數(shù)用于傳遞數(shù)組的長(zhǎng)度。所以在傳遞實(shí)參的時(shí)候,數(shù)組名和數(shù)組長(zhǎng)度也只能用兩個(gè)參數(shù)分開(kāi)傳遞,而不能寫(xiě)在一起。因?yàn)榧词箤?xiě)在一起,系統(tǒng)在編譯時(shí)也只是檢查數(shù)組名,并不會(huì)檢查數(shù)組長(zhǎng)度。所以數(shù)組長(zhǎng)度要額外定義一個(gè)變量進(jìn)行傳遞。


當(dāng)將數(shù)組從一個(gè)函數(shù)傳到另一個(gè)函數(shù)中時(shí),并不是將數(shù)組中所有的元素一個(gè)一個(gè)傳過(guò)來(lái)(那樣效率就太低了)。而是將能夠唯一確定一個(gè)數(shù)組的信息傳過(guò)來(lái),即數(shù)組名(數(shù)組首地址)和數(shù)組長(zhǎng)度。此時(shí)主調(diào)函數(shù)和被調(diào)函數(shù)操作的就是同一個(gè)數(shù)組。

數(shù)組名就是數(shù)組的首地址。因此在數(shù)組名作函數(shù)參數(shù)時(shí)所進(jìn)行的傳送只是地址的傳送,也就是說(shuō)把實(shí)參數(shù)組的首地址賦予形參數(shù)組名。形參數(shù)組名取得該首地址之后,也就等于有了實(shí)在的數(shù)組。實(shí)際上是形參數(shù)組和實(shí)參數(shù)組為同一數(shù)組,共同擁有一段內(nèi)存空間。


當(dāng)用數(shù)組名作函數(shù)參數(shù)時(shí),情況則不同。由于實(shí)際上形參和實(shí)參為同一數(shù)組,因此當(dāng)形參數(shù)組發(fā)生變化時(shí),實(shí)參數(shù)組也隨之變化。當(dāng)然這種情況不能理解為發(fā)生了“雙向”的值傳遞。但從實(shí)際情況來(lái)看,調(diào)用函數(shù)之后實(shí)參數(shù)組的值將由于形參數(shù)組值的變化而變化。

一般來(lái)數(shù)參數(shù)的傳遞是值傳遞,也就是說(shuō)實(shí)參傳給形參,形參發(fā)生改變時(shí)實(shí)參并不會(huì)改變,(單向)。但是數(shù)組在傳遞的時(shí)候是地址傳遞,只要形參發(fā)生了變化,實(shí)參也會(huì)發(fā)生變化(“雙向”)。



3、管理指針形參

因?yàn)閿?shù)組是以指針的形式傳遞給函數(shù)的,所以開(kāi)始函數(shù)并不知道數(shù)組的確切大小,調(diào)用者應(yīng)該為此提供一些額外的信息。管理指針形參有三種常用技術(shù):

(1)使用標(biāo)記指定數(shù)組長(zhǎng)度

    指要求數(shù)組本身包含一個(gè)結(jié)束字符。這種方法適用于有明顯結(jié)束標(biāo)記且該標(biāo)記不會(huì)與普通數(shù)據(jù)混淆的情況,倒是對(duì)像int這樣所有取值都是合法值的數(shù)據(jù)就不太有效了。

void printf(char *cp)

{

                       if(cp)         /*若數(shù)組不是一個(gè)空指針*/

while(*cp)   /*只要指針?biāo)傅淖址皇强兆址?/

cout<<*cp++;

}


(2)使用標(biāo)準(zhǔn)庫(kù)規(guī)范

指?jìng)鬟f指向數(shù)組首元素和尾后元素的指針。為了調(diào)用這個(gè)函數(shù),需要定義兩個(gè)指針:一個(gè)指向要輸出的首元素,另一個(gè)指向尾元素的下一位置。


(3)顯式傳遞一個(gè)表示數(shù)組大小的形參

指專門(mén)定義一個(gè)表示數(shù)組大小的形參。

# include<stdio.h>

int AddArray(intarray[], int n);  //函數(shù)聲明

int main(void)

{

inta[] = {1, 2, 3, 4, 5, 6, 7, 8};

/*數(shù)組所占內(nèi)存總大小除以該數(shù)組中一個(gè)元素所占內(nèi)存的大小, 從而得到數(shù)組元素的個(gè)數(shù)*/

    int size = sizeof(a) / sizeof(a[0]);

    printf("sum = %d\n", AddArray(a,size));

    return 0;

}

int AddArray(intarray[], int n)  //形參數(shù)組中不需要寫(xiě)長(zhǎng)度

{

    int i, sum = 0;

    for (i=0; i<n; ++i)

    {

        sum += array[ i];
[ i]
    }

    return sum;

}

輸出結(jié)果:sum=36






int test1(int *p)

{  

for(int i=0;i<5;i++)

{         

printf("%d",p[ i]); //我們?cè)谶@里還可以用)*(p+i)來(lái)輸出數(shù)組中的值
[ i]
}  

}

int test2(int a[])

{

for(int i=0;i<5;i++)

{

         printf("%d",a[ i]);
[ i]
    }

}

int main()

{  

int a[5] = {1,2,3,4,5},*p;

p = a;

test1(p);      

test2(a);

}




#include<stdio.h>


floataver(float a[5]){

    int i;

    float av,s=a[0];

    for(i=1;i<5;i++)

        s=s+a[ i];
[ i]
    av=s/5;

    return av;

}


intmain(void){

    float sco[5],av;

    int i;

    printf("\ninput 5 scores:\n");

    for(i=0;i<5;i++)

        scanf("%f",&sco[ i]);
[ i]
    av=aver(sco);

    printf("average score is%5.2f",av);

    return 0;

}



在函數(shù)形參表中,允許不給出形參數(shù)組的長(zhǎng)度,或用一個(gè)變量來(lái)表示數(shù)組元素的個(gè)數(shù)。例如,可以寫(xiě)為:

    void nzp(int a[])

或?qū)憺?br />
    void nzp( int a[], int n )

其中形參數(shù)組a沒(méi)有給出長(zhǎng)度,而由n值動(dòng)態(tài)地表示數(shù)組的長(zhǎng)度。n的值由主調(diào)函數(shù)的實(shí)參進(jìn)行傳送。



4、傳遞多維數(shù)組

多維數(shù)組也可以作為函數(shù)的參數(shù)。在函數(shù)定義時(shí)對(duì)形參數(shù)組可以指定每一維的長(zhǎng)度,也可省去第一維的長(zhǎng)度。因此,以下寫(xiě)法都是合法的:

int MA(int a[3][10]) 或 int MA(int a[][10])。

因?yàn)槎嗑S數(shù)組是數(shù)組的數(shù)組,所以首元素本身就是一個(gè)數(shù)組,指針就是一個(gè)指向數(shù)組的指針。數(shù)組第二維(以及后面所有維度)的大小都是數(shù)組類型的一部分,不能省略。

Void fun1( int (*matrix)[10], introwsize ) {……}

Void fun1( int matrix[][10], introwsize ) {……}



靈活的去定位到某一行某一列:

void test2(int  m,int n,int **p)

{  

//m,n是行和列,      

for(int i = 0; i < m; i++)

{         

for(int j = 0; j < n; j++)

{               

printf("%d ",*((int*)p+n*i+j));              

}  

}

}

int main()

{  

int a[5][5],i,j;            

for(i = 0; i < 5; i++)

{         

for(j = 0; j < 5; j++)

{               

a[ i][j] = i*5 + (j +1);        
[ i]
}  

}  

test2(5,5,(int **)a);   

return 0;     

}


或者:

#include<stdio>

void test2(int  m,int n,int *p)

{

//m,n是行和列,

for(int i = 0; i<m; i++)

{

for(int j = 0; j < n; j++)

{

            printf("%d ",*(p+n*i+j));

        }

    }

}

void main()

{

int a[5][5],i,j;

for(i = 0; i <5; i++)

{

for(j = 0; j < 5; j++)

{

a[ i][j] = i*5 + (j +1);
[ i]
        }

    }

   test2(5,5,(int *)a);

}
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表