[源碼下載]
作者:webabcd
介紹
不可或缺 Windows Native 之 C 語言
示例
cFunction.h
#ifndef _MYHEAD_FUNCTION_ #define _MYHEAD_FUNCTION_ #ifdef __cplusplus extern "C" #endif // 函數聲明 // 像這種在 .h 中聲明的函數,如果想被外部文件調用的話,則外部文件不用再聲明即可調用 char *demo_cFunction(); long recursion(int n); void update(int ary[], int aryLength); // 也可以將上面的函數聲明寫成下面這種形式,像這種只有參數類型,沒有參數名稱的函數聲明稱之為函數原型(function prototype) // void update(int[], int); void demo_variable1(); void demo_variable2(); void demo_params(); // 加上 static 關鍵字就是內部函數,僅能在當前文件使用;在不同的文件中如果有同名的內部函數,則他們互不干擾 static void cFunction_demo1(); // 加上 extern 關鍵字就是外部函數,可被其他文件調用 extern void cFunction_demo2(); // 如果既無 static 也無 extern,則默認為 extern void cFunction_demo3(); #endif
cFunction.c
/*
* 函數
*
*
* 1、從變量的作用域(scope)角度來分,可以分為全局變量(外部變量)和局部變量
* 2、從變量的生存期角度來分,可以分為靜態存儲方式和動態存儲方式
*
*
* argument - 實參
* parameter - 形參
*/
#include "pch.h"
#include "cFunction.h"
#include "cHelper.h"
// 全局變量(亦稱外部變量),作用域(scope)是整個源程序
int global01 = 100;
// 像這種定義在 .c 中的函數(無論在 .c 文件中有無函數聲明),如果想被外部文件調用的話,則外部文件在調用之前需要先聲明
void function0()
{
;
}
char *demo_cFunction()
{
// 函數定義在之前,則不用聲明也可以調用(同一文件);函數定義在之後,則必須先聲明才可以調用
function0();
// 以下為無參數無返回值的函數聲明(declare),其同 void demo_cFunction1();
void function1(void);
// 以下為有參數有返回值的函數聲明
int function2(int a, int b);
// 也可以將上面的函數聲明寫成下面這種形式,像這種只有參數類型,沒有參數名稱的函數聲明稱之為函數原型(function prototype)
// int demo_cFunction2(int, int);
// 無參數,無返回值函數演示
function1();
// 有參數,有返回值函數演示
int a = 1, b = 1; // 這裡的 a 和 b 是實參
int x = function2(a, b);
// 函數遞歸
long y = recursion(100); // 結果:5050
// 向函數傳遞數組類型的演示
// 之前說過 ary 是數組的首地址,也就是說傳遞過去的是指針,也就是說實參和形參其實指向的是一個地方,相當於引用類型
int ary[] = {0, 1, 2, 3, 4 };
update(ary, 5); // 數組 ary 被更新了
// 局部變量和全局變量的演示
demo_variable1();
// 變量存儲方式的演示
demo_variable2();
// 參數不定的函數(可變參數)
demo_params();
return "看代碼及注釋吧";
}
// 無參數,無返回值函數演示
void function1()
{
// 空參數時,寫 void 和不寫 void 的區別(C 語言建議沒有參數時使用 void)
/*
void fun(); // 代表可以傳遞任意參數(C++ 則代表不能傳遞任何參數)
fun(1); // 正常編譯(在本例中這麼做其實是會編譯錯誤的,因為用的是 C++ 編譯器)
fun(1, 2, 3); // 正常編譯(在本例中這麼做其實是會編譯錯誤的,因為用的是 C++ 編譯器)
*/
/*
void fun(void); // 代表不能傳遞任何參數
fun(1); // 編譯錯誤
fun(1, 2, 3); // 編譯錯誤
*/
}
// 有參數,有返回值函數演示
int function2(int a, int b)
{
// 這裡的 a 和 b 是形參,形參就是實參的副本
// 形參變量只在被調用期間才分配內存單元,調用結束立即釋放,也就是說形參變量只有在函數內才是有效的,離開該函數就不能再使用了,即形參的作用於在函數內
return a + b;
}
// 演示函數的遞歸調用
// return: 0 + 1 + 2 + 3 + ... + n
long recursion(int n)
{
long result = 0 ;
if (n > 0)
{
result += n;
result += recursion(n - 1);
}
return result;
}
// 參數為數組類型的演示(之所以需要傳遞 aryLength 數組長度,是因為傳遞過來的 ary 是個指針,無法計算其指向的數組長度。就好像 main 函數似的,需要傳遞參數個數)
void update(int ary[], int aryLength)
{
// 此處實參和形參其實指向的是一個地方
for (int i = 0; i < aryLength; i++)
{
ary[i] = 0;
}
}
// 局部變量和全局變量的演示
void demo_variable1()
{
// 我是局部變量,作用域在函數內
int i = 1;
{
// 我是復合語句內的局部變量,作用域在復合語句內,不能與復合語句外的局部變量重名
int j = 1;
}
// 我是局部變量,如果全局變量有與我同名的,則“屏蔽”全局變量
int global01 = 200;
// 上面“屏蔽”了全局變量,那我要怎麼引用全局變量呢?像下面這樣用“::”
int global01Outside = ::global01;
}
// 變量存儲方式的演示
void demo_variable2()
{
// 從變量的生存期角度來分,可以分為靜態存儲方式和動態存儲方式
// 1、靜態存儲方式:是指在程序運行期間分配固定的存儲空間的方式
// 2、動態存儲方式:是在程序運行期間根據需要進行動態的分配存儲空間的方式
// 全局變量在程序運行期間都會被分配固定的存儲空間(靜態存儲方式)
// 局部變量默認就是 auto 的,即動態分配存儲空間。下面這句寫全了就是 auto int i = 0;(動態存儲方式)
int i = 0;
// 如果希望函數中的局部變量的值在函數調用結束後不消失的話,則應該用 static 指定局部變量為“靜態局部變量”(靜態存儲方式)
static int j = 0;
// 用 register 指定“寄存器變量”,其會保存在 cpu 中的寄存器中。一個最佳場景是,將其作為循環控制的變量
// 寄存器變量無地址,所以不能用“&”對其取地址(C++ 可以取其地址,但是編譯器會自動將其變為內存變量)。另外,寄存器不夠用的話會自動變為內存變量
register int x = 0;
// 用 volatile 保證變量必在內存中,而不會被放入 cpu 寄存器(如果編譯器認為某變量無外部修改,則為了優化會將其放入寄存器)
volatile int y = 0;
// 全局變量是在函數的外部定義的,它的作用域為從變量定義處開始,到本程序文件的末尾
// 如果在定義點之前的函數想引用該全局變量,則應該使用 extern 表明該變量在別的地方已經定義過了,在這裡要使用那個變量
extern int global02, global03; // 如果沒有這句的話,則編譯會報“未聲明的標識符”的錯誤
int p02 = global02;
int p03 = global03;
}
int global02 = 200, global03 = 300;
// 以下演示如何定義及使用參數不定的函數(可變參數)
#include <stdarg.h> // 其定義了 va_start, va_arg, va_end (va 應該是 variable argument(可變參數)的簡寫)
void demo_params()
{
// 計算 n 個整數的平均值,第一個參數代表後面的參數的個數
float average(int paramCount, ...);
float result = average(4, 1, 2, 3, 4); // 2.5
}
float average(int paramCount, ...)
{
// 定義一個參數列表
va_list va_params;
long sum = 0;
// 告知不定參數的個數,並准備讀取參數
va_start(va_params, paramCount);
for (int i = 0; i < paramCount; i++)
{
// 一個一個地按照指定的類型讀取參數的值,每讀取完一個,參數指針就會向後移動繼續讀取下一個
int value = va_arg(va_params, int);
sum += value;
}
// 停止讀取參數
va_end(va_params);
return sum * 1.0f / paramCount;
}
OK
[源碼下載]