天天看點

在c語言中 函數名僅僅代表函數的名稱,09-C語言函數-指趣學院

函數基本概念

C源程式是由函數組成的

例如: 我們前面學習的課程當中,通過main函數+scanf函數+printf函數+邏輯代碼就可以組成一個C語言程式

C語言不僅提供了極為豐富的庫函數, 還允許使用者建立自己定義的函數。使用者可把自己的算法編寫成一個個相對獨立的函數,然後再需要的時候調用它

例如:你用C語言編寫了一個MP3播放器程式,那麼它的程式結構如下圖所示

在c語言中 函數名僅僅代表函數的名稱,09-C語言函數-指趣學院

可以說C程式的全部工作都是由各式各樣的函數完成的,是以也把C語言稱為函數式語言

函數的分類

在C語言中可從不同的角度對函數分類

從函數定義的角度看,函數可分為庫函數和使用者定義函數兩種

庫函數: 由C語言系統提供,使用者無須定義,也不必在程式中作類型說明,隻需在程式前包含有該函數原型的頭檔案即可在程式中直接調用。在前面各章的例題中反複用到printf、scanf、getchar、putchar等函數均屬此類

使用者定義函數:由使用者按需編寫的函數。對于使用者自定義函數,不僅要在程式中定義函數本身,而且在主調函數子產品中還必須對該被調函數進行類型說明,然後才能使用

從函數執行結果的角度來看, 函數可分為有傳回值函數和無傳回值函數兩種

有傳回值函數: 此類函數被調用執行完後将向調用者傳回一個執行結果,稱為函數傳回值。(必須指定傳回值類型和使用return關鍵字傳回對應資料)

無傳回值函數: 此類函數用于完成某項特定的處理任務,執行完成後不向調用者傳回函數值。(傳回值類型為void, 不用使用return關鍵字傳回對應資料)

從主調函數和被調函數之間資料傳送的角度看,又可分為無參函數和有參函數兩種

無參函數: 在函數定義及函數說明及函數調用中均不帶參數。主調函數和被調函數之間不進行參數傳送。

有參函數: 在函數定義及函數說明時都有參數,稱為形式參數(簡稱為形參)。在函數調用時也必須給出參數,稱為實際參數(簡稱為實參)

函數的定義

定義函數的目的

将一個常用的功能封裝起來,友善以後調用

自定義函數的書寫格式

傳回值類型 函數名(參數類型 形式參數1,參數類型 形式參數2,…) {

函數體;

傳回值;

}

示例

int main(){

printf("hello world\n");

retrun 0;

}

定義函數的步驟

函數名:函數叫什麼名字

函數體:函數是幹啥的,裡面包含了什麼代碼

傳回值類型: 函數執行完畢傳回什麼和調用者

無參無傳回值函數定義

沒有傳回值時return可以省略

格式:

void 函數名() {

函數體;

}

示例:

// 1.沒有傳回值/沒有形參

// 如果一個函數不需要傳回任何資料給調用者, 那麼傳回值類型就是void

void printRose() {

printf(" {@}\n");

printf(" |\n");

printf(" \\|/\n"); // 注意: \是一個特殊的符号(轉意字元), 想輸出\必須寫兩個斜線

printf(" |\n");

// 如果函數不需要傳回資料給調用者, 那麼函數中的return可以不寫

}

無參有傳回值函數定義

格式:

傳回值類型 函數名() {

函數體;

return 值;

}

示例:

int getMax() {

printf("請輸入兩個整數, 以逗号隔開, 以回車結束\n");

int number1, number2;

scanf("%i,%i", &number1, &number2);

int max = number1 > number2 ? number1 : number2;

return max;

}

有參無傳回值函數定義

形式參數表清單的格式: 類型 變量名,類型 變量2,......

格式:

void 函數名(參數類型 形式參數1,參數類型 形式參數2,…) {

函數體;

}

示例:

void printMax(int value1, int value2) {

int max = value1 > value2 ? value1 : value2;

printf("max = %i\n", max);

}

有參有傳回值函數定義

格式:

傳回值類型 函數名(參數類型 形式參數1,參數類型 形式參數2,…) {

函數體;

return 0;

}

示例:

int printMax(int value1, int value2) {

int max = value1 > value2 ? value1 : value2;

return max;

}

函數定義注意

函數名稱不能相同

void test() {

}

void test() { // 報錯

}

函數的參數和傳回值

形式參數

在定義函數時,函數名後面小括号()中定義的變量稱為形式參數,簡稱形參

形參變量隻有在被調用時才配置設定記憶體單元,在調用結束時,即刻釋放所配置設定的記憶體單元。

是以,形參隻有在函數内部有效,函數調用結束傳回主調函數後則不能再使用該形參變量

int max(int number1, int number2) // 形式參數

{

return number1 > number2 ? number1 : number2;

}

實際參數

在調用函數時, 傳入的值稱為實際參數,簡稱實參

實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須具有确定的值,以便把這些值傳送給形參

是以應預先用指派,輸入等辦法使實參獲得确定值

int main() {

int num = 99;

// 88, num, 22+44均能得到一個确定的值, 是以都可以作為實參

max(88, num, 22+44); // 實際參數

return 0;

}

形參、實參注意點

調用函數時傳遞的實參個數必須和函數的形參個數必須保持一緻

int max(int number1, int number2) { // 形式參數

return number1 > number2 ? number1 : number2;

}

int main() {

// 函數需要2個形參, 但是我們隻傳遞了一個實參, 是以報錯

max(88); // 實際參數

return 0;

}

形參實參類型不一緻, 會自動轉換為形參類型

void change(double number1, double number2) {// 形式參數

// 輸出結果: 10.000000, 20.000000

// 自動将實參轉換為double類型後儲存

printf("number1 = %f, number2 = %f", number1, number2);

}

int main() {

change(10, 20);

return 0;

}

當使用基本資料類型(char、int、float等)作為實參時,實參和形參之間隻是值傳遞,修改形參的值并不影響到實參函數可以沒有形參

void change(int number1, int number2) { // 形式參數

number1 = 250; // 不會影響實參

number2 = 222;

}

int main() {

int a = 88;

int b = 99;

change(a, b);

printf("a = %d, b = %d", a, b); // 輸出結果: 88, 99

return 0;

}

傳回值類型注意點

如果沒有寫傳回值類型,預設是int

max(int number1, int number2) {// 形式參數

return number1 > number2 ? number1 : number2;

}

函數傳回值的類型和return實際傳回的值類型應保持一緻。如果兩者不一緻,則以傳回值類型為準,自動進行類型轉換

int height() {

return 3.14;

}

int main() {

double temp = height();

printf("%lf", temp);// 輸出結果: 3.000000

}

一個函數内部可以多次使用return語句,但是return語句後面的代碼就不再被執行

int max(int number1, int number2) {// 形式參數

return number1 > number2 ? number1 : number2;

printf("執行不到"); // 執行不到

return 250; // 執行不到

}

函數的聲明

在C語言中,函數的定義順序是有講究的:

預設情況下,隻有後面定義的函數才可以調用前面定義過的函數

如果想把函數的定義寫在main函數後面,而且main函數能正常調用這些函數,那就必須在main函數的前面進行函數的聲明, 否則

系統搞不清楚有沒有這個函數

系統搞不清楚這個函數接收幾個參數

系統搞不清楚這個函數的傳回值類型是什麼

是以函數聲明,就是在函數調用之前告訴系統, 該函數叫什麼名稱, 該函數接收幾個參數, 該函數的傳回值類型是什麼

函數的聲明格式:

将自定義函數時{}之前的内容拷貝到調用之間即可

例如: int max( int a, int b );

或者: int max( int, int );

// 函數聲明

void getMax(int v1, int v2);

int main(int argc, const char * argv[]) {

getMax(10, 20); // 調用函數

return 0;

}

// 函數實作

void getMax(int v1, int v2) {

int max = v1 > v2 ? v1 : v2;

printf("max = %i\n", max);

}

函數的聲明與實作的關系

聲明僅僅代表着告訴系統一定有這個函數, 和這個函數的參數、傳回值是什麼

實作代表着告訴系統, 這個函數具體的業務邏輯是怎麼運作的

函數聲明注意點:

函數的實作不能重複, 而函數的聲明可以重複

// 函數聲明

void getMax(int v1, int v2);

void getMax(int v1, int v2);

void getMax(int v1, int v2); // 不會報錯

int main(int argc, const char * argv[]) {

getMax(10, 20); // 調用函數

return 0;

}

// 函數實作

void getMax(int v1, int v2) {

int max = v1 > v2 ? v1 : v2;

printf("max = %i\n", max);

}

函數聲明可以寫在函數外面,也可以寫在函數裡面, 隻要在調用之前被聲明即可

int main(int argc, const char * argv[]) {

void getMax(int v1, int v2); // 函數聲明, 不會報錯

getMax(10, 20); // 調用函數

return 0;

}

// 函數實作

void getMax(int v1, int v2) {

int max = v1 > v2 ? v1 : v2;

printf("max = %i\n", max);

}

當被調函數的函數定義出現在主調函數之前時,在主調函數中也可以不對被調函數再作聲明

// 函數實作

void getMax(int v1, int v2) {

int max = v1 > v2 ? v1 : v2;

printf("max = %i\n", max);

}

int main(int argc, const char * argv[]) {

getMax(10, 20); // 調用函數

return 0;

}

如果被調函數的傳回值是整型時,可以不對被調函數作說明,而直接調用

int main(int argc, const char * argv[]) {

int res = getMin(5, 3); // 不會報錯

printf("result = %d\n", res );

return 0;

}

int getMin(int num1, int num2) {// 傳回int, 不用聲明

return num1 < num2 ? num1 : num2;

}

main函數分析

main的含義:

main是函數的名稱, 和我們自定義的函數名稱一樣, 也是一個辨別符

隻不過main這個名稱比較特殊, 程式已啟動就會自動調用它

return 0;的含義:

告訴系統main函數是否正确的被執行了

如果main函數的執行正常, 那麼就傳回0

如果main函數執行不正常, 那麼就傳回一個非0的數

傳回值類型:

一個函數return後面寫的是什麼類型, 函數的傳回值類型就必須是什麼類型, 是以寫int

形參清單的含義

int argc :

系統在啟動程式時調用main函數時傳遞給argv的值的個數

const char * argv[] :

系統在啟動程式時傳入的的值, 預設情況下系統隻會傳入一個值, 這個值就是main函數執行檔案的路徑

也可以通過指令行或項目設定傳入其它參數

在c語言中 函數名僅僅代表函數的名稱,09-C語言函數-指趣學院
在c語言中 函數名僅僅代表函數的名稱,09-C語言函數-指趣學院

函數練習

寫一個函數從鍵盤輸入三個整型數字,找出其最大值

寫一個函數求三個數的平均值

遞歸函數(了解)

什麼是遞歸函數?

一個函數在它的函數體内調用它自身稱為遞歸調用

void function(int x){

function(x);

}

遞歸函數構成條件

自己搞自己

存在一個條件能夠讓遞歸結束

問題的規模能夠縮小

示例:

擷取使用者輸入的數字, 直到使用者輸入一個正數為止

void getNumber(){

int number = -1;

while (number < 0) {

printf("請輸入一個正數\n");

scanf("%d", &number);

}

printf("number = %d\n", number);

}

void getNumber2(){

int number = -1;

printf("請輸入一個正數abc\n");

scanf("%d", &number);

if (number < 0) {

// 負數

getNumber2();

}else{

// 正數

printf("number = %d\n", number);

}

}

遞歸和循環差別

能用循環實作的功能,用遞歸都可以實作

遞歸常用于"回溯", "樹的周遊","圖的搜尋"等問題

但代碼了解難度大,記憶體消耗大(易導緻棧溢出), 是以考慮到代碼了解難度和記憶體消耗問題, 在企業開發中一般能用循環都不會使用遞歸

遞歸練習

有5個人坐在一起,問第5個人多少歲?他說比第4個人大兩歲。問 第4個人歲數,他說比第3個人大兩歲。問第3個人,又說比第2個 人大兩歲。問第2個人,說比第1個人大兩歲。最後問第1個人, 他說是10歲。請問第5個人多大?

用遞歸法求N的階乘

設計一個函數用來計算B的n次方