程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言入門知識 >> C語言函數的秘密

C語言函數的秘密

編輯:C語言入門知識

C語言提供了大量的庫函數
自定義函數的一般形式:

[數據類型]函數名稱([參數])
{
    執行代碼塊;
    return(表達式);
}

注意:
[]包含的內容可以省略,數據類型說明省略,默認的是int類型函數;參數省略表示該數是無參數的函數,參數不省略表示該函數是有參函數;
2、函數名稱遵循標識符命名規范
3、自定義函數盡量放在main()函數之前,如果要放在main()函數後面的話,需要在main()函數之前先聲明自定義函數,聲明格式為:[數據類型說明]函數名稱([參數]);

#include 

int sayhello()
{
    printf("%s\n","慕課網的小伙伴,大家好");
    return 0;
}
int main()
{
    return 0;
}

函數的調用

在C語言中,函數調用的一般形式:

函數名([參數])

注意:
1、對無參數的調用的時候可以將[]包含的省略
2、[]中可以是常數,變量或其他構造類型數據及表達式,各個參數之間用逗號分開。

#include 
//自定義函數,sayhello()
int sayhello()
{
    printf("%s\n","慕課網的小伙伴們,大家好");
    return 0;
}
//主函數
int main()
{
    sayhello();
    return 0;
}

有參與無參數

在函數中不需要函數參數的稱之為無參數函數
在函數中需要參數的稱之為有參函數
有參函數的一般形式

[數據類型]函數名稱(參數列表)
{
    執行代碼塊;
    return 表達式;
}
[數據類型]函數名稱()
{
    執行代碼塊;
    return 0;
}

有參函數與無參函數的唯一的區別是:函數()中多了一個參數列表。

無參數函數
#include 

int Matrix()
{
    int i, j;
    for (i = 1; i <= 3; i++)
    {
        for (j = 1; j <= 3; j++)
        {
            printf(" * ");
        }
        printf("\n");
    }
    return 0;
}
int main()
{
    Matrix();
    return 0;
}
#include 

int Matrix(int n)
{
    int i, j;
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            printf("* ");
        }
        printf("\n");
    }
    return 0;
}
int main()
{
    Matrix(5);
    return 0;
}

對比兩個例子,不難發現有參函數更為靈活,輸出的圖形可以隨著n 的改變而隨意改變,只要在main()函數中傳遞一個參數就可以了;而在無參函數中輸出的相對就比較固定,當需要改動的時候還需要到自定義的方法內改變循環變量的值。

形參與實參

函數的參數分為形參和實參兩種。

形參是在定義函數名的時候使用的參數。目的是用來接收調用該函數時傳入的參數。

實參是在調用時傳遞該函數的參數。

(一)函數的形參和實參具有以下的特點:

形參只有在被調用時分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此形參只有在函數的內部有效。函數調用結束返回主調用函數名後則不能再使用該形參變量 實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須具有確定的值, 在參數傳遞時,實參和行參在數量上,類型上,順序上應嚴格一致,否則會發生類型不匹配的錯位
#include 

int MultiDouble(int x)//這裡的x是形參
{
    return x * 2;
}

int main()
{
    int x = 10;
    //下面的x是實參,他其實就是main()函數中定義的變量x
    printf("%d\n",MultiDouble(x));
    return 0;
}

求三角形的周長

#include 

int getGirth(int a, int b, int c)
{
    if ((a + b) <= c || (a + c) <= b || ((b + c) <= a))
    {
        printf("不構成三角形\n");
        return 0;
    }
    else
    {
        int cirf = a + b + c;
        return cirf;
    }
}
int main()
{
    int a, b, c;
    a = 3;
    b = 4;
    c = 5;
    printf("三角形的周長是:%d\n",getGirth(a,b,c));
}

函數的返回值

函數的返回值是指函數被調用之後,執行函數體中的程序段所取得的並返回給主調函數的值。
1、函數的值只能通過return語句返回主調函數。return語句的一般形式為:

return 表達式               return (表達式);

2、函數值的類型和函數定中函數的類型應保持一致。如果兩者不一致,則以函數返回類型為准,自動進行類型轉換。

int number()
{
    return 100;
}
void noResult()
{

}

注意:
void函數中可以有執行代碼塊,但是不能有返回值,令void函數中如果有return語句,該語句只能有起到結束函數運行的功能。

其格式為: return ;

沒有答案的

#include 
/* Jone算出結果應該怎麼寫函數? */
 ?  joneResult(int x, int y, int z)
{
   int sum = x+y+z;
   ?          //這裡是不是應該將sum返回呢?
}
/* Jack沒有算出結果只說了一句話是不是應該用無返回值函數? */
 ? jackResult(int x, int y, int z)
{
    printf("我算不出來\n");
}
int main()
{
    int a, b, c;
    a = 10;
    b = 20;
    c = 30;
    //Jone的返回值類型是什麼?
         jR = joneResult(a, b, c); 
    printf("Jone運算結果是:%d\n", jR);
    printf("Jack運算結果是:");
    //Jack沒有算出結果只說了句話,是不是直接調用函數就可以了?
    ?
    return 0;
}

遞歸

#include 
/* Jone算出結果應該怎麼寫函數? */
 ?  joneResult(int x, int y, int z)
{
   int sum = x+y+z;
   ?          //這裡是不是應該將sum返回呢?
}
/* Jack沒有算出結果只說了一句話是不是應該用無返回值函數? */
 ? jackResult(int x, int y, int z)
{
    printf("我算不出來\n");
}
int main()
{
    int a, b, c;
    a = 10;
    b = 20;
    c = 30;
    //Jone的返回值類型是什麼?
         jR = joneResult(a, b, c); 
    printf("Jone運算結果是:%d\n", jR);
    printf("Jack運算結果是:");
    //Jack沒有算出結果只說了句話,是不是直接調用函數就可以了?
    ?
    return 0;
}

計算n的階乘可以使用以下代碼

#include 
int factorial(int n)
{
    int result;
    if (n < 0)
    {
        printf("輸入錯誤!\n");
        return 0;
    }
    else if (n == 0 || n == 1)
    {
        result = 1;
    }
    else
    {
        result = factorial(n - 1)*n;
    }
    return result;
}

int main()
{ 
    int n = 5;
    printf("%d的階乘=%d",n,factorial(n));
    return 0;
}

遞歸就是一個函數在它的函數體內調用它自身

#include 

int getwordNumber(int n)
{
    if (n == 1)
    {
        return 1; 
    }
    else
    {
        return getwordNumber (n - 1) + n;
    }
}

int main()
{
    int num = getwordNumber(10);
    printf("小明第10天記了:%d個單詞。",num);
}

遞歸函數的特點:

每一級函數調用都有自己的變量,但是函數代碼並不會得到復制, 每次調用都會有一次返回 遞歸函數中,位於遞歸調用前的語句和各級被調用函數具有相同的執行順序, 遞歸函數中,位於遞歸調用錢的語句和各級被調用函數具有相同的執行順序; 遞歸函數中,位於遞歸調用的後的語句的執行順序和各個被調用函數的順序相反; 遞歸函數中必須有終止語句。 一句話總結遞歸:自我調用且具有完成狀態。
#include 

int getPeachNumber(int n)
{
    int num;
    if (n==10)
    {
        return 1;
    }
    else
    {
        num = (getPeachNumber(n + 1) + 1) * 2;
        printf("第%d天所剩桃子%d多個\n",n,num);
    }
    return num;
}
int main()
{
    int num = getPeachNumber(1);
    printf("猴子第一天摘了:%d個桃子。\n",num);
    return 0;
}

遞歸練習:

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

程序分析:

利用遞歸的方法,遞歸分為回推和遞推兩個階段。要想知道第5個人歲數,需知道第4人的歲數,依次類推,推到第1人(10歲),再往回推。

#include 

int getAge(int numPeople)
{
    int age;
    if (numPeople == 1)
        age = 10;
    else
        age = getAge(numPeople - 1) + 2;
    return age;
}

int main()
{
    int fifthAge = getAge(5);
    printf("第5個人的年齡是%d歲",fifthAge);
    return 0;
}

局部和全局

C語言中變量,按作用域范圍分為兩種,
局部變量全局變量
(1)局部變量也稱為內部變量,局部變量是在函數內作定義說明的。其作用域僅限於函數內
(2)全局變量也稱為外部變量,他是在函數外部定義的的變量,全局變量不屬於哪一個函數,全局變量屬於一個源程序文件,其作用是整個源程序

#include 
int x = 1;
int fn1(int x)
{
    int y, z;
    z = 2;
    y = x + z;
    printf("y=%d\n",y);
    return 0;
}

int main()
{
    fn1(2);
    int y = 10;

    printf("x+y=%d",y+x);
    return 0;
}

內部函數與外部函數

在C語言中不能被其他的源文件調用的函數稱為內部函數,內部函數由static關鍵字來定義因此又被稱為靜態函數,

stctic [數據類型]函數名([參數])

static()是對函數的作用范圍的一個限定,限定該函數只能在其所處的源文件中使用,因此在不同的文件中出現相同的函數名稱的內部函數是沒有問題。

在C語言中能被其他源文件調用的函數稱為外部函數,外部函數由extern關鍵字

extern[數據類型]函數名([參數])

C語言規定,在沒有指定函數的作用范圍時,系統會默認認為是外部函數,因此當需要定義外部函數時extern可以省略

A、C程序函數中定義的賦有初值的靜態變量,每調用一次函數,賦一次初值
B、在C程序的同一函數中,各復合語句內可以定義變量,其作用域僅限本復合語句
C、C程序函數定義的自動變量,系統不自動賦確定的初值
D、C程序函數的形式參數不可以說明為static型變量

北京市出租車打車計費規則如下:
1. 每公裡單價計費2.3元
2. 起步價13元(包含3公裡)
3. 晚上23點(含)至次日凌晨5點(不含)打車,每公裡單價計費加收20%。
4. 每次乘車加收1元錢的燃油附加稅。
小明每天上下班都要打車,公司和家的距離為12公裡,上午上班時間為9點,下午下班時間為6點。
請編寫一個小程序計算小明每天打車的總費用。

變量存儲的類別

C語言根據變量的生存周期來劃分,可以劃分為靜態存儲方式動態存儲方式

靜態存儲方式:是指在程序的運行期間分配固定的存儲空間的方式。靜態存儲區中存儲放了在整個程序執行過程中都存在的變量,如全局變量

動態存儲方式:是指在程序運行期間根據需要進行動態的分配存儲空間的方式。動態存儲區中存放的變量是根據程序運行需要而進行的需要而建立和釋放的。通常包括: 1. 函數形式參數;2. 自動變量;3. 函數調用時的現場保護、4. 和返回值地址等。

C語言中的存儲類別又分為4類:
自動(auto)、
靜態(static)、
動態(extern)
寄存器(register)

-1、 用關鍵字auto定義的變量為自動變量,auto可以省略,auto不寫則隱含定為”自動存儲類別“,屬於動態存儲方式。

int fn(int a)//定義f函數,a為參數
{
//定義b,c為自動變量
    auto  int b,c;
}
2、用static修飾的為靜態變量,如果定義在函數內部,稱之為靜態局部變量;如果定義在函數外部,稱之為靜態外部變量,
#include 

void fn()
{
    static int x =0;
    x++;
    printf("fn: x=%d\n",x);
}
int main()
{
    int i;
    for(i=0;j<10;i++)
    {
        fn();
    }
    return 0;
}

注意:
靜態局部變量屬於靜態存儲類別,在靜態存儲區內分配存儲單元,在程序整個運行期間都不釋放;
靜態局部變量在編譯時賦初值,即只賦初值一次;如果在定義局部變量時,不賦初值的話,則對靜態局部變量來說,編譯時自動賦初值0.(對數值型變量)或空字符(對字符變量)。

3、為了提高效率,C語言允許將局部變量得放在CPU中的寄存器中,這種變量叫”寄存器變量“,用關鍵字register做聲明
void fn()
{
    register int i;
}

注意:只有局部自動變量和形式參數可以作為寄存器變量;一個計算機系統中的寄存器數目有限,不能定義任意多個寄存器變量
局部靜態變量不能定義為寄存器變量。

4、用extern聲明的變量是外部變量,外部變量的意義是某函數可以調用在該函數之後定義的變量
#include 
int main()
{
    extern int x;//這裡聲明的是外部局部變量
    printf("extern x=%d\n",x);
}
int x=100;

任務:

#include 
void fn()
{
    static int x = 1;
    x *= 2;
    printf("x=%d\n",x);
}
int main()
{
    int i;
    for(i=0;i<5;i++)
    {
        fn();
    }
    extern int x;
    printf("x=%d\n",x);
    return 0;
}
int x = 100;

運行結果是x=2;x=4;x=8;x=16;x=32;x=100

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved