08-C語言-函數(shù)

一、概述

C 程序是由函數(shù)組成的,我們寫的代碼都是由主函數(shù) main()開始執(zhí)行的。函數(shù)是 C 程序的基本模塊,是用于完成特定任務的程序代碼單元。

1.1 函數(shù)分類

從函數(shù)定義的角度看,函數(shù)可分為系統(tǒng)函數(shù)和用戶定義函數(shù)兩種:

  • 系統(tǒng)函數(shù),即庫函數(shù):這是由編譯系統(tǒng)提供的,用戶不必自己定義這些函數(shù),可以直接使用它們,如我們常用的打印函數(shù)printf()。
  • 用戶定義函數(shù):用以解決用戶的專門需要。

1.2 函數(shù)作用

  • 函數(shù)的使用可以省去重復代碼的編寫,降低代碼重復率
  • 函數(shù)可以讓程序更加模塊化,從而有利于程序的閱讀,修改和完善

二、函數(shù)的定義

函數(shù)定義的一般形式:

返回數(shù)據(jù)的數(shù)據(jù)類型 函數(shù)名(形式參數(shù)列表)
{
    數(shù)據(jù)定義部分;
    執(zhí)行語句部分;
}

函數(shù)說明

三、函數(shù)相關說明

  1. 函數(shù)名:理論上是可以隨意起名字,最好起的名字見名知意,應該讓用戶看到這個函數(shù)名字就知道這個函數(shù)的功能。注意,函數(shù)名的后面有個圓換號(),代表這個為函數(shù),不是普通的變量名。
  2. 形參列表: 在定義函數(shù)時指定的形參,在未出現(xiàn)函數(shù)調用時,它們并不占內存中的存儲單元,因此稱它們是形式參數(shù)或虛擬參數(shù),簡稱形參,表示它們并不是實際存在的數(shù)據(jù),所以,形參里的變量不能賦值
  • 在定義函數(shù)時指定的形參,必須是,類型+變量的形式;
  • 在定義函數(shù)時指定的形參,可有可無,根據(jù)函數(shù)的需要來設計,如果沒有形參,圓括號內容為空,或寫一個void關鍵字
  1. 函數(shù)體: 花括號{ }里的內容即為函數(shù)體的內容,這里為函數(shù)功能實現(xiàn)的過程,這和以前的寫代碼沒太大區(qū)別,以前我們把代碼寫在main()函數(shù)里,現(xiàn)在只是把這些寫到別的函數(shù)里。
  2. 返回值: 函數(shù)的返回值是通過函數(shù)中的return語句獲得的,return后面的值也可以是一個表達式。
  • 盡量保證return語句中表達式的值和函數(shù)返回類型是同一類型。
  • 如果函數(shù)返回的類型和return語句中表達式的值不一致,則以函數(shù)返回類型為準,即函數(shù)返回類型決定返回值的類型。對數(shù)值型數(shù)據(jù),可以自動進行類型轉換。
    • 如果函數(shù)返回的類型和return語句中表達式的值不一致,而它又無法自動進行類型轉換,程序則會報錯。
  • return語句的另一個作用為中斷return所在的執(zhí)行函數(shù),類似于break中斷循環(huán)、switch語句一樣。
  • 如果函數(shù)帶返回值,return后面必須跟著一個值,如果函數(shù)沒有返回值,函數(shù)名字的前面必須寫一個void關鍵字,這時候,我們寫代碼時也可以通過return中斷函數(shù)(也可以不用)。

四、函數(shù)的調用

定義函數(shù)后,我們需要調用此函數(shù)才能執(zhí)行到這個函數(shù)里的代碼段。這和main()函數(shù)不一樣,main()為編譯器設定好自動調用的主函數(shù),無需人為調用,我們都是在main()函數(shù)里調用別的函數(shù),一個 C 程序里有且只有一個main()函數(shù)。

4.1 函數(shù)執(zhí)行流程

#include <stdio.h>

int main() {
    void print();  // 函數(shù)聲明
    char *s = "hello world";  // 實參
    print(s);  // 調用函數(shù);s為形參
    return 0;
}

void print(char *s)  // 函數(shù)定義
{
    printf("%s\n", s);  // 函數(shù)執(zhí)行體
}
  1. 首先執(zhí)行main()函數(shù)
  2. 執(zhí)行print()函數(shù)

4.2 函數(shù)的形參和實參

  1. 形參出現(xiàn)在函數(shù)定義中,在整個函數(shù)體內都可以使用,離開該函數(shù)則不能使用。
  2. 實參出現(xiàn)在主調函數(shù)中,進入被調函數(shù)后,實參也不能使用。
  3. 實參變量對形參變量的數(shù)據(jù)傳遞是“值傳遞”,即單向傳遞,只由實參傳給形參,而不能由形參傳回來給實參。
  4. 在調用函數(shù)時,編譯系統(tǒng)臨時給形參分配存儲單元。調用結束后,形參單元被釋放。
  5. 實參單元與形參單元是不同的單元。調用結束后,形參單元被釋放,函數(shù)調用結束返回主調函數(shù)后則不能再使用該形參變量。實參單元仍保留并維持原值。因此,在執(zhí)行一個被調用函數(shù)時,形參的值如果發(fā)生改變,并不會改變主調函數(shù)中實參的值。

4.3 函數(shù)的無參數(shù)調用

如果是調用無參函數(shù),則不能加上“實參”,但括號不能省略。

// 函數(shù)的定義
void test()
{
}

int main()
{
    // 函數(shù)的調用
    test(); // right, 圓括號()不能省略
    test(250); // error, 函數(shù)定義時沒有參數(shù)

return 0;
}

4.4 有參函數(shù)調用

  • 如果實參表列包含多個實參,則各參數(shù)間用逗號隔開。
// 函數(shù)的定義
void test(int a, int b)
{
}

int main()
{
    int p = 10, q = 20;
    test(p, q); // 函數(shù)的調用

    return 0;
}
  • 實參與形參的個數(shù)應相等,類型應匹配(相同或賦值兼容)。實參與形參按順序對應,一對一地傳遞數(shù)據(jù)。


  • 實參可以是常量、變量或表達式,無論實參是何種類型的量,在進行函數(shù)調用時,它們都必須具有確定的值,以便把這些值傳送給形參。所以,這里的變量是在圓括號( )外面定義好、賦好值的變量。
// 函數(shù)的定義
void test(int a, int b)
{
}

int main()
{
    // 函數(shù)的調用
    int p = 10, q = 20;
    test(p, q); // right
    test(11, 30 - 10); // right

    test(int a, int b); // error, 不應該在圓括號里定義變量

    return 0;
}

五、函數(shù)返回值

  1. 如果函數(shù)定義沒有返回值,函數(shù)調用時不能寫void關鍵字,調用函數(shù)時也不能接收函數(shù)的返回值。
// 函數(shù)的定義
void test()
{
}

int main()
{
    // 函數(shù)的調用
    test(); // right
    void test(); // error, void關鍵字只能出現(xiàn)在定義,不可能出現(xiàn)在調用的地方
    int a = test(); // error, 函數(shù)定義根本就沒有返回值

    return 0;
}
  1. 如果函數(shù)定義有返回值,這個返回值我們根據(jù)用戶需要可用可不用,但是,假如我們需要使用這個函數(shù)返回值,我們需要定義一個匹配類型的變量來接收。
// 函數(shù)的定義, 返回值為int類型
int test()
{
}

int main()
{
    // 函數(shù)的調用
    int a = test(); // right, a為int類型
    int b;
    b = test(); // right, 和上面等級

    char *p = test(); // 雖然調用成功沒有意義, p為char *, 函數(shù)返回值為int, 類型不匹配

    // error, 必須定義一個匹配類型的變量來接收返回值
    // int只是類型,沒有定義變量
    int = test();   
    
    // error, 必須定義一個匹配類型的變量來接收返回值
    // int只是類型,沒有定義變量
    int test();
    
    return 0;
}

六、函數(shù)聲明

如果使用用戶自己定義的函數(shù),而該函數(shù)與調用它的函數(shù)(即主調函數(shù))不在同一文件中,或者函數(shù)定義的位置在主調函數(shù)之后,則必須在調用此函數(shù)之前對被調用的函數(shù)作聲明。

所謂函數(shù)聲明,就是在函數(shù)尚在未定義的情況下,事先將該函數(shù)的有關信息通知編譯系統(tǒng),相當于告訴編譯器,函數(shù)在后面定義,以便使編譯能正常進行。

注意:一個函數(shù)只能被定義一次,但可以聲明多次。

#include <stdio.h>

int max(int x, int y); // 函數(shù)的聲明,分號不能省略
// int max(int, int); // 另一種方式

int main()
{
    int a = 10, b = 25, num_max = 0;
    num_max = max(a, b); // 函數(shù)的調用

    printf("num_max = %d\n", num_max);

    return 0;
}

// 函數(shù)的定義
int max(int x, int y)
{
    return x > y ? x : y;
}

函數(shù)定義和聲明的區(qū)別:

  1. 定義是指對函數(shù)功能的確立,包括指定函數(shù)名、函數(shù)類型、形參及其類型、函數(shù)體等,它是一個完整的、獨立的函數(shù)單位。
  2. 聲明的作用則是把函數(shù)的名字、函數(shù)類型以及形參的個數(shù)、類型和順序(注意,不包括函數(shù)體)通知編譯系統(tǒng),以便在對包含函數(shù)調用的語句進行編譯時,據(jù)此對其進行對照檢查(例如函數(shù)名是否正確,實參與形參的類型和個數(shù)是否一致)。

七、main函數(shù)與exit函數(shù)

在main函數(shù)中調用exit和return結果是一樣的,但在子函數(shù)中調用return只是代表子函數(shù)終止了,在子函數(shù)中調用exit,那么程序終止。

#include <stdio.h>
#include <stdlib.h>

void fun()
{
    printf("fun\n");
    //return;
    exit(0);
}

int main()
{
    fun();
    while (1);

    return 0;
}

八、多文件(分文件)編程

  • 把函數(shù)聲明放在頭文件xxx.h中,在主函數(shù)中包含相應頭文件
  • 在頭文件對應的xxx.c中實現(xiàn)xxx.h聲明的函數(shù)

防止頭文件重復包含

當一個項目比較大時,往往都是分文件,這時候有可能不小心把同一個頭文件 include 多次,或者頭文件嵌套包含。

為了避免同一個文件被include多次,C/C++中有兩種方式,一種是 #ifndef 方式,一種是 #pragma once 方式。

  1. 方法一、
#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__

// 聲明語句

#endif
  1. 方法二
#pragma once

// 聲明語句
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1、c語言的函數(shù)有以下特點: (1)才源程序由函數(shù)組成,一個主函數(shù)main()+若干其他函數(shù) C程序中的函數(shù)類似文...
    滕王閣序閱讀 1,521評論 0 6
  • #1.函數(shù)基礎1.1 局部對象1.2 函數(shù)聲明1.3 分離式編譯 #2.參數(shù)傳遞2.1 傳值參數(shù)2.2 傳引用參數(shù)...
    MrDecoder閱讀 657評論 0 1
  • 函數(shù)基本概念 C源程序是由函數(shù)組成的例如: 我們前面學習的課程當中,通過main函數(shù)+scanf函數(shù)+printf...
    極客江南閱讀 1,755評論 1 14
  • C語言函數(shù)(一) 謹記 短暫的人生中,注定有很多人陪伴著你度過,陪你一起歡呼,陪你一起傷心流淚,陪你一起走過一條又...
    長風留言閱讀 2,420評論 1 7
  • 函數(shù)的概述一個較大的程序可分為若干個程序模塊,每一個模塊用來實現(xiàn)一個特定的功能。在高級語言中用子程序實現(xiàn)模塊的功能...
    Eric_Hunter閱讀 1,111評論 0 0

友情鏈接更多精彩內容