115.C語言_函數
第六章 函數node
- 6.1 函數概述
- 定義
- 函數:是具備必定功能的一個程序塊;是C語言的基本組成單位。
- 在前面各章的例子及讀者本身編寫的C語言程序中都用到了以「main「開頭的主函數,而且在程序中頻繁地調用了C語言提供的用於輸入輸出的庫函數( scanf( )和printf( )函數)。
- 函數是C源程序的基本模塊,經過對函數模塊的調用實現特定的功能。
- 一個C程序可由一個主函數和若干個其餘函數構成,而且只能有一個主函數。由主函數來調用其餘函數,其餘子函數之間也能夠互相調用。
- C程序的執行老是從main()函數開始。調用其餘函數完畢後,程序流程回到main( )函數,繼續執行主函數中的其餘語句,直到main( )函數結束,則整個程序的運行結束。
- main( )函數是由系統定義的。全部的函數都是平行的,即在函數定義時它們是互相獨立的,函數之間並不存在從屬關係。也就是說,函數不能嵌套定義(這是與PASCAL不一樣的),函數之間能夠互相調用,但不容許調用main( )函數。
- 分類
- 從用戶的使用的角度看,函數有兩種:
- (1) 標準函數,即庫函數。這些函數由系統提供,能夠直接使用。
- (2) 自定義的函數。用以解決用戶須要時設計定義的函數。
- 從函數的形式看,函數分爲兩類:
- 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)必需要有一個明確的結束遞歸的條件。
- 當函數本身調用本身時,系統將自動把函數中當前的變量和形參暫時保留起來,在新一輪的調用過程當中,系統將爲本次調用的函數所用到的變量和形參,開闢新的存儲單元。所以,遞歸調用的層次越多,同名變量所佔的存儲單元也就越多。當本次調用的函數運行結束時,系統將釋放本次調用所佔的存儲單元。當程序執行的流程返回到上一層的調用點時,同時取用進入該層函數中的變量和形參所佔用的存儲單元中的數據。
- 例如 求n!的值,有程序段以下:
- #include<stdio.h>
- longff(int n)
- {
- long f;
- if(n<0)
- printf("n<0,input error");
- else if(n==0||n==1) f=1;
- else f=ff(n-1)*n;
- return(f);
- }
- main()
- {
- int n;
- long y;
- printf("請輸入整數值:\n");
- scanf("%d",&n);
- y=ff(n);
- printf("%d!=%ld",n,y);
- }
- 6.5 函數的說明
- 6.5.1 形式
- 概念
- C語言中,除了主函數外,對於用戶定義的函數要遵循先定義後使用的規則。把函數的定義放在調用以後,應該在調用以前對函數進行說明(或函數原型說明)。
- 函數說明的通常形式以下:
- 類型名 函數名(參數類型1 ,參數類型2 ,…,參數類型n);
- 或
- 類型名 函數名(參數類型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));以上兩個等價
歡迎關注本站公眾號,獲取更多信息