1. 程式人生 > >[C]第二章--分支語句與迴圈語句(1)--知識解析

[C]第二章--分支語句與迴圈語句(1)--知識解析

分支語句與迴圈語句

什麼是語句?

在C語言中,由一個分號;隔開的一段程式碼就是語句,比如:
return 0;/100 + 1 ;/printf("a");等都是語句.

分支語句

分支語句就是選擇結構

.其中最常見的關鍵詞就是if.
那if語句的語法結構是什麼樣的呢?以下列舉幾種經常使用的結構:
1
結構1

if(表示式)
	語句;

結構2

if(表示式)
	語句1;
else
	語句2;

結構三

if(表示式1)
	語句1;
else if(表示式2)
	語句2;
else
	語句3;

解釋一下:
如果表示式的結果為真,則語句1執行,否則表示式2執行.

在C語言中如何表示真假呢?
0 表示假
非0表示真

這與邏輯認知下的0為假,1為真有些差池,在C語言中非0即為真.

#include <stdio.h>
int main()[
	if
(表示式){ 語句列表1; } else{ 語句列表2; } return 0; ]

這裡是一個選擇語句的"坑".並不是跟在if之後的else之前的所有語句都會雨露均沾的執行到.
if/else預設只執行緊接著其的第一行程式碼,也就是說像這樣的語句列表並不會全部執行到.為了解決這個問題,我們引入程式碼塊的概念.
這裡的一對{ }就是程式碼塊;
用大括號{ }包裹的一系列語句的列表就是一個程式碼塊.
為了避免錯誤使用.建議讀者就將程式碼塊的使用加入平常選擇結構的使用.這樣習慣成自然,就完全不用糾結於到底有沒有執行這個語句列表了.這也有利於好的程式設計習慣的養成.

懸空else

一起來看下面這行程式碼:

#include <stdio.h>
int main(){
	int a = 0;
	int b = 2;
	if(a == 1)
		if(b == 2)
			printf("bingo\n");
	else
		printf("failed\n");
	return 0;
}

這裡的else究竟和哪個if匹配的呢?
是不是很容易產生歧義?
這就是懸空else,難以直觀的看出來if…else…結構究竟是如何配對的問題,這在C語言的初學階段是很常見的.

  • 解決方案:
    1.適當的使用{ }可以使程式碼的邏輯更加清晰,多用程式碼塊.
    2.程式碼風格的統一很重要.
    以下演示一下:
#include <stdio.h>
int main(){
	int a = 0;
	int b = 2;
	if(a == 1){
		if(b == 2)
			printf("bingo\n");
	}
	else{
		printf("failed\n");
	}
	return 0;
}

結論:
else總是與最近的if配對.

多分支

#include <stdio.h>
int main(){
	int coding = 0;
	printf("你會好好敲程式碼嗎?(選擇1或0)");
	if(coding == 1) {
		printf("堅持,你會有好成績");
	}
	else if(coding == 0){
		printf("放棄回家睡大覺吧.");
	}
	else if(coding == -1){
		printf("輸入錯誤啦");
	}
	return 0;
}

簡單的邏輯語句,就不多贅述了.

if書寫形式的對比

  • 程式碼一:
if(condition)
	return x;
return y;
  • 程式碼二:
if(condition){
	return x;
}
else{
	return y;
}
  • 程式碼三:
int num = 1;
if(num = 5){
	printf("goal");
}
  • 程式碼四:
int num = 1;
if(5 == num){
	printf("goal");
}

比較上面4個程式碼,其實各有利弊.

  1. 程式碼一利用了 if不加大括號只執行緊接的第一句語句,程式碼看起來很整潔,但是有些新手會混淆.
  2. 程式碼二就比程式碼一直觀很多了,但是二者所陳述的內容都是一樣的,加上了不必要的大括號,在實際使用上就會顯得繁瑣很多.
  3. 程式碼三是一串和預期效果不太相同的程式碼,通過分析得知num = 5這個語句,按尋常邏輯應該是num == 5的比較語句,而這裡因為少寫了一個等號 =,就使它變成了一個賦值語句,那麼這句語句再被if巢狀,他就成為了一定會判定成真的語句了.
    所以一定要注意程式碼的嚴謹性.
  4. 程式碼四中5 == num這樣書寫判斷語句雖然可以一定程度上提升程式碼安全性,因為編譯工具會自動檢查出程式碼缺陷並警告,但是這樣大大削減了程式碼的可讀性,這一句"有違常理"的語句,會使人很難讀懂其中的意思.
    很不建議這麼書寫.

綜上所述:
程式碼一 和 程式碼三 的書寫方式建議使用

switch語句

switch語句與if語句不同的是:
switch用於多分支選擇,而if適合單分支(甚至"無分枝"的簡單判斷)

switch(整形表示式){
	語句項;
}

而什麼是語句項?
是一些case語句.如下:

case 整型常量表達式:
	語句;

在switch語句中,我們沒法直接實現分支
搭配break使用才能實現真正的分支.這也是其精髓之處.
比如:

#include <stdio.h>
int main(){
	int day = 0;
	switch(day){
		case 1:
			printf("Monday");
			break;
		case 2:
			printf("Tuesday");
			break;
		case 3:
			printf("Wednesday");
			break;
		case 4:
			printf("Thursday");
			break;
		case 5:
			printf("Friday");
			break;
		case 6:
			printf("Saturday");
			break;
		default:
			printf("Sunday");
			break;
		}
		return 0;
}
default語句就是之前的case語句都為命中時執行的語句.

迴圈語句

1. while

我們已經掌握了if選擇語句,當條件滿足的情況下,if語句後的語句執行,否則不執行.但是這個語句只會執行一次.
但是我們發現生活中很多實際的例子是:同一件事情我們要完成很多次.
那我們怎麼做呢?
C語言中給我們引入了while語句,可以實現迴圈.

//while迴圈語法結構
while(表示式){
	迴圈語句;
}

比如在螢幕上列印1-10的數字.

#include <stdio.h
int main(){
	int i = 1;
	while(i <= 10){
		printf("%d ",i);
		i++;
	}
	return 0;
}

break 語句

  1. break在迴圈中的作用:
    其實在迴圈中只要遇到break,就停止後期所有的迴圈,直接跳出迴圈.
    所以,while中的break是用於永久終止迴圈的.

continue 語句

  1. continue在迴圈中的作用:
    本次continue後面的程式碼不會再執行,而是會直接跳轉到while語句的判斷部分,進行下一次迴圈的入口判斷.
    所以,while中的continue是用於終止本次迴圈

2. for

我們已經知道了while迴圈,但是為什麼還要一個for迴圈呢?

//for迴圈結構
for( 表示式1 ; 表示式2 ; 表示式3 )
	迴圈語句;
  • 表示式1為初始化部分,用於初始化迴圈變數的,在整個迴圈過程中只執行一次.
  • 表示式2為條件判斷部分,用於判斷迴圈何時終止
  • 表示式3為調整部分,用於更新迴圈變數.
    [其實必要的情況下三個表示式都可省略]

用for迴圈在螢幕上列印1-10的數字

#include <stdio.h>
int main(){
	int i = 0;
	for(i = 1; i <= 10; i++){
		printf("%d ",i);
	}
	return 0;
}

注:這裡int i寫在for語句之前是C語言寫法
我們看到過很多次在for語言中的寫法for(int i = 0;xx;xx)這樣是C++寫法

其實while中依然存在迴圈的三個必要條件,但是由於風格的問題使得三個部分偏離很遠,這樣查詢修改就不夠集中和方便,所以for迴圈更勝一籌.
for迴圈的使用頻率也最高.

一些建議:

  1. 不要在for迴圈體內修改迴圈變數,防止for迴圈失去控制
  2. 建議for語句的迴圈控制變數的取值採用"前開後閉區間"的寫法.[0 , 10)

3. do…while

//do...while語句格式
do
	迴圈語句;
while(表示式);

特點: 迴圈至少執行一次,使用的場景很侷限.這裡就不過多講解了.

4. goto語句

goto本來不是為了迴圈而誕生的,但是與標籤配合標記跳轉可以實現迴圈,實踐中沒有goto語句也可以很容易的寫出程式碼,一般不會使用goto,除非一些"必要情況".

  • 必要情況
    ->最常見的用法就是終止程式在某些深度巢狀的結構的處理過程,例如一次跳兩層或多層迴圈.
    這樣的情況使用break是達不到目的的,它只能從最內層退出到上一層的迴圈.而goto就可以直接跳轉出去.
for(...){
	for(...){
		for(...){
			if(disaster)
				goto error;
		}
	}
}
error:
	if(disaster)
	//處理錯誤情況

goto這樣迴圈語句中的"旁門左道",還是建議大家儘量不要採納,