函數
函數是C語言重要的組成部分,你現在,或者以後(如果C沒什麼變化的話)所寫的任何一個C語言程序都是由一個一個的函數組合在一起的,當然,現在或許你只會在主函數 main中寫一個小程序,那麼在看了本篇文章後,我覺得自己編寫多個函數在一個程序中運行肯定不是問題啦,對於理解C語言的模塊化編程也有很大的幫助。
前面已經學過很多數據類型,如指針,數組,結構體,等數據類型,想想,在使用之前,我們首先需要進行什麼操作? 沒錯,首先是定義。當然,使用函數之前也要先定義一個函數。下面給出如何定義:
類型說明符 函數名 (傳遞的參數類型 行參名...)
{
//此處的內容與主函數 main()大括號的一樣
}
想一想,上面的定義方式是否感覺很眼熟?
還記得你接觸的第一個程序吧?它的核心部分就是
int main()
{
//內容
return 0;
}
其實這就是一個主函數,每一個c語言程序的運行都需要它的存在。它的名稱是被固定的,不可整改的,即 main,會發現,main後面的小括號裡面什麼也沒有,這說明這個main函數是不帶參數的,這也是我們經常使用的。當然main函數也可以帶參數,形如 int main(int argc,char *argv[]) ,具體可參見:http://blog.csdn.net/cnctloveyu/article/details/3905720
上面的定義格式中的類型說明符指明了函數的返回值類型(一般所寫的main函數最後都有 return 0;這代表運行正常, 也可以省略,如果省略編譯時會自動加上,所以main函數的返回值為 int ),如果沒有返回值 需要加上 void 代表返回值為空。形如 void print(){} 現在這就表示定義了一個返回值類型為空的名稱為print且沒有形式參數的函數。下面我將使用到自己定義的print函數。
#include<stdio.h> void print() //print函數的定義 { printf("you are someone\n"); //語句
return ;
} int main() { print();//在主函數中調用print函數 }
運行結果:
假如沒有在主函數中調用所寫的print函數,程序也沒錯,但是print也就沒用到了。了解一個程序的執行過程是很關鍵的一步,作為一個C語言程序的運行順序,簡單來說就是以main函數為出發點,從上到下是根本,然後跟著所寫的語句執行這個順序。
下面再寫一個稍微復雜的程序:比較兩個數a,b的大小,如果a大,輸出a,如果b大,輸出b。
#include<stdio.h> //1 int Max(int c,int d) //Max函數的定義 //5 { //此時c的值等於a的值,d==b //如果c比d大,Max的返回值為c,否則,返回值為d if(c>d) //6 return c; //7 else //6 return d; //7 } int main() { int a,b,c;//2 scanf("%d%d",&a,&b);//3 //將a的值穿給形式參數 c,將b的參數穿給d //將Max的返回值,即a,b的最大值賦值給c c=Max(a,b);//4 //8 printf("%d\n",c);//輸出c //9 return 0; //10 }
(附加:外部函數應該寫在什麼位置?
一般來說,為了方便起見,把外部函數放在調用它的函數的上方,這樣可以不用再在主函數中對其進行申明。如果要放在你想放的位置,則必須要在主函數中對這個函數申明,以上面的程序為例,申明Max函數,需要在主函數裡面加上申明語句:int Max(int c,int d);c和d這兩個標識符可以去掉
#include<stdio.h> //1 int main() { int a,b,c; int Max(int c,int d); //2 //Max函數的申明,這樣可以把Max函數放在main函數的後面 //一般都把申明與數據的定義放在同一位置 //或者 int Max(int,int); scanf("%d%d",&a,&b);//3 //將a的值穿給形式參數 c,將b的參數穿給d //將Max的返回值,即a,b的最大值賦值給c c=Max(a,b);//4 //8 printf("%d\n",c);//輸出c //9 return 0; //10 } int Max(int c,int d) //Max函數的定義 //5 { //此時c的值等於a的值,d==b //如果c比d大,Max的返回值為c,否則,返回值為d if(c>d) //6 return c; //7 else //6 return d; //7 }
比較一下上面兩個程序的區別)
上面的程序就實現了求兩個數當中的最大值。程序的運行順序為 程序中所標注的 1~10 ,重復代表有可能是重復當中的某一個。現在看看這兩個程序,與最上面的程序相比是不是多了很多東西? 第二和第三個程序定義了一個Max函數,它有返回值,所以return後面接的是一個與這個返回值一致的某個數或者表達式,第一個程序,定義了返回值的類型為void類型,為空,所以沒有返回值,沒有返回值可以寫作 return;或者空著不寫這一語句. 另外可以看到我在main函數中定義了變量c,同時,在Max函數中我也定義了一個變量c,作為形參。不是說,程序中的變量名不能相同嗎?其實,這和變量的作用域有關。變量分為 兩種,全局變量和局部變量,全局變量即在函數外部定義的變量,局部變量是在函數內部定義的變量,前面可能沒提到過,全局變量只需要在函數的外部定義一次,即能在其下方所有的函數中使用這個變量,而局部變量定義在函數的內部,只能在這一個函數中使用,如果其他的函數要用到它,需要進行參數的傳遞,1.通過值傳遞,2.通過地址傳遞 ,傳遞給需要用到的那個函數。
下面講講這兩種傳遞吧
1.值傳遞
只能傳遞某些變量的數值到自定義的函數裡面,而不能訪問變量的地址,不能訪問變量的地址就意味著不能在自定義的函數體裡面對這個變量進行操作,前面所寫的比較兩個數的大小就用到了值傳遞,因為在這個地方我們只需要了解到a,b兩個的值,就可以判斷到底是a大還是b大,並不需要對a與b的值進行更改等操作。
然而,很多時候,我們並不是只是想知道某個變量的值,例如:給你兩個數,讓你交換兩個數的位置,然後輸出。看到這,你肯定會想這不是很簡單的事嗎!!於是你就寫出了下面的這些程序:
way1
#include<stdio.h> int main() { int a,b; scanf("%d%d",&a,&b); printf("%d %d\n",b,a); }
way2
#include<stdio.h> int main() { int a,b,c; scanf("%d%d",&a,&b); c=a; a=b; b=c; printf("%d %d\n",a,b); }
相信上面的兩個程序你能夠寫出來。當然它們也都是十分正確的。可是我現在講的是關於函數參數的地址傳遞啊,所以在實現這個程序的同時,我還要求你用到函數,並且其參數是地址,想想吧,現在應該怎麼做呢?
回想上一講的內容,指針,指針不正可以存放地址嗎,可以通過指針接收主函數中的變量的地址,然後傳送到自定義的函數中去,之後,在自定義的函數中就可以訪問到主函數中的地址了,能訪問地址,就能對與地址對應的變量進行操作。
code:
#include<stdio.h> void swap(int *p,int *q) //指針p,q作為swap函數的形參,分別接收來自主函數的a,b的地址 { //此時 *p和在主函數中的a一樣,只是名字不一樣,*q同理 int c; c=*p; *p=*q; *q=c; return; //因為是無返回void型的函數,也可以直接去掉這一行 } int main() { int a,b; scanf("%d%d",&a,&b); //輸入兩個數 swap(&a,&b);//&為取地址符,這樣就可以把a和b的地址作為函數的實參傳遞給swap函數 printf("%d %d\n",a,b);//輸出a和b }
上面的代碼與前面寫的兩個代碼的功能是完全一樣的,只是上面的代碼有助於理解內容,所以復雜化了。
如果你看懂了這個代碼,你可能會想,用其他的方法能不能實現呢?難道一定要用到指針嗎?
很多人容易犯的錯誤就是不通過地址傳遞,通過值傳遞就想實現這,那麼,可以編寫一下試試,
code:
#include<stdio.h> void swap(int p,int q) { //交換p與q的值 int c; c=p; p=q; q=c; //此時p與q的值被交換了,但是a與b的值並沒有被交換 return; //swap函數結束 } int main() { int a,b; scanf("%d%d",&a,&b); swap(a,b);//把a與b的數值傳遞給swap函數,在swap函數中不能再次訪問到a與b printf("%d %d\n",a,b);//輸出a和b,結果與輸入的一樣,並沒有交換 return 0; }
當然把主函數中的printf("%d %d\n",a,b);刪掉。然後再再swap函數中的return;上面加上一句printf("%d %d\n",p,q);。這樣也能實現功能,但是這樣和上面的第五個程序並沒有本質的區別。
還有一個方法,記得前面提到的全局變量不。它的作用域是它的定義下面的所有的函數。
code
#include<stdio.h> int a,b;//定義a,b為全局變量,作用於下面的所有函數 void swap() { //交換a和b int c; c=a; a=b; b=c; return; //swap函數結束 } int main() { scanf("%d%d",&a,&b); swap();//無需傳遞參數,因為a與b一直都存在於main主函數和swap函數 printf("%d %d\n",a,b); return 0; }
由於重復的代碼比較多,所以就不放上運行結果了。可以自己粘貼運行一下。
這樣也實現了相同的功能。因為a,b是全局變量,所以不用通過地址傳遞也能在swap中訪問到a與b的地址
關於函數的就說這麼多吧。雖然還有不少沒提到,不過這也足夠初學者去理解了。