函數調用
函數調用一般有兩種方式,一種是形參不會影響實參的傳值調用,另一種是形參會影響實參的傳址調用。
傳值調用:在函數調用過程中,我們將函數值傳遞進函數體中的時候,實際在函數體內形成了一份新的內存空間用來存儲我們傳遞進去的值,因此形參在函數體內無論再怎么改變都不會影響調用函數時使用的實參。
#define _CRT_SECURE_NO_WARNINGS //添加頭文件 #include <stdio.h> #include <stdlib.h> void exchange(int num1, int num2) { int t = num1; num1 = num2; num2 = t; } //主函數,函數入口 int main() { int num1 = 1; int num2 = 2; exchange(num1, num2); printf("num1 = %d,num2 = %d\n", num1, num2); return 0; }
傳址調用:傳址調用是將參數的地址進行傳入,其實就是把指針變量作為參數,而這個指針變量中存放的就是要傳入參數的地址,所以有了這個指針變量,我們就可以找到參數的本體,並對其進行操作,所以當我們將變量的地址傳入的時候,實參就被鎖定了,形參的改變,也會使實參改變。
#define _CRT_SECURE_NO_WARNINGS //添加頭文件 #include <stdio.h> #include <stdlib.h> void exchange(int* num1, int* num2) { int t = *num1; *num1 = *num2; *num2 = t; } //主函數,函數入口 int main() { int num1 = 1; int num2 = 2; exchange(&num1, &num2); printf("num1 = %d,num2 = %d\n", num1, num2); return 0; }
嵌套調用:嵌套調用是構成C語言最基礎的語法,簡單來說就是允許在函數內調用其它函數,就像我們在main()函數中調用外部我們自己寫的函數,這就是嵌套調用。
鏈式訪問:鏈式訪問是在函數參數里調用函數,這種調用方式也很簡單,不過是將一個有返回值的函數在另一個函數的參數列表中進行調用,運行時會優先調用參數列表中的函數然后根據返回值進行判斷外函數如何運行。
遞歸函數:遞歸函數簡單來說就是函數自己調用自己,形成循環,然后在一定條件下,結束循環,完成遞歸。
遞歸函數的思想十分巧妙,內部執行的過程很復雜,因此十分難理解。遞歸就是將大問題分解為子問題,將最終的子問題的解作為終止條件,而這些子問題和大問題的解法都是一樣的,只需要思考大問題和子問題之間的關系就行,不需要一層層往下去思考子問題與子子問題之間的關系。
給出幾個例子:
#define _CRT_SECURE_NO_WARNINGS //添加頭文件 #include <stdio.h> #include <stdlib.h> //遞歸求階乘 int factor(int num) { //如果數字等於一則返回它本身 if (num == 1) { return 1; } return num * factor(num - 1);//num! = num * (num - 1)! } //主函數,函數入口 int main() { printf("8的階乘是:%d!\n", factor(8)); return 0; }
還有兩個詳見我的另兩篇博
https://www.cnblogs.com/zhm521/p/13888179.html
https://www.cnblogs.com/zhm521/p/13884267.html
函數的聲明和定義
函數聲明:我們在寫代碼的時候經常把自定義函數寫在main()函數的上方,這樣會使代碼的可讀性變低。別人在看你寫的代碼的時候,必須得翻看你寫的那些雜亂無章的函數,然后才能找到main()函數,這樣就很不好。
那么我們可不可以把自定義函數寫在main()函數的下方?當然是可以的,只不過我們需要先聲明一下,聲明要告訴編譯器有一個函數叫什么,參數是什么,返回類型是什么,但是具體函數存在不存在,無關緊要。
#define _CRT_SECURE_NO_WARNINGS //添加頭文件 #include <stdio.h> #include <stdlib.h> //函數的聲明可以省略寫參數名 int func(int); //主函數,函數入口 int main() { int num = 0; func(num); return 0; } int func(int num) { /* something; */ return num; }
在本例中,函數的定義放在了調用之后,而編譯器並沒有報錯,這就是上方的聲明起到了作用。
頭文件:我們一般習慣添加一個頭文件,然后把函數的聲明放進頭文件中,在寫代碼的時候,只要包含這個頭文件即可,這樣使自己的代碼看起來更簡潔,可讀性更高。
並且頭文件的存在,可以使我們將代碼分開來寫,以后工作中,一個工程可能需要寫幾百萬行代碼,如果全都放在一起,那么可讀性幾乎為零,這時候,我們需要將主函數存放於一個文件,其他的函數分為不同的類別、不同的用法等等,放在其他的文件中,而所有的函數聲明放在頭文件中,在主函數所在的文件中,包含頭文件即可。展示如下:
//頭文件 #pragma once int func(int);//函數的聲明可以省略寫參數名
//另一個.c文件 int func(int num) { /* something; */ return num; }
//主函數所在的文件 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h>//添加頭文件 #include <stdlib.h> #include "test.h" int main()//主函數,函數入口 { int num = 0; func(num); return 0; }
注:①自己寫的頭文件,最好使用“”來包含,因為<>包含的頭文件是在庫函數中去查找,而“”包含的頭文件,則是在本工程中去查找,這樣可以提高查找頭文件的效率。
②在自己寫的頭文件上方,我們可以看到這個“#program once”語句,他存在的作用就是保證我們在多次調用同一個我文件的時候不會造成多次調用,發生錯誤,可以說是為了彌補C語言頭文件使用的弊端,也是頭文件必須的。