C語言函數

函數的概念

每個C程序都至少有一個函數,即主函數 main() ,如果程序的任務比較簡單,全部的代碼都寫在main()函數中,但是,在實際開發中,程序的任務往往比較復雜,如果全部的代碼都寫在main()函數中,main()函數將非常龐大臃腫,結構復雜,代碼重復。

我們可以根據程序的邏輯和任務的分工把代碼劃分到不同的自定義函數中,main()更關心業務邏輯和處理流程,需要執行具體任務的時候,調用這些自定義的函數就可以瞭。

為瞭方使理解,我們把函數分為兩種:一種是庫函數,一種是自定義函數。

庫函數是C語言提供的,或系統提供的,實現瞭某些基本的功能,例如scanf、printf,在程序中可以直接使用。

自定義函數是程序員為瞭完成某項任務而編寫的函數,目的是為瞭實現某項的功能或讓主程序更簡潔。程序員在使用自定義函數之前,必須先聲明和定義。

自定義函數的聲明

自定義函數聲明就是告訴編譯器函數名稱及如何調用函數,包括函數返回值的數據類型、函數名稱、參數列表。

有些程序員也將函數聲明說成是函數原型,隻是用詞不同,意思是一樣的。

C語言中的聲明函數的語法如下

返回值的數據類型return_type:函數執行完任務後,可以返回一個值,return_type是函數返回的值的數據類型,可以是int、char、double或其它自定義的數據類型。有些函數隻執行任務而不返回值,在這種情況下,return_type用是關鍵字 void表示。

無返回值的函數的聲明語法如下:

函數名稱function_name:函數名稱是標識符,命名規則與變量名稱的命名規則相同。

函數的參數列表parameter list:當函數被調用時,調用者需要向函數的參數傳遞值。參數列表包括參數的類型、順序。參數列表是可選的,也就是說,函數可以沒有參數。

無參數的函數的聲明語法如下:

函數聲明示例:

聲明瞭一個函數,返回值是int類型,函數名是checksc,函數隻有一個參數int height,註意,函數的聲明語句最後的分號不能少。

如果把自定義函數比喻成工具,函數的聲明就是這個工具的設計圖紙。

自定義函數的定義

自定義函數是工具,如果想讓這個工具能被使用,光有設計圖紙還不行,要把工具制造出來,函數的定義就是這個工具的實體,提供瞭函數的實際主體,為瞭實現函數的功能,程序員為需要函數編寫代碼。

C語言中的函數定義的語法如下:

函數定義的return_type、function_name和parameter list必須與函數聲明一致。

函數主體包含為瞭完成任務需要執行語句的集合,放在花括號內。

示例:

註意,不要在函數定義後面加分號,以下是錯誤的,初學者容易犯這種錯誤。

自定義函數聲明和定義的方式

如果自定義函數隻在調用者程序中使用,可以在調用者程序中聲明和定義,聲明一般為調用者程序的上部,定義一般在調用者程序的下部,這並不是C語言的規定,而是為瞭讓程序更方便閱讀,程序員約定的寫法。

自定義函數在調用者程序中聲明和定義的示例(book45.c):

在book45.c中,判斷超女身材的函數checksc不是公共的功能,隻是選秀程序使用,所以聲明和定義在book45.c中。

如果自定義函數是一個公共的功能模塊,例如比較兩個數的大小,就可以在其它的頭文件中聲明(如_public.h),調用者程序需要用#include預處理指令包含該函數聲明的頭文件。

如果自定義函數是一個公共的功能模塊,就可以在其它的程序文件中定義(如_public.c),編譯的時候,要把調用者程序和自定義函數的程序文件一起編譯。

在以下的示例中,函數max在_public.h頭文件中聲明,在_public.c程序文件中定義,在book46.c程序中被調用。

自定義函數的頭文件(_public.h):

自定義函數的程序文件(_public.c):

調用者程序文件(book46.c)

編譯命令如下:

註意:

1)在book46.c的第6行 ,這裡包含頭文件是用雙引號,不是尖括號<>。一般來說 #include <> 用於包含C語言提供的庫函數的頭文件,#include ""用於包含程序員自定義的頭文件。

2)編譯調用者程序的時候,把調用者程序和自定函數的程序文件一起編譯。否則編譯的時候會出現以下錯誤。

正確的編譯指令應該是gcc -o book46 book46.c _public.c

3)自定義函數的頭文件_public.h和_public.c的命名沒有規定,由程序員自己命名,就像變量的命名一樣,為瞭增加程序的可讀性,盡可能采用一些有意義的名稱。

庫函數

C語言提供瞭一些已聲明和定義的函數,調用這些函數可以完成一些基本的功能,我們把這些函數稱為C 標準函數(C standard library),簡稱庫函數,例如printf、scanf、memset、strcpy等。CC語言的庫函數有幾百個,常用的不過十分之二三,不需要記住,在以後的章節中我將詳細介紹一些常用庫函數的使用,用多瞭就熟瞭。

C語言標準庫函數的聲明的頭文件存放在/usr/include目錄中,如下:

<asset.h> <ctype.h> <errno.h> <float.h> <limits.h>

<locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h>

<stddef.h> <stdlib.h> <stdio.h> <string.h> <time.h>

C語言庫函數的定義的文件是/usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc.a(不同編譯器的版本目錄名有所不同),這是一個打包好的靜態鏈接庫文件,靜態鏈接庫的知識我們以後再介紹。

我們在用gcc編譯程序的時候並沒有把libgcc.a包含進來,那是因為gcc編譯器缺省會包含它,但是,程序員自定義函數的頭文件和程序文件就沒有這種待遇,需要手工的包含進來。

需要包含哪些頭文件

我們在使用庫函數的時候,如果不包含它的頭文件,編譯時會出現警告,如下:

該包含哪些頭文件呢?有兩種方法,一是上百度上查資料,二是使用Linux系統提供的幫助,以strcpy函數為例,在命令行下輸入man strcpy回車,如下:

man顯示瞭函數的聲明的頭文件(第5行),函數的參數、使用方法和返回值。

註意瞭,如果程序中使用的沒有包含它頭文件的庫函數,編譯的時候不一定是警告,也可能是報錯,函數無法識別等,這個要看編譯器,不同C語言的編譯器不一樣。

調用函數的方法

庫函數是系統聲明和定義的,是現成的工具。自定義函數是程序員自己聲明和定義的,是程序員補充的工具,不管是現成工具的還是補充的工具,都是工具,對使用者來說都一樣,沒有區別。

在C語言中,函數的調用非常靈活,可以獨占一行語句,也可以當成常量賦值給變量,也可以當成函數的參數。

如果函數的返回值是void,表示該函數的的任務以完成某項功能為主,一般用單行書寫,獨占一條語句。

如果函數的返回值不是void,如果單行書寫,表示不關心它的返回值,也可以當成常量用於任何表達式中。

例如:

函數調用的過程

當程序調用函數時,程序控制權會轉移給被調用的函數。被調用的函數執行函數體的代碼,當函數的返回語句被執行時,或到達函數的結束括號時,就把程序控制權交還給調用者程序。

示例(book47.c)

運行結果

函數參數的傳遞

關於函數的參數,在很多教程中有很多說法,如“形參”、“實參”、“值傳遞”、“地址傳遞”、“引用”等,這些說法把簡單的概念復雜化瞭,大傢不必理會。

函數的參數可以理解為函數的局部變量,參數傳遞就是調用者程序把變量(或常量)的值復制一份給函數的參數,簡單說來就是復制的過程。一旦完成數據的復制,調用者程序的變量和函數的參數就再也沒有瓜葛瞭,所以,在函數調用的過程中,函數的參數的值發生改變並不會影響調用者程序的變量的值。

我們在調用函數的時候,不關心函數參數的名稱,函數參數的名稱是函數自己的事情,隻在函數內部使用,與調用者無關。

示例(book48.c)

運行結果

const約束

const 是 constant 的縮寫,意思是“恒定不變的”!它是定義隻讀變量的關鍵字,或者說 const 是定義常變量的關鍵字。用 const 定義常變量的方法很簡單,就在通常定義變量時前面加 const 即可,如:

const int a = 10;

那麼用 const 修飾後和未修飾前有什麼區別呢?它們不都等於 10 嗎?

用 const 定義的變量的值是不允許改變的,即不允許給它重新賦值,即使是賦相同的值也不可以。所以說它定義的是隻讀變量。這也就意味著必須在定義的時候就給它賦初值。

在變量前加const約束,主要用於定義函數的參數,表示該參數在函數中是隻讀取,不允許改變,如果函數中試圖改變它的值,編譯的時候就會報錯。

例如:

函數max在聲明的時候,參數a和b都加瞭const約束,在函數中,a=10;和b=20;這兩代碼試圖改變a和b的值。編譯的時候如下:

編譯無法通過。

應用經驗

  1. 如果尋找函數

在我的課程中,會介紹常用的庫函數,但也有漏掉的。查資料是程序員的基本技能。

例如要查找C語言復制字符串功能的函數,在百度上輸入“C語言復制字符串”搜索就可以瞭,你想查什麼就輸入什麼。

然後,打開多幾個網頁看看,基本上就差不多瞭。

註意一個問題,網上的內容太多太雜亂,重點關註百度百科的文章。

1)測試函數的功能

要使用函數,隻需要關註它需要包含的頭文件、函數名、返回值、參數的數據類型和參數的順序,不必關心參數的名稱。

以strcpy函數為例,函數的聲明如下。

char *strcpy(char *dest, const char *src);

函數名:strcpy

返回值:返回dest,一般沒用,不理它。

第一個參數是目標字符串;第二個參數是源字符串,有const約束。

寫代碼測試一下:

char strname[50];

strcpy(strname,"西施");

printf("=%s=n",strname);

然後,看看輸出的結果是不是“=西施=”,用=號夾住輸出的內容是為瞭看清楚有沒有其它的字符。

赞(0)