在C語言中,大多數功能都是靠函數來實現的,定義一個函數的具體格式以下:
返回值類型 函數名([[參數類型 參數名1], [參數類型 參數名2],..., [參數類型 參數n]])
{
執行語句
.........
return 返回值;
}
釋義:
返回值類型:用於限定函數返回值的數據類型;
函數名:表示函數的名稱,該名稱能夠根據標識符命名規範來定義;
參數類型:用於限定調用方法時傳入參數的數據類型;
參數名:用於接收調用方法時傳入的數據;
return關鍵字:用於結束函數,並返回函數指定類型的值;
返回值:被return語句返回的值,該值返回給調用者。若是函數沒有返回值,則返回值類型要聲明爲void,此時,函數體中的return 語句能夠省略不寫。
在以上語法中,函數中的「[[參數類型 參數名1],[參數類型 參數名2],...[參數類型 參數n]]」被稱做參數列表,它用於標水函數在調用時須要接收的參數。若是函數不須要接收任何參數,則參數列表爲空,這樣的函數被稱爲無參函數。若是參數列表不爲空的函數就是有參函數。以下兩種函數:
無參函數: 在C語言中,無參函數的定義很簡單,定義以下:
void func()
{
printf("hello word");
}
上述代碼中,func()函數就是一無參函數,在定義時參數列表爲空,要想執行這個函數須要在main()函數中調用它。以下程序員
#include <stdio.h> //定義函數 void func() { printf("hello word!\n"); } int main(int argc, const char * argv[]) { func(); //打印hello word return 0; } 運行結果: hello word! Program ended with exit code: 0
有參函數
與無參函數函數相比,有你參函數函數須要在定義時,在函數名稱後面的括號中填寫參數。所謂的參數是一個變量,用於接收調用函數傳入的數據。
void func(int x, int y)
{
int sum = x + y;
printf("sum = %d\n", sum);編程
}
以上代碼是兩個整數之和,以下:數組
#include <stdio.h> //定義函數 void func(int x, int y) { int sum = x + y; printf("sum = %d\n", sum); } int main(int argc, const char * argv[]) { func(3, 5); //打印hello word return 0; } 運行結果以下: sum = 8 Program ended with exit code: 0
函數的返回值數據結構
函數的返回值是指函數被調用以後,返回給調用者的值,函數返回值的具體語法格式上以下:
return 表達式;
對於返回值爲空的函數,能夠直接在return語句後面加分號,具體語法格式以下:
return;
有返回值的函數以下示例:
函數
#include <stdio.h> //定義函數 int func(int x, int y) { int sum = x + y; return sum; } int main(int argc, const char * argv[]) { int sum = func(3, 5); //打印hello word printf("sum =%d\n", sum); return 0; } 運行結果 sum =8 Program ended with exit code: 0
在C語言中,常常會進行一些輸入輸出操做,爲此,C語言提供了printf()和scanf()函數,其中,printf()函數用於控制檯輸出字符,scanf()函數用於讀取用戶的輸入。spa
printf()函數
在前面章節中,常用printf()函數輸出數據,它能夠經過格式控制字符輸出多個任意類型的數據。以下:
code
經常使用格式字符 | 含義 |
%s | 輸出一個字符串 |
%c | 輸出一個字符 |
%d | 以十進制輸出一個有符號整型 |
%u | 以十進制輸出一個無符號整型 |
%o | 以八進制輸出一個整數 |
%x | 以十六進制輸出一個小寫整數 |
%X | 以十六進制輸出一個大寫整數 |
%f | 以十進制輸出一個浮點數 |
%e | 以科學計數法輸出一個小寫浮點數 |
%E | 以科學計數法輸出一個大寫浮點數 |
scanf()函數
scanf()函數負責從控制檯上接收用戶的輸入,它能夠靈活接收各類類型的數據,如字符串、字符、整型、浮點數等,scanf()函數也能夠經過格式控制字符控制用戶的輸入,其用法和printf()函數同樣。以下示例:遞歸
#include <stdio.h> int main(int argc, const char * argv[]) { //輸入一個字符串, 用字符數組保存字符串 char string[256]; scanf("%s", string); printf("%s\n", string); return 0; } 運行結果 dqk dqk Program ended with exit code: 0
以上代碼運行後輸入dqk並按回車鍵 而後控制檯會打印出結果:dqk.
注意:C語言中的終止符
在使用scanf()函數獲取用戶輸入信息時,若是輸入的信息包含某個終止符,scanf()函數就會認爲輸入結束。以下一些常見的終止符:ci
字符 | 含義 |
0x20 | 空格 |
\t | 水平製表符(tab鍵) |
\n | 換行 |
\v | 垂直 |
\f | 換頁 |
\r | 回車 |
函數是c語言的基本組成元素,要想實現函數的功能,必須學會正確調用函數。在c語言中,調用函數的具體語法格式以下:
函數名([[實參列表1], [實參列表2]......])
從上面的語法格式能夠看出,當調用一個函數時,須要明確函數名和實參列表。實參列表中的參數能夠是常量、變量、表達式或者空,各參數之間使用英文逗號分隔。
根據函數在程序中出現的位置,能夠有下列三種函數調用方式:
1.將函數做爲表達式調用
將函數做爲表達式調用時,函數的返回值參與表達式的運算,此時要求函數必須有返回值。示例代碼以下:作用域
int sum = func(100, 4);
2.將函數做爲語句調用
函數以語句的形式出現時,能夠將函數做爲一條語句進行調用。示例代碼以下:
printf("哈哈哈 今天是週五");
3.將函數做爲實參調用
將函數做爲另外一個函數的實參,要求該函數有返回值,示例代碼以下:
printf("%d\n", func(100, 5));
嵌套調用
在c語言中函數的定義是獨立的,即一個函數不能定義在另一個函數內部。但在調用函數時,能夠在一個函數中調用另外一個函數,這就是函數的嵌套調用。示例代碼以下:
#include <stdio.h> //求兩個數的和 int func1(int x, int y) { return x + y; } //求兩個數之差 int func2(int x, int y) { //調用函數1先求兩個數之和 int sum = func1(x, y); return sum - y; } int main(int argc, const char * argv[]) { //輸入一個字符串, 用字符數組保存字符串 int s = func2(10, 5); printf("%d\n", s); return 0; } 運行結果: 10 Program ended with exit code: 0
腦洞大開:函數調用時最多能夠嵌套多少層?
有沒有這個疑問:「既然函數嵌套調用和普通的調用看上去沒有什麼區別,那是否是能夠無限層的函數嵌套呢?」很遺憾,函數能夠嵌套調用多少層是由程序運行時一個名爲「棧」的數據結構決定的。通常而言,Windows上程序的默認棧大小大約爲8KB,每一次函數調用至少佔用8個字節,所以粗略計算下,函數調用只能只能嵌套大約一千層,若是嵌套調用的函數裏包含許多變量和參數,實際值要遠遠小於這個數目。
固然,單純手動書寫代碼寫出一千層嵌套函數調用基本是不可能的,可是一種名爲「遞歸的方法能夠輕鬆達到這個上限。
遞歸調用
所謂的遞歸就是函數內部調用自身的過程。須要注意的是,遞歸必需要求有結束條件,否則就會陷入無限遞歸的狀態,永遠沒法結束調用。接下來經過一個求1~100天然數之間的和來做爲一個案例,示例代碼以下:
#include <stdio.h> int getsum(int n) { if (n == 1) { return 1; } int temp = getsum(n-1); return temp + n; } int main(int argc, const char * argv[]) { //打印天然數之和 printf("%d\n", getsum(100)); return 0; } 運行結果 5050 Program ended with exit code: 0
前面關於函數的調用都是針對同一個源文件中其它函數進行調用的,在有些狀況下,函數也可能對另一個源文件中函數進行調用。當一個程序由多個源文件組成時,根據函數時可否被其它源文件調用,將函數分爲內部函數和外部函數。
外部函數
開發大型項目時,爲了便於團隊的協同工做;,須要把一個項目拆分紅不少源文件來分別實現,最終再把它們整合在一塊兒。爲了減小重複代碼,一個源文件有時須要調用其餘源文件中定義的函數。在c語言中,能夠被其它源文件調用的函數稱爲外部函數,在調用外部函數以前,須要在當前源文件中定義外部函數。定義外部函數的方式是在函數的返回值類型前面添加extern關鍵字,示例代碼以下:
extern int sum(int x, int y);
在上述示例代碼中,編譯會經過extern關鍵字知道sum()函數時是定義在其餘文件中的外部函數。請看代碼:
peresion.c 源文件:
#include "persion.h" int sum(int x, int y){ int sum = x + y; return sum; }
main.c 主函數文件:
extern int sum(int x, int y); int main(int argc, const char * argv[]) { int y = sum(100, 10); printf("%d\n", y); return 0; }
運行結果:
110 Program ended with exit code: 0
爲簡化編程,C語言中容許在定義外部函數時省略關鍵字extern。在以上例子中外部函數sum()也能夠修改成下面的代碼:
int sum(int x, int y);
上述代碼由函數的返回類型、函數名和參數列表組成,這類格式的代碼被稱爲函數原型。當代碼中包含函數原型時,可能會有下列兩種狀況:
1.程序員但願編譯器自動從其餘文件中查找該函數的定義。
2.程序員先定義未實現的空函數,而後在其餘文件中具體實現
內部函數
相對外部函數,外部函數只要聲明一個函數原型就可以調用其餘源文件中的函數。可是當多人蔘與開發一個項目時,頗有可能會出現函數重名的狀況,這樣,不一樣源文件中重名的函數就會互相干擾。此時,就須要一些特殊函數,這些函數只在它定義文件中有效,該類函數稱爲內部函數。
在定義內部函數時,須要在函數的返回值類型前面添加static關鍵字(又稱爲靜態函數),示例代碼以下:
static void eat(int x) { printf("%d", x); }
請看以下案例:
persion.c源文件:
#include "persion.h" void eat(int x){ x += x; printf("小狗吃了%d個饅頭", x); }
main.c 主函數源文件:
#include <stdio.h> static void eat(int x) { printf("小豬吃了%d個饅頭\n", x); } int main(int argc, const char * argv[]) { eat(10); return 0; }
運行結果:
小豬吃了10個饅頭 Program ended with exit code: 0
以上代碼中在persion.c文件和main.c源文件中都定義了eat()函數,從運行結果中能夠看出打印的是main.c文件中的eat()函數,所以說明內部函數只會被自身調用,不會受到其餘文件中同名函數的影響。
變量既能夠定義在函數內,也能夠定義在函數外。定義在不一樣位置的變量,其做用域也是不一樣的。C語言中的變量,按做用域範圍可分爲局部變量和全局變量。
局部變量
局部變量就是在函數內部聲明的變量,它只在本函數內有效,也就是說,只能在本函數內使用它。此外,局部變量只有當它所在的函數被調用時纔會被使用,而當函數調用結束時局部變量就會失去做用。
全局變量 在全部函數外部定義的變量稱爲全局變量(包含main()函數),它不屬於哪個函數,而是屬於源程序。所以全局變量能夠爲程序中全部函數共用。它的有效範圍從定義開始到源程序結束。