頭檔案
頭檔案是擴展名為 .h 的檔案,包含了 C 函式宣告和宏定義,被多個源檔案中參考共享,有兩種型別的頭檔案:程式員撰寫的頭檔案和編譯器自帶的頭檔案,
在程式中要使用頭檔案,需要使用 C 預處理指令 #include 來參考它,前面我們已經看過 stdio.h 頭檔案,它是編譯器自帶的頭檔案,
參考頭檔案相當于復制頭檔案的內容,但是我們不會直接在源檔案中復制頭檔案的內容,因為這么做很容易出錯,特別在程式是由多個源檔案組成的時候,
A simple practice in C 或 C++ 程式中,建議把所有的常量、宏、系統全域變數和函式原型寫在頭檔案中,在需要的時候隨時參考這些頭檔案,
參考頭檔案的語法
使用預處理指令 #include 可以參考用戶和系統頭檔案,它的形式有以下兩種:
#include <file>
這種形式用于參考系統頭檔案,它在系統目錄的標準串列中搜索名為 file 的檔案,在編譯源代碼時,您可以通過 -I 選項把目錄前置在該串列前,
#include "file"
這種形式用于參考用戶頭檔案,它在包含當前檔案的目錄中搜索名為 file 的檔案,在編譯源代碼時,您可以通過 -I 選項把目錄前置在該串列前,
參考頭檔案的操作
#include 指令會指示 C 前處理器瀏覽指定的檔案作為輸入,前處理器的輸出包含了已經生成的輸出,被參考檔案生成的輸出以及 #include 指令之后的文本輸出,例如,如果您有一個頭檔案 header.h,如下:
char *test (void);
和一個使用了頭檔案的主程式 program.c,如下:
int x;
#include "header.h"
int main (void)
{
puts (test ());
}
編譯器會看到如下的代碼資訊:
int x;
char *test (void);
int main (void)
{
puts (test ());
}
只參考一次頭檔案
如果一個頭檔案被參考兩次,編譯器會處理兩次頭檔案的內容,這將產生錯誤,為了防止這種情況,標準的做法是把檔案的整個內容放在條件編譯陳述句中,如下:
// 如果HEADER_FILE不存在
#ifndef HEADER_FILE
#define HEADER_FILE
the entire header file file
#endif
這種結構就是通常所說的包裝器 #ifndef,當再次參考頭檔案時,條件為假,因為 HEADER_FILE 已定義,此時,前處理器會跳過檔案的整個內容,編譯器會忽略它,
有條件參考
有時需要從多個不同的頭檔案中選擇一個參考到程式中,例如,需要指定在不同的作業系統上使用的配置引數,您可以通過一系列條件來實作這點,如下:
#if SYSTEM_1
# include "system_1.h"
#elif SYSTEM_2
# include "system_2.h"
#elif SYSTEM_3
...
#endif
但是如果頭檔案比較多的時候,這么做是很不妥當的,前處理器使用宏來定義頭檔案的名稱,這就是所謂的有條件參考,它不是用頭檔案的名稱作為 #include 的直接引數,您只需要使用宏名稱代替即可:
#define SYSTEM_H "system_1.h"
...
#include SYSTEM_H
SYSTEM_H 會擴展,前處理器會查找 system_1.h,就像 #include 最初撰寫的那樣,SYSTEM_H 可通過 -D 選項被您的 Makefile 定義,
強制型別轉換
強制型別轉換是把變數從一種型別轉換為另一種資料型別,例如,如果您想存盤一個 long 型別的值到一個簡單的整型中,您需要把 long 型別強制轉換為 int 型別,您可以使用強制型別轉換運算子來把值顯式地從一種型別轉換為另一種型別,如下所示:
(type_name) expression
請看下面的實體,使用強制型別轉換運算子把一個整數變數除以另一個整數變數,得到一個浮點數:
#include <stdio.h>
int main()
{
int sum = 17, count = 5;
double mean;
mean = (double) sum / count;
printf("Value of mean : %f\n", mean );
}
當上面的代碼被編譯和執行時,它會產生下列結果:
Value of mean : 3.400000
這里要注意的是強制型別轉換運算子的優先級大于除法,因此 sum 的值首先被轉換為 double 型,然后除以 count,得到一個型別為 double 的值,
型別轉換可以是隱式的,由編譯器自動執行,也可以是顯式的,通過使用強制型別轉換運算子來指定,在編程時,有需要型別轉換的時候都用上強制型別轉換運算子,是一種良好的編程習慣,
整數提升
整數提升是指把小于 int 或 unsigned int 的整數型別轉換為 int 或 unsigned int 的程序,請看下面的實體,在 int 中添加一個字符:
#include <stdio.h>
int main()
{
int i = 17;
char c = 'c'; /* ascii 值是 99 */
int sum;
sum = i + c;
printf("Value of sum : %d\n", sum );
}
當上面的代碼被編譯和執行時,它會產生下列結果:
Value of sum : 116
在這里,sum 的值為 116,因為編譯器進行了整數提升,在執行實際加法運算時,把 'c' 的值轉換為對應的 ascii 值,
常用的算術轉換
常用的算術轉換是隱式地把值強制轉換為相同的型別,編譯器首先執行整數提升,如果運算元型別不同,則它們會被轉換為下列層次中出現的最高層次的型別:

常用的算術轉換不適用于賦值運算子、邏輯運算子 && 和 ||,讓我們看看下面的實體來理解這個概念:
#include <stdio.h>
int main()
{
int i = 17;
char c = 'c'; /* ascii 值是 99 */
float sum;
sum = i + c;
printf("Value of sum : %f\n", sum );
}
當上面的代碼被編譯和執行時,它會產生下列結果:
Value of sum : 116.000000
在這里,c 首先被轉換為整數,但是由于最后的值是 float 型的,所以會應用常用的算術轉換,編譯器會把 i 和 c 轉換為浮點型,并把它們相加得到一個浮點數,
錯誤處理
C 語言不提供對錯誤處理的直接支持,但是作為一種系統編程語言,它以回傳值的形式允許您訪問底層資料,在發生錯誤時,大多數的 C 或 UNIX 函式呼叫回傳 1 或 NULL,同時會設定一個錯誤代碼 errno,該錯誤代碼是全域變數,表示在函式呼叫期間發生了錯誤,您可以在 errno.h 頭檔案中找到各種各樣的錯誤代碼,
所以,C 程式員可以通過檢查回傳值,然后根據回傳值決定采取哪種適當的動作,開發人員應該在程式初始化時,把 errno 設定為 0,這是一種良好的編程習慣,0 值表示程式中沒有錯誤,
errno、perror() 和 strerror()
C 語言提供了 perror() 和 strerror() 函式來顯示與 errno 相關的文本訊息,
- perror() 函式顯示您傳給它的字串,后跟一個冒號、一個空格和當前 errno 值的文本表示形式,
- strerror() 函式,回傳一個指標,指標指向當前 errno 值的文本表示形式,
讓我們來模擬一種錯誤情況,嘗試打開一個不存在的檔案,您可以使用多種方式來輸出錯誤訊息,在這里我們使用函式來演示用法,另外有一點需要注意,您應該使用 stderr 檔案流來輸出所有的錯誤,
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno ;
int main ()
{
FILE * pf;
int errnum;
pf = fopen ("unexist.txt", "rb");
if (pf == NULL)
{
errnum = errno;
fprintf(stderr, "錯誤號: %d\n", errno);
perror("通過 perror 輸出錯誤");
fprintf(stderr, "打開檔案錯誤: %s\n", strerror( errnum ));
}
else
{
fclose (pf);
}
return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
錯誤號: 2
通過 perror 輸出錯誤: No such file or directory
打開檔案錯誤: No such file or directory
被零除的錯誤
在進行除法運算時,如果不檢查除數是否為零,則會導致一個運行時錯誤,
為了避免這種情況發生,下面的代碼在進行除法運算前會先檢查除數是否為零:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int dividend = 20;
int divisor = 0;
int quotient;
if( divisor == 0){
fprintf(stderr, "除數為 0 退出運行...\n");
exit(-1);
}
quotient = dividend / divisor;
fprintf(stderr, "quotient 變數的值為 : %d\n", quotient );
exit(0);
}
當上面的代碼被編譯和執行時,它會產生下列結果:
除數為 0 退出運行...
程式退出狀態
通常情況下,程式成功執行完一個操作正常退出的時候會帶有值 EXIT_SUCCESS,在這里,EXIT_SUCCESS 是宏,它被定義為 0,
如果程式中存在一種錯誤情況,當您退出程式時,會帶有狀態值 EXIT_FAILURE,被定義為 -1,所以,上面的程式可以寫成:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int dividend = 20;
int divisor = 5;
int quotient;
if( divisor == 0){
fprintf(stderr, "除數為 0 退出運行...\n");
exit(EXIT_FAILURE);
}
quotient = dividend / divisor;
fprintf(stderr, "quotient 變數的值為: %d\n", quotient );
exit(EXIT_SUCCESS);
}
當上面的代碼被編譯和執行時,它會產生下列結果:
quotient 變數的值為 : 4
遞回
遞回指的是在函式的定義中使用函式自身的方法,
語法格式如下:
void recursion()
{
statements;
... ... ...
recursion(); /* 函式呼叫自身 */
... ... ...
}
int main()
{
recursion();
}
流程圖:

C 語言支持遞回,即一個函式可以呼叫其自身,但在使用遞回時,程式員需要注意定義一個從函式退出的條件,否則會進入死回圈,
遞回函式在解決許多數學問題上起了至關重要的作用,比如計算一個數的階乘、生成斐波那契數列,等等,
數的階乘
下面的實體使用遞回函式計算一個給定的數的階乘:
#include <stdio.h>
double factorial(unsigned int i)
{
if(i <= 1)
{
return 1;
}
return i * factorial(i - 1);
}
int main()
{
int i = 15;
printf("%d 的階乘為 %f\n", i, factorial(i));
return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
15 的階乘為 1307674368000.000000
斐波那契數列
下面的實體使用遞回函式生成一個給定的數的斐波那契數列:
#include <stdio.h>
int fibonaci(int i)
{
if(i == 0)
{
return 0;
}
if(i == 1)
{
return 1;
}
return fibonaci(i-1) + fibonaci(i-2);
}
int main()
{
int i;
for (i = 0; i < 10; i++)
{
printf("%d\t\n", fibonaci(i));
}
return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
0
1
1
2
3
5
8
13
21
34
參考自:https://www.runoob.com/cprogramming/c-tutorial.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/224148.html
標籤:C
上一篇:計算機網路 - 應用層
