1. 程式人生 > 其它 >C/C++程式設計學習 - 第1周 ⑦ 標頭檔案、強制型別轉換、遞迴

C/C++程式設計學習 - 第1周 ⑦ 標頭檔案、強制型別轉換、遞迴

技術標籤:C語言程式設計c++程式語言c語言遞迴演算法標頭檔案

文章目錄

標頭檔案

標頭檔案包含了 C 函式宣告和巨集定義,被多個原始檔中引用共享。有兩種型別的標頭檔案:程式設計師編寫的標頭檔案和編譯器自帶的標頭檔案。

在程式中要使用標頭檔案,需要使用 C 預處理指令 #include 來引用它。前面我們已經看過 stdio.h 標頭檔案,它是編譯器自帶的標頭檔案。

引用標頭檔案相當於複製標頭檔案的內容,但是我們不會直接在原始檔中複製標頭檔案的內容,因為這麼做很容易出錯,特別在程式是由多個原始檔組成的時候。

引用標頭檔案的語法

使用預處理指令 #include 可以引用使用者和系統標頭檔案。例如:

#include <stdio.h>
#include "header.h"

引用標頭檔案的操作

#include 指令會指示 C 前處理器瀏覽指定的檔案作為輸入。前處理器的輸出包含了已經生成的輸出,被引用檔案生成的輸出以及 #include 指令之後的文字輸出。例如,如果我們有一個頭檔案 header.h,如下:

char *test(void);

和一個使用了標頭檔案的主程式 program.c,如下:

#include "header.h"
int main() { puts(test()); return 0; }

編譯器會看到如下的程式碼資訊:

char *test(void);
int main()
{
	puts(test());
	return 0;
}

只引用一次標頭檔案

如果一個頭檔案被引用兩次,編譯器會處理兩次標頭檔案的內容,這將產生錯誤。為了防止這種情況,標準的做法是把檔案的整個內容放在條件編譯語句中,如下:

#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 型別。可以使用強制型別轉換運算子來把值顯式地從一種型別轉換為另一種型別。

#include <stdio.h>
int main()
{
	int sum = 17, count = 5;
	double mean;
	mean = (double) sum / count;
	printf("Value of mean : %f\n", mean);
	return 0;
}

程式碼執行結果:

Value of mean : 3.400000

這裡要注意的是強制型別轉換運算子的優先順序大於除法,因此 sum 的值首先被轉換為 double 型,然後除以 count,得到一個型別為 double 的值。

型別轉換可以是隱式的,由編譯器自動執行,也可以是顯式的,通過使用強制型別轉換運算子來指定。在程式設計時,有需要型別轉換的時候都用上強制型別轉換運算子,是一種良好的程式設計習慣。

整數提升

整數提升是指把小於 int 或 unsigned int 的整數型別轉換為 int 或 unsigned 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 );
	return 0;
}

程式碼執行結果:

Value of sum : 116

sum 的值為 116,因為編譯器進行了整數提升,在執行實際加法運算時,把 ‘c’ 的值轉換為對應的 ascii 值。

常用的算術轉換

常用的算術轉換是隱式地把值強制轉換為相同的型別。編譯器首先執行整數提升,如果運算元型別不同,則它們會被轉換為下列層次中出現的最高層次的型別:

int unsigned int long unsigned long long long float double long double

在這裡插入圖片描述

常用的算術轉換不適用於賦值運算子、邏輯運算子 && 和 ||。

#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);
	return 0;
}

程式碼執行結果:

Value of sum : 116.000000

在這裡,c 首先被轉換為整數,但是由於最後的值是 float 型的,所以會應用常用的算術轉換,編譯器會把 i 和 c 轉換為浮點型,並把它們相加得到一個浮點數。

遞迴

遞迴就是自己呼叫自己。舉個例子:

從前有座山,山裡有座廟,廟裡有個老和尚,正在給小和尚講故事呢!故事是什麼呢?“從前有座山,山裡有座廟,廟裡有個老和尚,正在給小和尚講故事呢!故事是什麼呢?‘從前有座山,山裡有座廟,廟裡有個老和尚,正在給小和尚講故事呢!故事是什麼呢?……’”

遞迴指的是在函式的定義中使用函式自身的方法。

C 語言支援遞迴,即一個函式可以呼叫其自身。但在使用遞迴時,需要注意定義一個從函式退出的條件,否則會進入死迴圈。遞迴函式在解決許多數學問題上起了至關重要的作用,比如計算一個數的階乘、生成斐波那契數列,等等。

數的階乘

使用遞迴函式計算一個給定的數的階乘:

#include <stdio.h>
long long factorial(int i)
{
	if(i <= 1) return 1;
	return i * factorial(i - 1);
}
int main()
{
	int i = 8;
	printf("%d 的階乘為 %lld\n", i, factorial(i));
	return 0;
}

執行結果:

8 的階乘為 40320

斐波那契數列

使用遞迴函式生成一個給定的數的斐波那契數列:

#include <stdio.h>
long long fibonaci(int i)
{
	if(i == 0) return 0;
	if(i == 1) return 1;
	return fibonaci(i - 1) + fibonaci(i - 2);
}
int main()
{
	for(int i = 0; i < 10; i++)
		if(i == 9) printf("%lld", fibonaci(i));
		else printf("%lld,", fibonaci(i));
    return 0;
}

執行結果:

0,1,1,2,3,5,8,13,21,34