標準C語言2

sleeeeeping發表於2024-05-05

二、常量(瞭解)

​ 常量就是程式執行過程中不能改變的量,C語言中常量有:字面值常量、宏常量、列舉常量。

字面值常量

100		int
100l	long
100ll	long long
100u	unsigned int
100lu	unsigned long
100llu	unsigned long long
定義一個宏常量表示100年總共有多少秒,不考慮閏平年
	#defined SEC 3600*24*365*100u

3.14	double
3.14f	float
3.14F   long double

'b' 	char

注意:使用適當的字尾可以確保資料型別的匹配,其次提高程式碼可讀性,如果沒有正確的字尾,可能導致不正確的結果或者型別轉換的問題

三、格式化輸出

%nd		最少顯示n個字元寬度,不夠則補空格,右對齊
%-nd	最少顯示n個字元寬度,不夠則補空格,左對齊
%0nd	最少顯示n個字元寬度,不夠則補0,右對齊
%n.mf	最少顯示n個字元寬度(包括小數點),小數點後顯示m個字元寬度,不夠則補空格,右對齊
%g		不顯示小數點後多餘的0

四、運算子

自變運算子
前自變:++num/--num
	變數的值立即加1或者減1
後自變:num++/num--
    變數的值也會加1或減1,但是在下一行程式碼才生效
注意:

​ 不要在一行程式碼中過多地使用自變運算子,因為不同的編譯器對它們的解釋規則不同,而且有時候會在合適的地方把後自變最佳化成前自變

​ 只能給變數使用自變運算子

算術運算子
+ - * 
    /	除		進行除法運算,獲取商
    %	求餘		進行除法運算,獲取餘數
注意:
	整數/整數	計算結果沒有小數部分	例如5/3 1  3/5 0
    /和%都是除法運算,除數不能為0,執行時會出現 浮點數例外 (核心已轉儲) 的報錯資訊,並且程式立即停止執行
    求餘的運算物件不能出現浮點數 
關係運算子
>
>=
<
<=
==	相等
!=	不相等

注意1:它們的運算結果是邏輯值,C語言中的邏輯值用0(假)和1(真)來模擬的,並且計算出來的結果還可以繼續參與數學運算

注意2:

​ 與數學規則不同 ,10 < num <100 在C語言中會先計算左邊小於號,得到邏輯值1\0,該結果繼續與100進行比較,一定滿足小於100,所以在C中是恆為真的。

注意3:

​ 使用 == 運算子時,容易漏寫一個= ,變成賦值,所以一般把常量放在==的左邊,如果漏寫,編譯器會報錯

邏輯運算子
會把運算物件先轉換成邏輯值再運算,值為0時邏輯為假,值非0時邏輯為真
A && B	邏輯與運算子 
	一假即假
A || B	邏輯或運算子 
	一真即真
!A	邏輯非運算子	
	求反
注意:! 運算子的優先順序要比 && || 高
&& || 短路特性:

​ 當左邊的運算結果已經可以確定整個邏輯運算表示式的結果時,右邊的不再進行執行

​ 適當地使用該特性可以精簡if單分支結構,能看懂即可,不要太過分,不要過分地影響程式碼可讀性

if(num > 0) {   
    num++;
} 
等同於
((num > 0) && (num++)); 
三目運算子
[A] ? [B] : [C]
有三個運算物件,先把A轉換成邏輯值,為真則執行B,為假則執行C,相當於精簡版的if else結構

注意:與else if不同的是三目運算子必須有運算結果,所以裡面不能出現流程控制語句:return 0\break\continue

賦值運算子
=		注意:賦值的值就是整個賦值運算子的運算結果
a += b;		a = a+b;
a -= b;	a *= b; a/=b; a%=b;
sizeof位元組運算子:

​ sizeof不是函式,是C語言32個關鍵字之一,能計算出資料在記憶體中的所需要的位元組數,如果運算物件不是一個表示式時,可以不使用小括號 sizeof num

​ 並且sizeof括號內的表示式沒有執行,只是猜測裡面位元組數最大為結果`

sizeof(10>100?3.13:40)	//	結果是8 並沒有執行三目運算子
位運算子

​ & | ~ ^ >> << 都是針對資料的二進位制補碼進行運算,後序再詳細講解

五、型別轉換

前提:只有相同型別的資料才能在一起進行運算,因為不同型別的資料,位元組數不同、格式、運算規則不同,必須把不同型別的資料轉換成同一型別才能運算。

自動型別轉換(隱式型別轉換):

​ 不同型別的資料組成的表示式,編譯器會把先它們轉換成相同的型別再計算,這叫作自動型別型別或隱式型別轉換,它們的轉換規則是以不丟失資料為前提:在C語言中,當不同的基本型別組成表示式時,會發生自動型別轉換。這些轉換規則通常是為了使表示式能夠正確計算。以下是一些基本型別在表示式中自動型別轉換的規則:

  1. 整數提升:在表示式中,所有的char和short型別的值都會被提升為int型別。

  2. 算術轉換:算術轉換髮生在不同數值型別之間。具體來說,當一個運算元是浮點數(float或double)而另一個運算元是整數(int、char、short等)時,整數會被轉換為浮點數。這種轉換確保了浮點數和整數之間進行運算時的精度。

  3. 無符號整數和有符號整數的轉換:當無符號整數和有符號整數進行運算時,有符號整數的型別會被提升為與其範圍相同的無符號整數型別。

  4. 賦值運算子(=):在賦值運算子中,右邊的表示式會被轉換為左邊變數的型別。

    ​ 這些規則是為了使C語言在處理不同型別的資料時能夠正確地計算結果。然而,需要注意的是,過多的型別轉換可能會導致程式碼難以理解和維護,因此在編寫程式碼時需要小心處理這些轉換。

強制型別轉換(顯式型別轉換):

​ 在C語言中,強制型別轉換(也稱為顯式型別轉換)用於將一個表示式或變數的值強制轉換為指定的型別。強制型別轉換的語法如下:

(type) expression

其中,type 是目標型別,expression 是要轉換的表示式或變數名。

請注意以下幾點關於強制型別轉換的注意事項:

  1. 強制型別轉換可以將表示式或變數的值轉換為目標型別,無論其原始型別是什麼。這可能導致精度損失或資料截斷(位元組多的向位元組數少進行轉換 )。
  2. 強制型別轉換隻改變值的解釋方式,而不改變任何位的內容。例如,將一個浮點數轉換為整數時,小數部分會被丟棄。
  3. 當進行強制型別轉換時,應確保轉換操作是合法和安全的。例如,在將浮點數轉換為整數時,如果浮點數超出了整數型別的表示範圍,則結果可能是不確定的。
  4. 強制型別轉換可以應用於基本型別、指標型別和列舉型別。

以下是一些示例,展示了強制型別轉換的使用情況:

int a = 10;
double b = 3.14;
int result = (int) b;  // 將浮點數轉換為整數型別
double sum = (double) a + b;  // 將整數轉換為浮點數型別

int* ptr = (int*) malloc(sizeof(int));  // 強制將返回型別為 void* 的 malloc 轉換為 int* 型別

enum Colors { RED, GREEN, BLUE };
int color = (int) GREEN;  // 將列舉型別轉換為整數型別

​ 需要謹慎使用強制型別轉換,確保轉換操作的安全性和合理性。不正確的型別轉換可能會導致程式執行時錯誤和不確定的行為。應仔細考慮使用強制型別轉換的場景,並儘量避免過度依賴強制型別轉換來解決問題,而是考慮是否有更好的設計和型別匹配的方案。

六、if語句

​ 程式碼的預設執行流程是從上到下,逐步、逐條執行的,if語句可以根據判斷條件選擇讓程式碼是否執行,改變了程式碼 的預設執行流程,所以這種語句也叫流程控制語句。

if(條件) { // 單分支  
	// 當條件為真時,執行此處程式碼,如果此處程式碼只有一行,大括號可以省略,但在商業專案中建議不要省略,因為這樣會影響程式碼的可擴充套件性
}

if(條件) {	// 雙分支
	// 當條件為真時,執行此處程式碼
} else {
	// 當條件為假時,執行此處程式碼
}

if(條件1) { // 多分支
	// 當條件1為真時,執行此處程式碼
} else if(條件2) { // 可以有多個else if
    // 當條件2為真時,執行此處程式碼
} 
...
else {
	// 當條件1、條件2都為假時,執行此處程式碼
}

注意:

​ 如果if、else的程式碼塊只有一行程式碼,大括號可以省略。

​ 儘管C語言允許在if語句中省略大括號,但這樣做可能導致以下問題:

  1. 可讀性差:如果省略大括號,只有緊隨其後的一行程式碼會在if條件為真時執行。這樣容易導致程式碼混淆,特別是當if語句中有多行程式碼時,很難一目瞭然地知道哪些程式碼受到if條件的控制。
  2. 容易出錯:因為只有緊隨其後的一行程式碼受到if條件的控制,如果在if語句後面新增其他程式碼而沒有新增大括號,則新新增的程式碼無論if條件真還是假都會執行。這可能會導致邏輯錯誤和意外行為。
  3. 可維護性低:如果要在if條件為真時新增更多程式碼,需要手動新增大括號。在多個if語句巢狀時,容易忘記新增大括號或新增錯誤的大括號,導致邏輯混亂和錯誤。

因此,為了保證程式的可讀性、可靠性和可維護性,推薦始終使用大括號明確指定if語句的程式碼塊。即使if條件只控制一行程式碼,也應該用大括號將該行程式碼包裹起來,以防止潛在的錯誤和增加程式碼的可讀性。

七、switch開關語句

switch(資料) {
    case v1:	語句1;	break;
    case v2:	語句2;	break;
    case v3:	語句3;	break;
	...
    default:	語句4;
}

1、switch小括號中的資料可以是變數、表示式、常量,但是結果一定是整型;case後面的資料也必須是整型常量,不能是變數

2、當case後面的值與資料相等時會開啟開關,case後面的語句會執行,如果開關沒有透過break關閉,那會一直往下執行

3、default無論放在switch中哪個位置,當所有的case開關都不滿足時,會最後執行dafault的內容

4、switch與if else 比較只是程式碼較為簡潔,switch能解決的問題,if else一樣可以解決,所以在實際開發中程式設計師一般只使用if else就足夠了

gnu編譯器的專用語法:
switch(資料) {
    case n1 ... n2:	語句; break;
}
表示 [n1,n2]之間都滿足開啟開關

八、for迴圈語句

​ 透過反覆執行一段程式碼,達到解決問題的目的,被反覆執行的程式碼稱為迴圈語句

​ for是一種非常靈活的迴圈,一般使用一個變數來引導它的執行,該變數稱為迴圈變數,早期使用index名字作為迴圈變數名,後面逐漸演變成i,如果有多個迴圈巢狀時,可以使用i j k l

for ([1]; [2]; [3]) {
   [4]; 
}

模組1:為for迴圈做一些準備工作:定義迴圈變數、給迴圈變數賦初值,但是在for中定義的變數,一旦出了迴圈就無法使用
模組2:判斷迴圈條件是否成立,如果條件成立執行模組4,如果條件不成立則結束for迴圈,如果沒有語句,則預設條件成立
模組4:被反覆執行的程式碼,稱為迴圈體語句
模組3:改變迴圈變數的值,讓迴圈變數自加或自減,i++、i--,防止出現死迴圈
迴圈流程:
	1、2、4、3、2、4、3、2、4、3、4...
    
C89語法標準下不允許在模組1中定義變數,C99之後允許定義,當前Ubuntu16.04預設的gcc語法標準採用的是c99標準
如果想要使用其他標準:
	gcc xxx.c -std=gnu89\99\11
for的不同寫法:
for (;;) {	//	死迴圈
    ...
}

int i=0;
for (; i < 10; ++i) {
    ...
}

for(int i = 0; i < 10; ) {
    ...
    i++;
}

for (int i = 0; i < 10; ++i,...);

注意:如果無論for迴圈寫成什麼樣子,迴圈體只執行1次,就很有可能是小括號後面加了分號
注意:
	1、建議for的大括號要上下對齊,裡面的內容要縮排一次
	2、如果for迴圈只有一行程式碼,可以省略大括號,但是商業程式碼要求不能省略

九、while迴圈語句

while (迴圈條件) {
   	//	迴圈語句
}

for (;迴圈條件;) {
    //	與上面的while效果一致
}

執行流程:先檢查迴圈條件,條件為真執行迴圈體,條件為假,直接結束while迴圈

for迴圈的精簡版本效果與while相似

當明確知道迴圈次數的問題適合使用for迴圈解決

當不明確知道迴圈次數的問題,適合使用while迴圈解決

十、do-while迴圈語句

do {
   //	迴圈語句 
} while (迴圈條件);	//	分號不能少

執行流程:先執行迴圈語句,再判斷迴圈條件,條件為真執行迴圈體,條件為假,直接結束迴圈,無論條件真或假,迴圈語句必定最少執行一次

注意:適合先幹活、再判斷的場景:輸入密碼判斷

注意:在do-while的大括號中定義變數,在小括號中不能使用

十一、迴圈巢狀

迴圈語句中包含了迴圈語句,特點:外層迴圈執行1次,內層迴圈執行n次

for (int i = 0; i < 10; ++i) {
    for (int j = 0; j < 10; ++j) {

    }
    printf("\n");
}

十二、跳轉語句

break跳轉語句

​ 用法1:在switch語句中可以關閉開關

​ 用法2:在迴圈語句中,可以跳出所在的一層迴圈,是一種提前結束迴圈的一種方式,提高迴圈效率

continue跳轉語句

​ 只能在迴圈語句中,停止本次迴圈,直接進入下一次迴圈,根據條件改善迴圈的執行

return跳轉語句

​ return可以提前結束函式,並返回一個結果給呼叫者

goto跳轉語句
標籤名:
	...
    goto 標籤名;

​ goto可以在函式內任意跳轉,但是由於它過於靈活自由,可能會破壞已經設計好的分支、迴圈語句,因此一般公司都禁止使用goto,新的程式設計語句中已經取消了該關鍵字

​ goto非常適合驅動程式中處理異常、釋放資源,所以在硬體程式設計中適合使用

相關文章