C語言完整函數教程_第1頁
C語言完整函數教程_第2頁
C語言完整函數教程_第3頁
C語言完整函數教程_第4頁
C語言完整函數教程_第5頁
已閱讀5頁,還剩123頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、 1第五章第五章 函數函數 25.1 子程序設計子程序設計5.2 函數函數5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 3 編寫程序,求所有四位可逆素數編寫程序,求所有四位可逆素數 ,所謂可逆素所謂可逆素數是這么一種素數,它的逆數也是素數。數是這么一種素數,它的逆數也是素數。 包含的主要功能:包含的主要功能: 判斷一個數是否素數。判斷一個數是否素數。 求一個整數的逆數。如求一個整數的逆數。如1234的逆數是的逆數是4321。 5.1 子程序設計子程序設計 45.1 子程序

2、設計子程序設計求可逆素數求可逆素數 本程序中判斷素數的代碼本程序中判斷素數的代碼會出現兩次;會出現兩次; 判斷素數、求整數逆數這判斷素數、求整數逆數這兩個功能是獨立的功能,兩個功能是獨立的功能,且在多個程序中都有可能且在多個程序中都有可能用到:用到: 求一個整數的逆數:該求一個整數的逆數:該功能在判斷一個整數是功能在判斷一個整數是否回文數中也被用到;否回文數中也被用到; 判斷一個數是否素數:判斷一個數是否素數:該功能在對整數進行素該功能在對整數進行素數分解中用到。數分解中用到。 55.1 子程序設計子程序設計 能否將完成上述獨立功能的代碼包裝成一個單能否將完成上述獨立功能的代碼包裝成一個單元,

3、并且可以供其他代碼來調用?元,并且可以供其他代碼來調用?-答案是可答案是可以使用以使用子程序子程序一一. 子程序的定義子程序的定義 子程序是子程序是封裝封裝并給以并給以命名命名的一段程序代碼的一段程序代碼,這,這段程序代碼完成子程序所定義的功能,可供調段程序代碼完成子程序所定義的功能,可供調用。用。 封裝封裝:調用者只需要關心代碼能完成什么功能,:調用者只需要關心代碼能完成什么功能,如何調用代碼(即子程序接口),而不需要關如何調用代碼(即子程序接口),而不需要關心代碼的內部實現。心代碼的內部實現。 6判斷素數的判斷素數的子程序子程序調用調用判斷素數的判斷素數的子程序子程序調用調用計算逆數的計算

4、逆數的子程序子程序調用調用5.1 子程序設計子程序設計子程序很重要的特點:子程序很重要的特點:調用者只需要關心子調用者只需要關心子程序接口,不必了解程序接口,不必了解子程序內部實現細節。子程序內部實現細節。isPrimreverse可以設計子程序可以設計子程序isPrim,用于判斷一個整數是否是素,用于判斷一個整數是否是素數;子程序數;子程序reverse ,用于計算一個整數的逆數;,用于計算一個整數的逆數; 75.1 子程序設計子程序設計二.子程序的控制和調用機制子程序的控制和調用機制u通過子程序名進行調通過子程序名進行調用;用;u調用時需要傳遞一些調用時需要傳遞一些供子程序計算和處理供子程

5、序計算和處理的數據(參數);的數據(參數);u子程序執行完成后需子程序執行完成后需要返回處理結果。要返回處理結果。 8判斷素數的判斷素數的子程序子程序調用調用5.1 子程序設計子程序設計flag=isPrim(num)判斷素數的判斷素數的子程序子程序調用調用flag=isPrim(reverseNum)子程序名子程序名參數參數返回值返回值 95.1 子程序設計子程序設計三三. 引入子程序的目的引入子程序的目的 1. 程序程序“復用復用”,避免在程序中使用重復代碼;,避免在程序中使用重復代碼;2. 結構化程序設計的需要:結構化程序設計的需要: 自頂向下、逐步細化,將復雜問題分解為相對自頂向下、逐

6、步細化,將復雜問題分解為相對簡單的子問題,這些子問題用子程序實現,簡單的子問題,這些子問題用子程序實現,從而提高主程序結構的清晰性和易讀性。從而提高主程序結構的清晰性和易讀性。3.使程序的調試和使程序的調試和 維護變得更加容易。維護變得更加容易。 10四四. 子程序設計原則子程序設計原則 高內聚高內聚:功能相對獨立和完整;:功能相對獨立和完整; 低耦合低耦合:與外界的關系盡量松散,:與外界的關系盡量松散, 不要太緊密,使其能方便地被重用;不要太緊密,使其能方便地被重用; 需要合理地設計子程序參數和子程序執行的局需要合理地設計子程序參數和子程序執行的局部環境部環境 來達到以上目標。來達到以上目標

7、。5.1 子程序設計子程序設計五五. 子程序在子程序在C語言中的實現機制語言中的實現機制C語言中的語言中的函數函數機制機制 115.1 子程序設計子程序設計5.2 函數函數5.2.1 5.2.1 函數函數5.2.2 5.2.2 函數的定義函數的定義5.2.5.2.3 3 函數的調用函數的調用5.2.4 5.2.4 函數原型函數原型5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 12u C語言中用函數實現子程序設計思想。較大的語言中用函數實現子程序設計思想。較大的C語語言應用

8、程序,往往是由多個函數組成的(用戶自定義言應用程序,往往是由多個函數組成的(用戶自定義函數或標準庫函數),每個函數完成明確的功能;函數或標準庫函數),每個函數完成明確的功能;u每一個函數應該只完成單一的預定好的任務,并且每一個函數應該只完成單一的預定好的任務,并且函數名能有效地反映函數完成的任務;如果不能選擇函數名能有效地反映函數完成的任務;如果不能選擇簡潔的函數名,那可能函數完成的功能太多,建議拆簡潔的函數名,那可能函數完成的功能太多,建議拆分成幾個較小的函數。分成幾個較小的函數。uC標準庫提供了豐富的函數集,能夠完成常用的數標準庫提供了豐富的函數集,能夠完成常用的數學計算、字符串操作、輸入

9、學計算、字符串操作、輸入/輸出等有用操作,程序員輸出等有用操作,程序員可以直接使用、從而減少工作量;可以直接使用、從而減少工作量;5.2.1 函數函數 135.1 子程序設計子程序設計5.2 函數函數5.2.1 函數函數5.2.2 函數的定義函數的定義5.2.3 函數的調用函數的調用5.2.4 函數原型函數原型5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 145.2.2 函數的定義函數的定義 函數設計的要求:函數設計的要求: 明確該函數的功能;明確該函數的功能; 定義該函

10、數的接口(即函數頭,包括函數名、定義該函數的接口(即函數頭,包括函數名、參數和返回值)參數和返回值) 定義該函數的功能實現部分定義該函數的功能實現部分 155.2.2 函數的定義函數的定義函數定義的格式:函數定義的格式: 返回值類型返回值類型 函數名函數名( 參數列表參數列表 ) /*接口定義部分接口定義部分*/ 聲明聲明 語句語句 /*功能實現部分功能實現部分*/函數定義函數定義:求求x的的y次方次方int power(int x,int y) int i, p=1; p=1; for (i=1;i=y;i+) p = p * x; return p; 1、函數名、函數名簡潔、能反映出函數的

11、功能。簡潔、能反映出函數的功能。如:如:square、printf等。等。3、返回值類型、返回值類型(1)指返回給函數調用者的結果的類)指返回給函數調用者的結果的類型;型;(2)如果不指明返回值類型,編譯器)如果不指明返回值類型,編譯器將假定返回值是將假定返回值是int型(最好明確指型(最好明確指定);定);(3)如果函數不返回任何值(即函數功)如果函數不返回任何值(即函數功能實現部分無能實現部分無return語句),則返回值類語句),則返回值類型定義成型定義成void。若返回值類型不是。若返回值類型不是void,但又無但又無return語句,則函數將返回一個不語句,則函數將返回一個不確定的值

12、;確定的值;4、返回值與、返回值與return語句語句(1)return語句的一般格式:語句的一般格式: return ( 返回值表達式返回值表達式 ); 或或 return 返回值表達式返回值表達式 ;(2)return語句的功能:返回調用函語句的功能:返回調用函數,并將數,并將“返回值表達式返回值表達式”的值帶給的值帶給調用函數;調用函數;(3) return語句中返回值表達式的語句中返回值表達式的類型要和返回值的類型說明一致。如類型要和返回值的類型說明一致。如果不一致,則以返回值類型為準果不一致,則以返回值類型為準(進行進行類型轉換類型轉換)。2、參數列表、參數列表(1)參數列表聲明了在

13、調用函數時函數)參數列表聲明了在調用函數時函數所接收的參數,形式為:所接收的參數,形式為:數據類型數據類型 參數參數1,數據類型,數據類型 參數參數2 (2)如果函數不接收任何參數,則參數)如果函數不接收任何參數,則參數列表定義為列表定義為void ;如;如 int print(void)(3)如果不列出參數的類型,編譯器就)如果不列出參數的類型,編譯器就假定其為假定其為int類型。但最好明確指定參數類型。但最好明確指定參數的類型,即使是的類型,即使是int型,最好也明確定義。型,最好也明確定義。 165.2.2 函數的定義函數的定義練習練習1:設計一個函數:設計一個函數IsLeapYear(

14、n),用于判斷,用于判斷n年是否是閏年。如果是,則返回年是否是閏年。如果是,則返回1;否則返回;否則返回0。 n年是否是閏年的判斷條件為:年是否是閏年的判斷條件為:a)n能被能被4整除但整除但不能被不能被100整除;或整除;或b)n能被能被400整除。整除。 【程序程序演示演示】 175.2.2 函數的定義函數的定義/*函數功能:判斷函數功能:判斷n是否是閏年是否是閏年 參數:參數: year :要判斷的年份:要判斷的年份 返回值:若是閏年,返回返回值:若是閏年,返回1,否則返回,否則返回0*/int isLeapYear(int year) if ( (year % 4 = 0 & year

15、 % 100 != 0 ) | year % 400 = 0) return 1; else return 0; 18常見的程序設計錯誤:常見的程序設計錯誤:(1)把同一種類型的參數聲明為類似于形式)把同一種類型的參數聲明為類似于形式float x,y,而不是而不是float x,float y;(2)在函數內部把函數參數再次定義成局部變在函數內部把函數參數再次定義成局部變量是一種語法錯誤;如:量是一種語法錯誤;如: int sum(int x, int y) int x, y;/錯誤!錯誤! return (x+y); 5.2.2 函數的定義函數的定義 195.2.2 函數的定義函數的定義(

16、3)不能在一個)不能在一個C函數的內部定義另一個函數;函數的內部定義另一個函數; main() int sum(int x,int y) return(x+y); 不允許!不允許! 205.2.2 函數的定義函數的定義 練習練習2:定義以下問題的函數頭:定義以下問題的函數頭 設計一函數,求一個正整數的長度;設計一函數,求一個正整數的長度; int length(int n) 設計一函數,求三個整數中的最大值;設計一函數,求三個整數中的最大值; int max(int n1, int n2, int n3) 215.2.2 函數的定義函數的定義練習練習3 3:要求設計一個函數:要求設計一個函數:

17、isPrim(x) 函數定義:函數定義:isPrim(x)=1 當當x 是素數;是素數; =0 當當x 不是素數不是素數 ; 225.2.2 函數的定義函數的定義要判斷的數通過要判斷的數通過參數傳入參數傳入判斷結果通過判斷結果通過return語句返語句返回回 23/* 函數功能:判斷一個正整數是否為素數函數功能:判斷一個正整數是否為素數.若是若是,則返回則返回1;否則返回否則返回0。 輸入參數:輸入參數:n:要判斷的整數。:要判斷的整數。 返回值:若返回值:若n是素數,則返回值為是素數,則返回值為1;否則返回值為否則返回值為0。*/int isPrim(int n) int i; /*不斷判斷

18、不斷判斷n能否被能否被i整除。整除。i的取值范圍是的取值范圍是2sqrt(n)*/int isPrim; /*isPrim=1:表示表示n是質數;是質數;isPrim=0:表示:表示n不是質數不是質數*/i = 2; isPrim = 1; /*初始設定初始設定n是素數。在判斷中一旦發現不是素數,則是素數。在判斷中一旦發現不是素數,則isPrim被修改成被修改成0。*/while (i = sqrt(n) & isPrim = 1) if (n % i = 0) isPrim = 0; else i+; ; return isPrim; /*返回返回*/ 245.1 子程序設計子程序設計5.2

19、 函數函數5.2.1 函數函數5.2.2 函數的定義函數的定義5.2.3 函數的調用函數的調用5.2.4 函數原型函數原型5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 255.2.3 函數的調用函數的調用 函數是一段封裝的代碼,能完成預定好的、獨函數是一段封裝的代碼,能完成預定好的、獨立的任務,能被其他函數所調用。那么,如何立的任務,能被其他函數所調用。那么,如何調用一個函數?調用一個函數? 函數的調用和執行的實質是控制轉移,調用函函數的調用和執行的實質是控制轉移,調用函

20、數時,將控制轉到被調用的函數,被調函數執數時,將控制轉到被調用的函數,被調函數執行結束時,則將控制轉回主調函數,繼續執行行結束時,則將控制轉回主調函數,繼續執行后續的操作后續的操作 。子函數子函數1子函數子函數2主函數主函數 26int square(int); /*函數原型函數原型*/main() int x; for (x = 1; x = 10; x+) printf(“%4d”,square(2 * x); int square(int y) /*函數定義函數定義*/ return (y * y);實參實參形參形參函數調用過程:函數調用過程:給被調用函數分配存儲空間;給被調用函數分配存

21、儲空間;計算實際參數表達式的值;計算實際參數表達式的值;把實際參數的值按賦值轉換規則把實際參數的值按賦值轉換規則轉換成形式參數的類型。轉換成形式參數的類型。把轉換后的實際參數(實參)的把轉換后的實際參數(實參)的值送入形式參數(形參)中。值送入形式參數(形參)中。運行調用函數中的語句;運行調用函數中的語句;計算返回值表達式的值,并轉換計算返回值表達式的值,并轉換成函數的結果類型;成函數的結果類型;釋放被調用函數占用的存儲空間;釋放被調用函數占用的存儲空間;1.帶著轉換后的值返回調用函數。帶著轉換后的值返回調用函數。函數調用函數調用函數原型的作用:是對被調函數原型的作用:是對被調用函數的用函數的

22、接口聲明,接口聲明,它它告訴編譯器函數返回的告訴編譯器函數返回的數據類型、函數所要接數據類型、函數所要接收的參數個數、參數類收的參數個數、參數類型和參數順序,編譯器型和參數順序,編譯器用函數原型校驗函數調用函數原型校驗函數調用是否正確。用是否正確。函數調用:函數調用: 函數名函數名(實參實參1,實參,實參2, ) 275.2.3 函數的調用函數的調用int square(int); /*函數原型函數原型*/main() int x; for (x = 1; x = 10; x+) printf(“%4d”,square(2 * x); int square(int y) /*函數定義函數定義*

23、/ return(y * y);2000H2002H2005H2007H2006H2003H2001Hx存儲空間存儲空間y12 4函數調用函數調用 285.2.3 函數的調用函數的調用#includemain() int i;for(i = 1000;i = 9999;i+) if (isPrim(i) = 1) printf(%dt, i); return 0; int isPrim(int n) /略略 輸出輸出4位正整數中的素數位正整數中的素數等價于:等價于:for(i = 1000;i = 9999;i+) if(isPrim(i) printf(%dt,i);此種寫法更接近于人慣用的

24、此種寫法更接近于人慣用的表達方式表達方式 29在語言中,可以用以下幾種方式調用函數:在語言中,可以用以下幾種方式調用函數:對于有返回值的函數:對于有返回值的函數:(1)函數表達式函數表達式。函數作為表達式的一個操作數,出現在。函數作為表達式的一個操作數,出現在表達式中,函數返回值參與表達式的運算。表達式中,函數返回值參與表達式的運算。 如:如:i = 2*max(x, y); if (isPrim(n)(2)函數實參函數實參。函數作為另一個函數調用的實際參數。這。函數作為另一個函數調用的實際參數。這種情況是把該函數的返回值作為實參進行傳送。如:種情況是把該函數的返回值作為實參進行傳送。如: p

25、rintf(”the large number is %d”, max(x, y);對于無返回值的函數:對于無返回值的函數:(3)函數語句函數語句。C語言中的函數可以只進行某些操作而不語言中的函數可以只進行某些操作而不返回函數值,這時的函數調用可作為一條獨立的語句。返回函數值,這時的函數調用可作為一條獨立的語句。如:如:printf(”hellon”);5.2.3 函數的調用函數的調用 305.2.3 函數的調用函數的調用切記切記:實參的個數、類型和順序,應該與形參:實參的個數、類型和順序,應該與形參個數、類型和順序一致,才能正確地進行數據個數、類型和順序一致,才能正確地進行數據傳遞。傳遞。

26、實參可以是常量、變量、表達式、函數等。無實參可以是常量、變量、表達式、函數等。無論實參是何種類型的量,在進行函數調用時,論實參是何種類型的量,在進行函數調用時,它們都必須具有確定的值,以便把這些值傳送它們都必須具有確定的值,以便把這些值傳送給形參。給形參。 形參變量只有在被調用時,才分配內存單元;形參變量只有在被調用時,才分配內存單元;調用結束時,即刻釋放所分配的內存單元(有調用結束時,即刻釋放所分配的內存單元(有例外,以后會講到)。例外,以后會講到)。 315.2.3 函數的調用函數的調用 實參和形參占用不同的內存單元,即使同名也實參和形參占用不同的內存單元,即使同名也互不影響?;ゲ挥绊?。

27、實參對形參的數據傳送是單向的,即只能把實實參對形參的數據傳送是單向的,即只能把實參的值傳送給形參,而不能把形參的值反向傳參的值傳送給形參,而不能把形參的值反向傳送給實參。送給實參。 不同函數中可以使用相同名稱和類型的變量,不同函數中可以使用相同名稱和類型的變量,它們占用不同的內存單元,互不影響。它們占用不同的內存單元,互不影響。 325.2.3 函數的調用函數的調用 如何確保能夠逐層返回到上一級調用?如何確保能夠逐層返回到上一級調用? 為何不同的函數可以使用同名的參數和變量?為何不同的函數可以使用同名的參數和變量? 進一步剖析函數的調用過程。進一步剖析函數的調用過程。 33數據在內存中的存儲數

28、據在內存中的存儲系統區:用于存放系統軟件和運行系統區:用于存放系統軟件和運行需要的數據,如操作系統。只要需要的數據,如操作系統。只要機器一運行,這部分空間就必須機器一運行,這部分空間就必須保留給系統軟件使用。保留給系統軟件使用。用戶程序代碼區:存放用戶程序的用戶程序代碼區:存放用戶程序的代碼。代碼。靜態存儲區:存放程序運行期間不靜態存儲區:存放程序運行期間不釋放的數據(靜態局部變量,全釋放的數據(靜態局部變量,全局變量);局變量);棧區:存放程序運行期間會被釋放棧區:存放程序運行期間會被釋放的數據(非靜態局部變量)以及的數據(非靜態局部變量)以及活動的控制信息;活動的控制信息;堆區:用戶可以在

29、程序運行過程中堆區:用戶可以在程序運行過程中根據需要動態地進行存儲空間的根據需要動態地進行存儲空間的分配,這樣的分配在堆區進行;分配,這樣的分配在堆區進行;5.2.3 函數的調用函數的調用 用用戶戶數數據據區區int num; /全局變量全局變量void func(int n) static int m;/靜態局部變量靜態局部變量 34 一個類比:裝東西的籮筐一個類比:裝東西的籮筐籮筐:一個存放東西的容器,框底封了口。籮筐:一個存放東西的容器,框底封了口。 裝東西:東西從籮筐口入;裝東西:東西從籮筐口入; 取東西:東西從籮筐口出,框頂的東西先被取取東西:東西從籮筐口出,框頂的東西先被取出。即最

30、先放入的東西最后才能取出;最后放出。即最先放入的東西最后才能取出;最后放入的東西最先取出(先進后出)。入的東西最先取出(先進后出)。5.2.3 函數的調用棧區簡介函數的調用棧區簡介重點介紹和函數調用相關的棧區:重點介紹和函數調用相關的棧區: 35 棧區棧區 一片存放用戶數據的內存空間;一端一片存放用戶數據的內存空間;一端“封封”了口(棧底),一端了口(棧底),一端“開開”著口著口(棧頂棧頂); 保存數據保存數據:數據只能從頂部(:數據只能從頂部(棧頂棧頂)進入;)進入; 取數據取數據:棧頂的數據先被取出,:棧頂的數據先被取出,棧底棧底的數據的數據最后被取出。即數據是最后被取出。即數據是“先進后

31、出先進后出”。數據。數據的進入和退出均在棧頂進行。的進入和退出均在棧頂進行。 讀數據讀數據:只能讀?。褐荒茏x取 棧頂的數據棧頂的數據5.2.3 函數的調用棧區簡介函數的調用棧區簡介棧底棧底棧頂棧頂 365.2.3 函數的調用棧區簡介函數的調用棧區簡介設計了一個位置指示設計了一個位置指示top,用來指示當前的棧頂位置。,用來指示當前的棧頂位置。通過通過top可以訪問當前棧頂數據。數據的進入和退可以訪問當前棧頂數據。數據的進入和退出通過修改出通過修改top的值來實現。的值來實現。數據退出數據退出數據進入數據進入 37函數調用過程函數調用過程-開辟新的運行環境開辟新的運行環境int square(i

32、nt); /*函數原型函數原型*/main() int x; for (x=1; x=10; x+) printf(“%4d”,square(x); int square(int y) /*函數定義函數定義*/ return(y*y);運行環境即指函數執行時需要的數運行環境即指函數執行時需要的數據空間。需要哪些數據空間?據空間。需要哪些數據空間?函數執行時需要的數據空間函數執行時需要的數據空間 1. 生存期在本次函數執行過程中生存期在本次函數執行過程中的的數據對象數據對象,如,如形參、局部變量形參、局部變量等;等; 2.用以用以管理函數調用過程管理函數調用過程的信息。的信息。當函數當函數A調用

33、函數函數調用函數函數B時,函數時,函數A的運行被中斷,的運行被中斷,當前機器的狀態當前機器的狀態信息信息,如,如程序計數器程序計數器(返回地(返回地址)、址)、寄存器寄存器的值等都必須保存,的值等都必須保存,以便調用結束后,能準確返回到以便調用結束后,能準確返回到函數函數A并繼續正確執行。并繼續正確執行。 385.2.3 函數調用過程函數調用過程-開辟新的運行環境開辟新的運行環境 為方便,引入一個術語:為方便,引入一個術語:“函數的活動記錄函數的活動記錄”。函數的活。函數的活動記錄是一段在動記錄是一段在棧區棧區分配的連續的內存存儲區,用以存放分配的連續的內存存儲區,用以存放函數一次執行所需的數

34、據。函數一次執行所需的數據。 開辟新的運行環境即指在開辟新的運行環境即指在棧區的棧頂棧區的棧頂創建一個函數活動記創建一個函數活動記錄。釋放本函數的運行環境即指從棧頂將活動記錄釋放。錄。釋放本函數的運行環境即指從棧頂將活動記錄釋放。 被調用函數中被調用函數中的數據的數據 現場信息,用現場信息,用于調用結束能于調用結束能正確返回正確返回 395.2.3 函數調用過程函數調用過程-開辟新的運行環境開辟新的運行環境uint square(int); /*umain()uu int x;u for (x=1; x=10; x+)u printf(“%4d”,square(x); uint square(

35、int y) /*函數定義函數定義*/ return(y*y); 為簡化起見,假設為簡化起見,假設square函數的活動函數的活動記錄只包含分配給記錄只包含分配給形參形參y和返回地址的和返回地址的存儲空間存儲空間 40 uint square(int); /*umain()uu int x;u for (x=1; x=3; x+)u printf(“%4d”,square(x); uint square(int y) /*函數定義函數定義*/ return(y*y);棧底棧底棧底棧底 41函數活動記錄使用示例函數活動記錄使用示例main() A(); B(); void A() C(); 42

36、函數調用過程函數調用過程總結總結 如何確保能夠逐層返回到上一級調用?如何確保能夠逐層返回到上一級調用?函數函數A調用函數調用函數B,則在函數,則在函數B的活動記錄中記的活動記錄中記錄了錄了A的返回地址。返回前取出該地址,即能的返回地址。返回前取出該地址,即能正確返回。正確返回。 為何不同的函數可以使用同名的參數和變量?為何不同的函數可以使用同名的參數和變量? 因為不同函數的活動記錄占用不同的內存單元,因為不同函數的活動記錄占用不同的內存單元,程序運行時始終是從位于棧頂的活動記錄中取程序運行時始終是從位于棧頂的活動記錄中取形參和變量的值。形參和變量的值。 43子程序參數傳遞兩種方式:子程序參數傳

37、遞兩種方式:按值傳遞按值傳遞和和按引用傳遞按引用傳遞。按值傳遞按值傳遞:實參的值被復制并置入被調用子程序的形實參的值被復制并置入被調用子程序的形參中。此方式下不管在被調用子程序中怎樣操作并參中。此方式下不管在被調用子程序中怎樣操作并改變形參的值,在主調程序中的實參的值都是安全改變形參的值,在主調程序中的實參的值都是安全的未發生變化的。的未發生變化的。5.2.3 函數的調用函數的調用按值傳遞按值傳遞按值傳遞(將實參的按值傳遞(將實參的值傳遞給形參)值傳遞給形參)實參實參實參實參形參形參形參形參 445.2.3 函數的調用函數的調用按引用傳遞(函按引用傳遞(函數調用時實參數調用時實參雖然寫的是變雖

38、然寫的是變量量max,但實,但實際傳遞的不是際傳遞的不是max的值,而的值,而是是max的地址)的地址)主調程序主調程序(實參)(實參)子程序子程序 (形參形參)如何解決函數的多返回值問題?如何解決函數的多返回值問題?按引用傳遞按引用傳遞:此時實參必須是變量,子程序調:此時實參必須是變量,子程序調用時將用時將實參的實參的地址地址而不是實參的值置入被調子而不是實參的值置入被調子程序的形參中。被調子程序對形參的操作實際程序的形參中。被調子程序對形參的操作實際上是對主調程序中實參的操作,從而向主調程上是對主調程序中實參的操作,從而向主調程序傳回函數處理結果。序傳回函數處理結果。 455.2.3 函數

39、的調用函數的調用注意:注意:C C語言中所有的調用都是語言中所有的調用都是傳值調用傳值調用,但是可以通過其他方式來實現函數的多返回但是可以通過其他方式來實現函數的多返回值值( (即實參本身存放的就是某個變量的內存即實參本身存放的就是某個變量的內存地址,將該地址傳遞給被調用函數后,被調地址,將該地址傳遞給被調用函數后,被調用函數通過該地址來訪問變量,將函數處理用函數通過該地址來訪問變量,將函數處理結果寫入變量結果寫入變量) )。具體以后學習指針時講解具體以后學習指針時講解 465.1 子程序設計子程序設計5.2 函數函數5.2.1 函數函數5.2.2 函數的定義函數的定義5.2.3 函數的調用函

40、數的調用5.2.4 函數原型函數原型5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 47#includefloat square(float);/形參名可寫可不寫形參名可寫可不寫main() float x=2.5; printf(%.2f,square(x); system(pause);/*函數定義函數定義*/ float square(float y) return(y*y);5.2.4 函數的原型函數的原型編譯到藍色行時報錯:編譯到藍色行時報錯:conflictin

41、g types for square。錯誤原因:當自上而下對錯誤原因:當自上而下對源程序編譯時,編譯到源程序編譯時,編譯到紅色字體那一行,編譯紅色字體那一行,編譯器會默認器會默認square(x)函數函數返回值類型是返回值類型是int型,從型,從而和后面的而和后面的float沖突。沖突。解決方法:在函數調用前解決方法:在函數調用前使用函數原型對函數進使用函數原型對函數進行聲明。行聲明。在文件在文件stdio.h中已經給出了函數原型中已經給出了函數原型思考:編譯器為何不會提示思考:編譯器為何不會提示printf未定義呢?未定義呢? 48(1) C語言的原則(先聲明、后使用);語言的原則(先聲明、

42、后使用);(2)函數原型的作用:函數原型是對被調用函數)函數原型的作用:函數原型是對被調用函數的的接口聲明,接口聲明,它告訴編譯器函數返回的數據類型、它告訴編譯器函數返回的數據類型、函數所要接收的參數個數、參數類型和參數順序,函數所要接收的參數個數、參數類型和參數順序,編譯器用函數原型校驗函數調用是否正確。編譯器用函數原型校驗函數調用是否正確。(3)函數原型一般格式:)函數原型一般格式: 返回值類型返回值類型 函數名函數名(數據類型數據類型 參數名參數名1, 數據數據類型類型 參數名參數名2);注意注意:參數名可寫可不寫。:參數名可寫可不寫。 5.2.4 函數的原型函數的原型float squ

43、are(float ); /*函數原型函數原型*/ 49(4)函數原型可以放置在任何函數之外,出現在函數原型可以放置在任何函數之外,出現在該函數原型之后的所有函數都可以調用對應的函該函數原型之后的所有函數都可以調用對應的函數;也可以放在某個函數中,此時只有該函數能數;也可以放在某個函數中,此時只有該函數能夠調用它。從程序設計風格考慮,最好是將函數夠調用它。從程序設計風格考慮,最好是將函數原型集中在一起,放在主函數之前。原型集中在一起,放在主函數之前。(5)當被調用函數的函數定義出現在該函數調用)當被調用函數的函數定義出現在該函數調用之前時,可以省略函數原型。因為在調用之前,之前時,可以省略函數

44、原型。因為在調用之前,編譯系統已經知道了被調用函數的函數類型、參編譯系統已經知道了被調用函數的函數類型、參數個數、類型和順序。數個數、類型和順序。5.2.4 函數的原型函數的原型/*square函數在函數在main和和fun中中均可被調用均可被調用*/float square(float); main() int fun() float square(float y) return(y*y);main()/*square函數只能在函數只能在main中被調用中被調用*/ float square(float); int fun()float square(float y) return(y*y)

45、;/*函數定義函數定義*/ float square(float y) return(y*y);main() 50(6)函數原型、函數定義、函數調用要保持一致。)函數原型、函數定義、函數調用要保持一致。和函數原型不匹配的函數調用會導致語法錯誤;函和函數原型不匹配的函數調用會導致語法錯誤;函數原型和函數定義不一致,也會產生錯誤。數原型和函數定義不一致,也會產生錯誤。(7)如果程序中沒有包含函數原型,則編譯器就會)如果程序中沒有包含函數原型,則編譯器就會用第一次出現的該函數(函數定義或函數調用)來用第一次出現的該函數(函數定義或函數調用)來構造函數原型。默認情況下,編譯器假定函數的返構造函數原型。

46、默認情況下,編譯器假定函數的返回類型為回類型為int類型,而對參數不作任何假定。類型,而對參數不作任何假定。5.2.4 函數的原型函數的原型#includefloat square(float y);/函數原型函數原型main() float x=2.5; printf(“%.2f”,square(x); /函數調用函數調用 system(pause);/*函數定義函數定義*/ float square(float y) return(y*y); 51(8)函數原型可以用來強制轉換參數類型。)函數原型可以用來強制轉換參數類型。在函數調用之前,和函數原型中的參數類型不完全一致在函數調用之前,和函

47、數原型中的參數類型不完全一致的實參值會被轉換為合適的類型。的實參值會被轉換為合適的類型。如:如: sqrt 的參數類型是的參數類型是double,進行如下調用進行如下調用printf(“%.3fn”,sqrt(4)時,在將時,在將4傳遞給傳遞給sqrt之前先轉換之前先轉換為為double類型的值類型的值4.0;參數類型的轉換有可能是低類型向高類型轉換,也可能參數類型的轉換有可能是低類型向高類型轉換,也可能是高類型向低類型轉換。高類型向低類型轉換可能會導是高類型向低類型轉換。高類型向低類型轉換可能會導致不正確的結果(如致不正確的結果(如long類型向類型向short類型的轉換)。類型的轉換)。5

48、.2.4 函數的原型函數的原型 525.1 子程序設計子程序設計5.2 函數函數5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 535.3 頭文件頭文件 對于一些通用的函數(如輸入輸出函數、數學對于一些通用的函數(如輸入輸出函數、數學函數等),可能在不同的程序中都會用到。函數等),可能在不同的程序中都會用到。 為了使用這些函數,需要在程序中說明其函數為了使用這些函數,需要在程序中說明其函數原型。原型。n一種方式是在程序中逐個寫出函數原型;一種方式是在程序中逐個寫出函數原型;

49、double sqrt(double x) ;double fabs(double x) ;n另一種方式是將這些函數原型集中在一起,另一種方式是將這些函數原型集中在一起,形成形成.h頭文件頭文件,然后在程序中直接包含這然后在程序中直接包含這些頭文件。些頭文件。#include 54每一個標準庫都有一個相應的頭文件每一個標準庫都有一個相應的頭文件,文件擴展名為文件擴展名為.h(如如stdio.h,示例示例)。該頭文件包含了該庫中所有函數該頭文件包含了該庫中所有函數的原型以及這些函數所需的所有常量和數據類型的定的原型以及這些函數所需的所有常量和數據類型的定義。義。程序員可以根據需要自己建立頭文件,

50、使用程序員可以根據需要自己建立頭文件,使用include命命令可以把程序員定義的頭文件包含到程序中,如:令可以把程序員定義的頭文件包含到程序中,如:#include “square.h”注意注意:#include包含標準庫的頭文件包含標準庫的頭文件#include “square.h” 包含程序員自定義的頭文件包含程序員自定義的頭文件5.3 頭文件頭文件 555.1 子程序設計子程序設計5.2 函數函數5.3 頭文件頭文件5.4 函數應用舉例函數應用舉例5.5 變量作用域變量作用域5.6 變量的存儲類別變量的存儲類別5.7 內部函數和外部函數內部函數和外部函數提綱提綱 56例例1 1、驗證歌德

51、巴赫猜想、驗證歌德巴赫猜想 任一充分大的偶數,可以用兩個素數之和表示,任一充分大的偶數,可以用兩個素數之和表示,例如:例如:4 = 2 + 24 = 2 + 26 = 3 + 36 = 3 + 3 10 = 3 + 710 = 3 + 7 10 = 5 + 510 = 5 + 5.9 8 = 1 9 + 7 99 8 = 1 9 + 7 9輸入一個偶數,將其表示為兩素數之和,并輸出輸入一個偶數,將其表示為兩素數之和,并輸出5.4 函數應用舉例函數應用舉例 57例例1 1、驗證歌德巴赫猜想、驗證歌德巴赫猜想 思路:偶數思路:偶數num是要分解的數,則是要分解的數,則 num = i + (num

52、 - i) 其中其中i和和(num - i)都得是素數都得是素數 因此可以對因此可以對i可能的取值進行窮舉。可能的取值進行窮舉。 58例例1 1、驗證歌德巴赫猜想、驗證歌德巴赫猜想main()int num;/*num:要判斷的一個偶數要判斷的一個偶數*/ int num1; /*num表示為兩個素數表示為兩個素數num1和和num-num1之和之和*/ int count;/*計數輸出個數,用于換行。計數輸出個數,用于換行。*/ printf(輸入要驗證的偶數:輸入要驗證的偶數:); scanf(%d,&num);if (num%2!=0) printf(輸入的數不是偶數,程序終止輸入的數不

53、是偶數,程序終止n); 59例例1 1、驗證歌德巴赫猜想、驗證歌德巴赫猜想 else/采用窮舉法,將采用窮舉法,將num分解為兩個素數之和分解為兩個素數之和 count=0; for(num1=2;num1=num/2;num1+) if (isPrim(num1) & isPrim(num-num1) printf(%d = %d + %dt,num,num1,num-num1); count+; if(count%3=0) printf(n);/每輸出每輸出3個數換一行個數換一行 /end of if /end of for /end of else system(pause); retu

54、rn 0; 605.4 函數應用舉例函數應用舉例 例例2:設計一個函數,將十進制數轉換成二進:設計一個函數,將十進制數轉換成二進制、八進制和十六進制。然后在主函數中讀入制、八進制和十六進制。然后在主函數中讀入一個整數,調用函數,輸出轉換結果。一個整數,調用函數,輸出轉換結果。 算法思路:見算法思路:見C程序設計教程程序設計教程489490頁頁 61例例2.進制轉換進制轉換 假設將十進制數假設將十進制數57轉換為二進制轉換為二進制 從右到左寫出每列的位值,直到發現位值大于該從右到左寫出每列的位值,直到發現位值大于該十進制數的列。這樣就先得到十進制數的列。這樣就先得到 位值:位值:64 32 16

55、 8 4 2 1 然后去掉位值為然后去掉位值為64的列,得到:的列,得到: 位值:位值:32 16 8 4 2 1 然后,從左至右進行。然后,從左至右進行。57除以除以32得商為得商為1,余數,余數為為25,所以在,所以在32這列寫下這列寫下1,然后,然后25除以除以16商為商為1,余數為余數為9,所以在,所以在16這列寫下這列寫下1, 位值:位值: 32 16 8 4 2 1 符號值:符號值: 1 1 1 0 0 1 所以所以(57)10=(111001)2 62例例2.進制轉換進制轉換 假設將十進制數假設將十進制數57轉換為八進制轉換為八進制 從右到左寫出每列的位值,直到發現位值大于該十進

56、從右到左寫出每列的位值,直到發現位值大于該十進制數的列。這樣就先得到制數的列。這樣就先得到 位值:位值:64 8 1 然后去掉位值為然后去掉位值為64的列,得到:的列,得到: 位值:位值:8 1 然后,從左至右進行。然后,從左至右進行。57除以除以8得商為得商為7,余數為,余數為1,所,所以在以在8這列寫下這列寫下1,然后,然后1除以除以1商為商為1,余數為,余數為0,所以,所以在在1這列寫下這列寫下1. 位值:位值: 8 1 符號值:符號值: 7 1 所以所以(57)10=(71)8 63例例2.進制轉換進制轉換/*將將num轉換為轉換為base進制并輸出進制并輸出*/ void trans

57、fer(int num,int base) int p,k; p = 1; while (p = num) /求求p:p是是base的的x次冪,且次冪,且p大于大于num p = p * base; p = p / base; /*循環求循環求base進制數的各位進制數的各位*/ while( p != 0) k = num /p; /*計算當前要輸出的那個十進制數計算當前要輸出的那個十進制數*/ if (k = 9) printf(%d,k); else printf(%c,k 10 + A); num = num % p; p = p / base; 64例例3:擲骰子游戲:擲骰子游戲(見

58、見C程序設計教程程序設計教程119頁頁)1、rand()函數:函數:產生一個產生一個0到到RAND_MAX之間的整數,使用時之間的整數,使用時需要包含頭文件需要包含頭文件 。 RAND_MAX 是在頭文件是在頭文件中定義的符中定義的符號常量,號常量,ANSI規定其不得小于規定其不得小于32767。 用于產生用于產生16之間的隨機數:之間的隨機數: 1+rand()%65.4 函數應用舉例函數應用舉例 65每一次調用函數每一次調用函數rand()時,時,0到到RAND_MAX之之間的每一個數字被選中的機會幾乎均等(見書間的每一個數字被選中的機會幾乎均等(見書上上120頁圖頁圖5-5)rand()

59、所產生的隨機數是偽隨機數,反復調用所產生的隨機數是偽隨機數,反復調用rand()產生的一系列數似乎是隨機的,但是每產生的一系列數似乎是隨機的,但是每次執行程序所產生的序列則是重復的次執行程序所產生的序列則是重復的(重復運重復運行行120頁圖頁圖5-4的程序得到的結果是一樣的的程序得到的結果是一樣的)。5.4 函數應用舉例函數應用舉例 662、srand(unsigned)函數函數如何實現真正的隨機化:為函數如何實現真正的隨機化:為函數rand設置設置隨機隨機數種子數種子;每次執行程序時,只要隨機數種子不;每次執行程序時,只要隨機數種子不同,產生的隨機數序列也將不同(見書上同,產生的隨機數序列也

60、將不同(見書上122頁圖頁圖5-6)。)。讓機器設置隨機數種子:讓機器設置隨機數種子:srand(time(NULL):通過通過time函數使計算機讀取當函數使計算機讀取當前時間值(以秒為單位,如前時間值(以秒為單位,如1099228431 ),并),并把該值設成隨機數種子,這樣可以避免用戶自把該值設成隨機數種子,這樣可以避免用戶自己輸入隨機數種子。己輸入隨機數種子。5.4 函數應用舉例函數應用舉例 67例例4、碰運氣游戲、碰運氣游戲(見見C程序設計教程程序設計教程123頁頁)游戲規則:投擲兩個骰子,游戲規則:投擲兩個骰子,1、第一次投擲時,如果所得和為、第一次投擲時,如果所得和為7或者或者1

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論