C語言函式一本道來
函式的由來
程式=資料+演算法
C程式=資料+函式
-
模組化程式設計
程式導向的程式設計
- 以過程為中心的程式設計思想
- 首先將複雜的問題,分解為一個個容易的問題
- 分解過後的問題可以按照步驟一步步完成
- 函式是C語言程式導向的一種體現
- 解決問題的每個步驟可以用函式來實現
宣告&&定義
- 宣告 就是預先告訴編譯器實體的存在
- 定義 就是明確指示編譯器實體的意義
#include <stdio.h>
extern int g_var;//全域性的
void f(int i, int j);//函式宣告
int main()
{
//extern int g_var;//區域性變數宣告
int g(int x);//函式宣告
g_var = 10;
f(1, 2);
printf("%d\n", g(3));
return 0;
}
void f(int i, int j)//函式定義
{
printf("i + j = %d\n", i + j);
}
int g(int x)//函式定義
{
return 2 * x + g_var;
}
檔案二
int g_var = 0;
函式的引數
- 函式的引數在本質上與區域性變數相同,都是在棧上面分配空間
- 函式引數的初始值是函式呼叫時的實參值
#include <stdio.h>
int f(int i, int j)
{
printf("%d, %d\n", i, j);
}
int main()
{
int k = 1;
f(k, k++);
printf("%d\n", k);
return 0;
}
這裡的輸出是2,1,2
解釋
- 函式的引數的求值順序是依賴於編譯器的實現!
- 在程式到達順序點的時候,之前所做的一切操作必須反映到後續訪問中.
也就是說在這個例子中,在gcc
編譯器下面,先傳第二個引數到函式,然後,再進行++
運算,在進行第一個引數傳遞
.
可變引數列表
可變引數的含義
- C語言中可以定義引數可變的函式
- 引數可變的函式實現依賴於stdarg.h標頭檔案
- va_list變數va_start(),va_end和va_arg配合使用能夠訪問引數值
在C語言中是沒有過載,但是可以使用可變引數列表
#include <stdio.h>
#include <stdarg.h>
float average(int n, ...)
{
va_list args;
int i = 0;
float sum = 0;
va_start(args, n);
for(i=0; i<n; i++)
{
sum += va_arg(args, int);
}
va_end(args);
return sum / n;
}
int main()
{
printf("%f\n", average(5, 1, 2, 3, 4, 5));
printf("%f\n", average(4, 1, 2, 3, 4));
return 0;
}
可變引數的限制
- 可變引數必須從頭到尾按照順序逐個訪問
- 引數列表至少一個確定命名的引數
- 可變引數巨集是沒有辦法判斷實際存在的引數的數量
- 可變引數巨集無法判斷引數的實際型別
小結
- 可變引數是C語言提供的一種函式設計的技巧
- 可變引數提供了一種更方便的函式呼叫方式
- 可變引數必須順序的訪問
- 無法直接訪問可變引數列表中間的引數值
函式呼叫行為
活動記錄
- 活動記錄是函式呼叫時用於記錄一系列相關資訊的記錄
- 臨時變數域:用來存放臨時變數的值,如k++的中間結果
- 區域性變數域:用來存放函式本次執行中的區域性變數
- 機器狀態域:用來儲存呼叫函式之前有關機器狀態的資訊,包括各種暫存器的當前值和返回地址等。(棧頂指標等)
- 實參域:用來存放函式實參資訊
- 返回值域:為呼叫者函式存放返回值
函式引數計算的次序是依賴編譯器實現的,引數的入棧次序如何確定?
呼叫約定(在呼叫動態連線庫的時候可以用)
- 當函式被呼叫時,引數會傳遞給被呼叫的函式,函式呼叫約定就是描述是如何傳遞到棧空間的,以及棧空間由誰維護
- 引數的傳遞順序
- 從右到左依次入棧: __stdcall,__cdecl,__thiscall
- 從左到右依次入棧:__pascal,__fastall
- 呼叫堆疊清理
- 呼叫者清除棧
- 被呼叫函式返回後清除棧
小結
- 函式呼叫時C語言的核心機制
- 活動記錄儲存了函式呼叫以及返回所需要的一切資訊
- 呼叫約定是呼叫者和開發者之間的呼叫協議,常用於不同的開發者編寫的庫函式呼叫
函式的設計技巧
- 不要再函式中使用全域性變數,儘量讓函式從意義上是一個獨立功能模組
- 引數名要能夠體現引數意義
- 如果說傳遞的引數為指標,且僅僅作輸入引數用,則應在型別前加const,以防止該指標在函式體內被惡意修改
- 不要省略返回值的型別,如果函式沒有返回值,那麼應當宣告為void
- 在函式體的“入口處”,對引數的有效性進行檢查,對指標的檢查尤為重要
- 語句不可返回指向“棧記憶體”的“指標”,因為該記憶體會在函式結束後銷燬
- 函式體的規模要小
- 相同的輸入應當產生相同的輸出,儘量避免函式帶有“記憶”功能少用static
- 避免函式有太多的引數,引數個數應當控制在4個以內
- 有時候函式不需要返回值,但是增加靈活性,可以附加返回值
- 函式名與返回值在語義上不能衝突
相關文章
- C語言函式手冊:c語言庫函式大全|C語言標準函式庫|c語言常用函式查詢C語言函式
- C語言 execve()函式C語言函式
- C語言常用函式C語言函式
- C語言的函式C語言函式
- C語言 itoa函式及atoi函式C語言函式
- C語言函式呼叫棧C語言函式
- 詳解C語言函式C語言函式
- tmpnam() - C語言庫函式C語言函式
- tmpfile() - C語言庫函式C語言函式
- C語言時間函式C語言函式
- c語言函式庫(轉)C語言函式
- C語言 函式指標C語言函式指標
- 08. C語言函式C語言函式
- C語言基礎函式C語言函式
- C語言庫函式及示例C語言函式
- C語言函式sscanf()的用法C語言函式
- C語言解讀assert函式C語言函式
- C語言qsort函式的使用C語言函式
- C#語言函式遞迴C#函式遞迴
- C語言 sizeof函式詳解C語言函式
- C語言標準函式庫C語言函式
- c#語言-高階函式C#函式
- [ASM C/C++] C語言的main 函式ASMC++C語言AI函式
- C語言函式指標與回撥用函式C語言函式指標
- C語言printf()函式:格式化輸出函式C語言函式
- C 語言回撥函式詳解函式
- c語言函式指標的定義C語言函式指標
- C語言巨集和函式淺析C語言函式
- C語言有關函式淺析C語言函式
- c語言學習筆記===函式C語言筆記函式
- C語言函式指標基礎C語言函式指標
- C語言Math函式庫簡介C語言函式
- c語言字串處理函式大全C語言字串函式
- c語言快速排序(庫函式使用)C語言排序函式
- 使用函式式語言來建立領域模型函式模型
- python高階函式和C語言函式指標Python函式C語言指標
- C語言getgroups()函式:獲取組程式碼函式C語言函式
- C語言setgroups()函式:設定組程式碼函式C語言函式