while為什么不是條件語句關鍵字?
1、結論
while是循環語句的關鍵字,不是條件語句的關鍵字。雖然需要滿足一定條件才能進入循環體。
2、拓展
while在英文中常被翻譯為“在……的時候,當……時”,私以為在C語言的while里,應當為“當……的時候,一直……”因為這樣說,才符合while表示循環的身份,while循環結構也是C語言很常見和很重要的一種語法
while的作用是:
表示一種入口條件循環——while循環結構。
1、while的使用
如果你已經有C程序的編程經驗,那可能while已經是你的老熟人了,如果你正在學循環結構,不妨也一起回顧一下while的格式:
int i = 0;
while (i < 10) /* while關鍵字后跟小括號,括號內是邏輯表達式,只要邏輯表達式成立,就循環地執行while后的語句 */
i++; /* 這是一條循環體的語句,這段代碼的效果是i從0開始一直自增1,i=10的時候循環結束 */
int i = 0, sum = 0;
while (i < 10) /* 如果循環體是復合語句,需要加大括號 */
{ /* 這段代碼的效果是,sum保存的是0到9的和 */
sum += i;
i++;
}
2、談談邏輯表達式
和if-else的邏輯表達式類似,效果都是看看是否成立,成立的標準是看表達式的值是不是非零或者true,反之不成立是0和false
作為一種入口條件循環,while關鍵字后的邏輯表達式只要成立,就會執行循環體,然后返回再看邏輯表達式是否成立,以此循環
所以你可能注意到了,如果邏輯表達式一直成立呢?這就是我們常說的死循環:
while (1)
{
/* 這種死循環很常見,并非人為疏忽造成的bug,而是利用死循環的特性寫的程序,如多線程編程中常用這種死循環 */
/* 提示:如果邏輯表達式是整數常量,記住,只有0表示false,非零常量都表示true,3,1024,-1 ,-10等等 */
/* 不過習慣上就寫while (1)就行,寫while (1024)的話其他同事看著不知道你這是什么名堂 */
}
while (true)
{
/* true是bool常量,當然也表示成立,java轉過來的程序員對這種寫法應該更倍感親切,因為java的死循環喜歡這樣寫 */
}
int i = 0;
int j = 1, sum = 0;
while (i < 10)
{
sum += j;
j++;
/* 整個循環體中忘記了對循環條件做處理導致的死循環,這種bug在使用while結構且循環體比較長的時候可能發生 */
}
有一種常見的while循環的應用,叫做讀循環,它是指循環地輸入一些數據然后處理,一遍一遍地執行這樣的操作:
int a, b, flag;
flag = scanf("%d%d", &a, &b); /* 輸入兩個整數 */
while (flag == 1)
{
printf("Summary is %d\n", a + b); /* 打印兩個數的和 */
flag = scanf("%d%d", &a, &b); /* 再輸入兩個數,循環上述步驟 */
}
/* 順便提醒一句,編程需要謹慎認真,專心致志,==運算符一定要與=運算符區分好,下面這種是常見錯誤 */
while (flag = 1) /* 這相當于把flag賦值為1了,而不是邏輯表達式 */
{
/* 好的編譯器在這里會報錯 */
}
這只是讀循環的一個小demo,一般輸入語句存在于while之前和循環體的最后,不過在C語言的風格中,還有一種更簡練的寫法:
int a, b; /* flag直接省了 */
while (scanf("%d%d", &a, &b)) /* 這樣用scanf是因為它被成功調用時會返回一個1,這里索性把==運算符也省了 */
{
printf("Summary is %d\n", a + b); /* 打印兩個數的和 */
}
ACMer或者參加過程序設計大賽、算法比賽和認證的人可能對上面這種很大神的操作很熟悉,那是對付OJ系統上的輸入類的題的一種技巧
3、while的應用
說到while的常見使用,我首先能想起的是人性化輸入糾錯(自己安的名字):
char sex;
scanf("%c", &sex); /* 輸入性別,只能是字符m或f */
while (sex != 'm' && sex != 'f') /* 只要輸入的不是m和f,就重來 */
{
printf("Wrong character, input again:\n");
scanf("%c", &sex);
}
/* 另外常見的還有必須輸入正數,必須輸入數字,必須輸入字母,必須是某幾種枚舉,為的是保證輸入數據符合后面的程序處理 */
還有一種很常見應用就是與指針的配合了,比如鏈表的遍歷:
cur = head->next; /* p指向帶頭結點的鏈表的第一個結點 */
while (cur) /* 這里其實應該寫為cur != NULL */
{
printf("%d\t", cur->value);
cur = cur->next;
}
/*
因為在一個鏈表中,尾結點的next指針一般是NULL的,而NULL可以作為不成立的邏輯表達式,與false和0效果一樣
所以上述程序的效果就是,cur指針按序指向每個結點,當遍歷完最后一個結點后,cur=cur->next=NULL
回到while頭的循環條件判斷時則會不成立,由此跳出了循環,所以最后一條語句一定要有,否則會死循環
*/
當然,多線程中也常見while,而且是死循環的while(死循環一般很少用do-while循環和for循環):
/* 常規操作:while(1) */
while (1) /* 報時器 */
{
Sleep(1000); /* 線程休眠1s */
char* time;
getSystemTime(time);
printf("Current time : %s\n"); /* 打印當前時間 */
}
/* 非主流操作:for(;;) */
for(;;)
{
Sleep(1000); /* 線程休眠1s */
char* time;
getSystemTime(time);
printf("Current time : %s\n"); /* 打印當前時間 */
}
/* 魔鬼般的操作:do-while */
do{
Sleep(1000); /* 線程休眠1s */
char* time;
getSystemTime(time);
printf("Current time : %s\n"); /* 打印當前時間 */
}
while (1)