函數編程
函數是C語言重要的組成部分,你如今,或者之後(若是C沒什麼變化的話)所寫的任何一個C語言程序都是由一個一個的函數組合在一塊兒的,固然,如今或許你只會在主函數 main中寫一個小程序,那麼在看了本篇文章後,我以爲本身編寫多個函數在一個程序中運行確定不是問題啦,對於理解C語言的模塊化編程也有很大的幫助。小程序
前面已經學過不少數據類型,如指針,數組,結構體,等數據類型,想一想,在使用以前,咱們首先須要進行什麼操做? 沒錯,首先是定義。固然,使用函數以前也要先定義一個函數。下面給出如何定義:數組
類型說明符 函數名 (傳遞的參數類型 行參名...)模塊化
{函數
//此處的內容與主函數 main()大括號的同樣spa
}.net
想想,上面的定義方式是否感受很眼熟?指針
還記得你接觸的第一個程序吧?它的核心部分就是code
int main()blog
{
//內容
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的地址
關於函數的就說這麼多吧。雖然還有很多沒提到,不過這也足夠初學者去理解了。