函數空間

一、函數的真面目android

    程序 = 數據 + 算法   ==》C程序 = 數據 + 函數算法

    模塊化程序設計:編程

        QQ截圖20180909190948.jpg

    C語言中的模塊化:ide

        QQ截圖20180909191338.jpg

    面向過程的程序設計模塊化

面向過程是一種以過程爲中心的編程思想
函數

首先將複雜的問題分解爲一個個容易解決的問題this

分解事後的問題能夠按照步驟一步步完成spa

函數是面向過程在C語言中的體現設計

解決問題的每一個步驟能夠用函數來實現3d

    聲明和定義:

程序中的聲明可理解爲預先告訴編譯器實體的存在,如:變量,函數,等等

程序中的定義明確指示編譯器實體的意義

    函數參數

函數參數在本質上與局部變量相同,都是在棧上分配空間
函數參數的初始值是函數調用時的實參值
函數參數的求值順序依賴於編譯器的實現!
C語言中大多數運算符對其操做數求值的順序都是依賴於編譯器的實現的 

image.png

    程序中的順序點

程序中存在必定的順序點
順序點指的是執行過程當中修改變量值的最晚時刻

在程序達到順序點的時候,以前所作的一切操做必須反映到後續的訪問中

每一個完整表達式結束時
&&, ||, ?:, 以及逗號表達式的每一個運算對象計算以後
函數調用中對全部實際參數的求值完成以後(進入函數體以前)

    函數的缺省認定

C語言會默認沒有類型的函數參數爲int

image.png

二、可變參數分析與宏分析

    可變參數

C語言中能夠定義參數可變的函數
參數可變函數的實現依賴於stdarg.h頭文件
va_list變量與va_start, va_endva_arg配合使用可以訪問參數值

    可變參數的限制

可變參數必須從頭至尾按照順序逐個訪問
參數列表中至少要存在一個肯定的命名參數
可變參數宏沒法判斷實際存在的參數的數量
可變參數宏沒法判斷參數的實際類型
警告:
  va_arg中若是指定了錯誤的類型,那麼結果是不可預測的

    函數和宏的對比

宏是由預處理直接替換展開的,編譯器不知道宏的存在
函數是由編譯器直接編譯的實體,調用行爲由編譯器決定
屢次使用宏會致使程序代碼量增長
函數是跳轉執行的,所以代碼量不會增長
宏的效率比函數要高,由於是直接展開,無調用開銷
函數調用時會建立活動記錄,效率不如宏

    宏的優勢和缺點

宏的效率比函數稍高,可是其反作用巨大,容易出錯

image.png

函數存在實參到形參的傳遞,所以無任何反作用,可是函數須要創建活動對象,效率受影響

image.png

宏參數能夠是任何C語言實體
  宏編寫的_MIN_參數類型能夠是int, float等等
  宏的參數能夠是類型名

image.png

三、函數調用行爲

    活動記錄

活動記錄是函數調用時用於記錄一系列相關信息的記錄
  臨時變量域:用來存放臨時變量的值,如k++的中間結果
  局部變量域:用來存放函數本次執行中的局部變量
  機器狀態域:用來保存調用函數以前有關機器狀態的信息,包括各類寄存器的當前值和返回地址等;
  實參數域:   用於存放函數的實參信息
  返回值域:   爲調用者函數存放返回值

    參數入棧

既然函數參數的計算次序是依賴編譯器實現的,那麼函數參數的入棧次序是如何肯定的呢?

image.png

    調用約定

當一個函數被調用時,參數會傳遞給被調用的函數,而返回值會被返回給調用函數。函數的調用約定就是描述參數是怎麼傳遞到棧空間的,以及棧空間由誰維護。

參數傳遞順序

  從右到左依次入棧:__stdcall__cdecl__thiscall
  從左到右依次入棧:__pascal__fastcall
調用堆棧清理
  調用者清除棧。
  被調用函數返回後清除棧

四、函數遞歸與函數設計技巧

    遞歸概述

遞歸是數學領域中概念在程序設計中的應用

遞歸是一種強有力的程序設計方法

遞歸的本質爲函數內部在適當的時候調用自身


C遞歸函數有兩個主要的組成部分:
  遞歸點 以不一樣參數調用自身
  出口不在遞歸調用

    函數設計技巧

不要在函數中使用全局變量,儘可能讓函數從意義上是一個獨立的功能模塊
參數名要可以體現參數的意義
    void str_copy (char *str1, char *str2);

    void str_copy (char *str_dest, char *str_src);

若是參數是指針,且僅做輸入參數用,則應在類型前加const,以防止該指針在函數體內被意外修改

    void str_copy (char *str_dest, const char *str_src);

不要省略返回值的類型,若是函數沒有返回值,那麼應聲明爲void類型

在函數體的「入口處」,對參數的有效性進行檢查,對指針的檢查尤其重要
不可返回指向「棧內存」的「指針」,由於該內存在函數體結束時被自動銷燬

函數體的規模要小,儘可能控制在80行代碼以內
相同的輸入應當產生相同的輸出,儘可能避免函數帶有記憶功能
避免函數有太多的參數,參數個數儘可能控制在4個之內

有時候函數不須要返回值,但爲了增長靈活性,如支持鏈式表達,能夠附加返回值
    char s[64];
    int len = strlen(strcpy(s, 「android」));

函數名與返回值類型在語義上不可衝突

    char c
    c = getchar();

    if(EOF == c)
    {
      //…

    }

相關文章
相關標籤/搜索