1. 程式人生 > >C語言(六)

C語言(六)

第六章 函式

  • 6.2 函式定義的一般形式
    • 函式的定義
      • C語言中函式定義的一般形式如下:
        • 函式返回值的型別名  函式名(型別名  形式引數1,型別名  形式引數2, … )
        • {
        • 說明部分;
        • 語句部分;
        • }
    • 說明:
      • 函式名和各個形式引數都是由使用者命名的合法識別符號,與普通變數名的定義規則相同。在同一程式中,函式名必須唯一,不能出現重名的情況。形式引數名只要在同一函式中唯一即可,由於形式引數的作用域不相同,因此形式引數名可以與其他函式中的變數名同名。C語言規定,不能在一個函式內部再定義函式,也就是說函式不能巢狀定義。
      • 若在函式的首部省略了函式返回值的型別名,可以把函式首部寫成:
        • 函式名(型別名形式引數1 ,型別名 形式引數2 ,…,型別名 形式引數n)
      • 緊跟在函式名之後的圓括號中的內容是形式引數和型別說明表,在每個形參之前都要有型別名,以標識形式引數的型別。各形參的定義之間用逗號分隔。
        • 例如,求兩整數和的函式:
          • int  add(int a ,int b)
          • {
          • intt;       /* 函式體中宣告部分 */
          • t=a+b;
          • return t;
          • }
      • 若所定義的函式沒有形參,函式名後的一對圓括號依然不能省略。本例中函式體中的語句是用來完成求和的功能。在某些情況下,函式體可以是空的,例如:
        • fun()
        • {  }
        • 該函式中沒有任何語句,什麼工作也不做,沒有任何實際作用。之所以要在主調函式上這樣寫,是為了表明此處要呼叫一個函式,而現在這個函式的具體功能可能還沒有設計好,沒有起作用,等以後擴充函式功能時補充上即可。
      • 在函式體中,除形參外,用到的其他變數必須在說明部分進行定義,這些變數(包括形參)只在函式被呼叫時才被臨時分配記憶體單元,當退出函式時,這些臨時開闢的儲存單元全部被釋放掉,即在該函式體內部定義的變數都將不存在。因此,這些變數只在函式體內部起作用,與其他函式體內的變數並不相關。
  • 6.3 函式引數和函式返回值
    • 6.3.1 形式引數和實際引數
      • 定義
        • 在程式中呼叫函式時,絕大多數情況下,主調函式和被調函式之間會發生資料傳遞關係,這就要用到前面提到的有參函式。在定義函式時,函式名後面括號中的變數稱為“形式引數“(簡稱“形參“);在主調函式中,函式名後面括號中的引數(可以是一個表示式)稱為“實際引數“(簡稱“實參“)。
      • 說明:
        • (1)實參可以是常量、變數或表示式。
        • (2)在被定義的函式中必須指定形參型別。
        • (3)實參與形參的型別應相同或賦值相相容。
        • (4)C語言規定,實參變數對形參變數的資料傳遞是“值傳遞“,即單向傳遞。只能由實參傳給形參,而不能由形參返回來給實參。在記憶體中,實參單元與形參單元是不同的單元。
        • (5)在呼叫函式時,給形參分配儲存單元,並將實參對應的值傳遞給形參。呼叫結束後,形參單元被釋放,實參單元仍保留並維持原值。
        • (6)一定要注意引數之間的傳遞,實參和形參之間 傳數值,和傳地址的差別。傳數值的話,形參的變化不會改變實參的變化。傳地址的話,形參的變化就會有可能改變實參的變化。
    • 6.3.2 函式的返回值
      • 函式的返回值就是通過函式呼叫使主調函式能得到一個確定的值。函式的值通過return語句返回,return語句的形式如下:
        • return 表示式;
        • 或return(表示式);
        • 或return;
      • return 語句中的表示式的值就是所求的函式值。此表示式值的型別必須與函式首部所說明的型別一致。若型別不一致,則以函式值的型別為準,由系統自動進行轉換。
        • 例如 通過函式呼叫的方法求1到自然數n(n>1)自然數的和,有程式段如下
          • #include<stdio.h>
          • ints(int n)
          • {
          • int i,sum=0;
          • for(i=1;i<=n;i++)
          • sum+=i;
          • return sum;
          • }
          • main()
          • {
          • int n;
          • printf("input number\n");
          • scanf("%d",&n);
          • n=s(n);
          • printf("1到n的和為:%d\n",n);
          • }
  • 6.4 函式的呼叫
    • 6.4.1 函式呼叫的一般形式
      • 函式名(實參表列);
      • 函式的呼叫可以分為呼叫無參函式和呼叫有參函式兩種,如果是呼叫無參函式,則不用“實參表列“,但括號不能省略。在呼叫有參函式時,若實參列表中有多個實參,各引數間用逗號隔開。實參與形參要求型別一致。
    • 6.4.2 函式呼叫的方式
      • (1)函式語句。把函式呼叫做為一個語句,這時該函式只需要完成一定的操作而不必有返回值。
      • (2)函式表示式。當一個函數出現在一個表示式中,該表示式就被稱為函式表示式。因為要參與表示式中的計算,所以要求該函式有一個確定的返回值提供給表示式。
      • (3)函式引數。函式呼叫做為一個函式的實參。
    • 6.4.3 C語言中,呼叫函式和被呼叫函式之間的資料可通過3種方式進行傳遞。
      • (1)實參與形參之間進行資料傳遞。
      • (2)通過return語句把函式值返回到主呼叫函式中。
      • (3)通過全域性變數。
    • 6.4.3  函式的遞迴呼叫
    • 函式的遞迴呼叫一定要記得有結束的條件
    • 在呼叫一個函式的過程中又出現直接或間接地呼叫該函式本身,稱為函式的遞迴呼叫。允許函式的遞迴呼叫是C語言的特點之一。
    • 當一個問題在採用遞迴法解決時,必須符合以下3個條件:
    • (1)可以把要解決的問題轉化為一個新的問題。而這個新的問題的解決方法仍與原來的解決方法相同,只是所處理的物件有規律地遞增或遞減。
    • (2)可以應用這個轉化過程使問題得到解決。
    • (3)必須要有一個明確的結束遞迴的條件。
    • 當函式自己呼叫自己時,系統將自動把函式中當前的變數和形參暫時保留起來,在新一輪的呼叫過程中,系統將為本次呼叫的函式所用到的變數和形參,開闢新的儲存單元。因此,遞迴呼叫的層次越多,同名變數所佔的儲存單元也就越多。當本次呼叫的函式執行結束時,系統將釋放本次呼叫所佔的儲存單元。當程式執行的流程返回到上一層的呼叫點時,同時取用進入該層函式中的變數和形參所佔用的儲存單元中的資料。
  • 6.5 函式的說明
    • 6.5.1  形式
      • 概念
        • C語言中,除了主函式外,對於使用者定義的函式要遵循先定義後使用的規則。把函式的定義放在呼叫之後,應該在呼叫之前對函式進行說明(或函式原型說明)。
      • 函式說明的一般形式如下:
        • 型別名 函式名(引數型別1 ,引數型別2 ,…,引數型別n);
            • intadd(int  ,int  );
        • 型別名 函式名(引數型別1 引數名1,引數型別2 引數名2 ,…,引數型別n  引數名n);
          • 此處的引數名完全是虛設的,它們可以是任意的使用者識別符號,既不必與函式首部中的形參名一致,又可以與程式中的任意使用者識別符號同名,實際上引數名常常省略。函式說明語句中的型別名必須與函式返回值的型別一致。
      • 函式說明可以是一條獨立的語句。對函式進行說明,能使C語言的編譯程式在編譯時進行有效的型別檢查。當呼叫函式時,若實參的型別與形參的型別不能賦值相容而進行非法轉換,C編譯程式將會發現錯誤並報錯;當實參的個數與形參的個數不同時,編譯程式也將報錯。
    • 6.5.2函式說明的位置
      • 一個函式在所有函式的外部,如在被呼叫之前說明,則在說明後的所有位置上都可以對該函式進行呼叫。如在main()函式內部進行說明,則只能在main()函式內部才能識別。
      • 例如 呼叫求和函式輸出1到n的和值,程式段如下:
        • #include<stdio.h>
        • main()
        • {
        • int n;
        • int s(int n);
        • printf("input number\n");
        • scanf("%d",&n);
        • s(n);
        • printf("n=%d\n",n);
        • }
        • ints(int n)
        • {
        • int i,sum=0;
        • for(i=1;i<=n;i++)
        • sum+=i;
        • printf("1到n的和值為:%d\n",n);
        • }
    • 一定要有:函式名,函式的返回型別,函式的引數型別。不一定要有:形參的名稱。
  • 6.6 常用函式
    • 6.6.1  字串 <string.h>
      • 6.6.1.1  strlen 計算長度
      • 6.6.1.2  strcmp 比較
      • 6.6.1.3  strcpy 複製 (不安全,越界)
      • 6.6.1.4  strcat 追加 (不安全,越界)
    • 6.6.2  數學函式<math.h>
      • 6.6.2.1   向上,向下取整
        • 函式名: ceil
          • 功能:向上取整
          • 用法: double ceil(double x);
        • 函式名: floor
          • 功能:向下取整
          • 用法: double floor(double x);
      • 6.6.2.2  取絕對值
        • 函式名:abs
          • 功能:返回整型數的絕對值.
          • 用法:abs(number)
          • number 引數可以是任意有效的數值表示式。如果 number 包含 Null,則返回Null;如果是未初始化變數,則返回 0.
        • 函式名:fabs
          • 功能:求浮點數x的絕對值.
          • 用法:fabs  (double x);
      • 6.6.2.3  平方根
        • 函式名:sqrt
          • 功能:返回指定數字的平方根.
          • 用法:sqrt  (double x);
      • 6.6.2.4  求冪
        • 函式名:exp
          • 功能:返回 e 的 n 次冪.
          • 用法:exp  (double x);
        • 函式名:pow
          • 功能:返回指定數字的指定次冪.
          • 用法:pow   (double x, double y);(將返回x的y次冪)
      • 6.6.2.5  取餘
        • 函式名: fmod
          • 功  能: 計算x對y的模, 即x/y的餘數
          • 用  法:double fmod(double x, double y);
      • 6.6.2.6  對數
        • 函式名:log
          • 功能: 自然對數函式ln(x)
          • 用法: double log(double x);
        • 函式名:log10
          • 功能:返回以 10 為底的對數.
          • 用法:log10(double x);
      • 6.6.2.7  三角函式:(所有引數必須為弧度)
        • sin
          • 函式宣告:sin  (double x);
          • 用途:用來返回給定的 X 的正弦值。
        • cos
          • 函式宣告:cos  (double x);
          • 用途:用來返回給定的 X 的餘弦值。
        • tan
          • 函式宣告:tan   (double x);
          • 用途:用來返回給定的 X 的正切值。
      • 6.6.2.8  反三角函式
        • acos
          • 函式申明:acos  (double x);
          • 用途:用來返回給定的 X 的反餘弦函式。
        • asin
          • 函式申明:asin  (double x);
          • 用途:用來返回給定的 X 的反正弦函式。
        • atan
          • 函式申明:atan  (double x);
          • 用途:用來返回給定的 X 的反正切函式。
        • atan2
          • 函式宣告:atan2 (double y, double x);
          • 用途:返回給定的 X 及 Y 座標值的反正切值
      • 6.6.2.9  雙曲函式
        • 函式名:cosh
          • 功能:返回指定角度的雙曲餘弦值.
          • 用法:Double Cosh(double x(以弧度計量的角度)) ;
        • 函式名:sinh
          • 功能:返回指定角度的雙曲正弦值。
          • 用法:sinh (double x);(其中引數x必須為弧度制)
        • 函式名:tanh
          • 功能:回指定角度的雙曲正切值.
          • 用法:tanh  (double x);
      • 6.6.2.10  實型數分整數和小數
        • 函式名:modf
          • 功  能: 把數分為整數部分和小數部分
          • 用  法: double modf(doublevalue, double *iptr);
          • eg
            • 1.  #include<math.h>
            • 2.
            • 3.  #include<stdio.h>
            • 4.
            • 5.  int main(void)
            • 6.
            • 7.  {
            • 8.
            • 9.  double fraction,integer;
            • 10.
            • 11. double number =100000.567;
            • 12.
            • 13. fraction =modf(number, &integer);
            • 14.
            • 15. printf("Thewhole and fractional parts of %lf are %lf and %lf\n",
            • 16.
            • 17. number, integer,fraction);
            • 18.
            • 19. return 0;
            • 20.
            • 21. }
            • The whole andfractional parts of 100000.567000 are 100000.000000 and 0.567000
      • 6.6.2.11  隨機數
        • 在程式設計的時候需要電腦來獲取一些隨機的反應,這個時候我們可以使用隨機數,比較常見的是 rand() 函式,它可以隨機的產生 0 ~rand_max 的隨機數。rand_max 是一個很大的數字,具體關係到IDE和資料型別,我們一般的需要不可能超出它的範圍
        • C語言中還有一個 random() 函式可以獲取隨機數,但是 random() 函式不是ANSI C標準,不能在VC等編譯器通過,所以比較少用。
        • eg
          • int a=rand()%10; //產生0~9的隨機數,注意10會被整除
          • int a=rand()%51+13; //產生13~63的隨機數
          • 產生 13~63 範圍內隨機數的完整程式碼:
            • 1.      #include <stdio.h>
            • 2.      #include <stdlib.h>
            • 3.      #include <time.h>
            • 4.      int main(){
            • 5.      int a;
            • 6.      srand((unsigned)time(NULL));
            • 7.      a=rand()%51+13;
            • 8.      printf("%d\n",a);
            • 9.      return 0;
            • 10.  }
          • 下面是一個例項:
            • 1.      #include <stdio.h>
            • 2.      #include <stdlib.h>
            • 3.      int main(){
            • 4.      int a=rand();
            • 5.      printf("%d\n",a);
            • 6.      return 0;
            • 7.      }
            • 編譯後再執行幾次,你會發現產生的隨機數是相同的。實際上,rand() 函式產生的隨機數是偽隨機數,是根據一個數按照某個公式推算出來的,這個數我們稱之為“種子”,但是這個種子在系統啟動之後就是一個定值,我們需要用 srand() 來進行播種,即在int a前加一句:
              • 1.      srand((unsigned)time(NULL)); //這裡利用時間進行播種,需要time.h
      • sqrt( ) fabs( )  pow( )  sin( )
    • 6.6.3 malloc
      • malloc的返回型別是 void *
        • int  *p;
        • p = (int *)malloc(2);
        • p = (int *)malloc(sizeof(int));以上兩個等價