天天看點

08-C語言流程控制選擇結構循環結構

流程控制基本概念

  • 預設情況下程式運作後,系統會按書寫順序從上至下依次執行程式中的每一行代碼。但是這并不能滿足我們所有的開發需求, 為了友善我們控制程式的運作流程,C語言提供3種流程控制結構,不同的流程控制結構可以實作不同的運作流程。
  • 這3種流程結構分别是順序結構、選擇結構、循環結構
  • 順序結構:
    • 按書寫順序從上至下依次執行
    • 08-C語言流程控制選擇結構循環結構
  • 選擇結構
    • 對給定的條件進行判斷,再根據判斷結果來決定執行代碼
    • 08-C語言流程控制選擇結構循環結構
    • 08-C語言流程控制選擇結構循環結構
  • 循環結構
    • 在給定條件成立的情況下,反複執行某一段代碼
    • 08-C語言流程控制選擇結構循環結構
    • 08-C語言流程控制選擇結構循環結構

  • C語言中提供了兩大選擇結構, 分别是if和switch

選擇結構if

  • if第一種形式
    • 表示如果表達式為真,執行語句塊1,否則不執行
if(表達式) {
  語句塊1;
}
後續語句;
           
if(age >= 18) {
  printf("開網卡\n");
}
printf("買煙\n");
           
  • if第二種形式
    • 如果表達式為真,則執行語句塊1,否則執行語句塊2
    • else不能脫離if單獨使用
if(表達式){
  語句塊1;
}else{
  語句塊2;
}
後續語句;
           
if(age > 18){
  printf("開網卡\n");
}else{
  printf("喊家長來開\n");
}
printf("買煙\n");
           
  • if第三種形式
    • 如果"表達式1"為真,則執行"語句塊1",否則判斷"表達式2",如果為真執行"語句塊2",否則再判斷"表達式3",如果真執行"語句塊3", 當表達式1、2、3都不滿足,會執行最後一個else語句
    • 衆多大括号中,隻有一個大括号中的内容會被執行
    • 隻有前面所有添加都不滿足, 才會執行else大括号中的内容
if(表達式1) {
  語句塊1;
}else if(表達式2){
  語句塊2;
}else if(表達式3){
  語句塊3;
}else{
  語句塊4;
}
後續語句;
           
if(age>40){
  printf("給房卡");
}else if(age>25){
  printf("給名片");
}else if(age>18){
   printf("給網卡");
}else{
  printf("給好人卡");
}
printf("買煙\n");
           
  • if嵌套
    • if中可以繼續嵌套if, else中也可以繼續嵌套if
if(表達式1){
    語句塊1;
   if(表達式2){
      語句塊2;
  }
}else{
   if(表達式3){
      語句塊3;
  }else{
      語句塊4;
  }
}
           
  • if注意點
    • 任何數值都有真假性
#include <stdio.h>
int main(){
    if(0){
        printf("執行了if");
    }else{
        printf("執行了else"); // 被執行
    }
}
           
    • 當if else後面隻有一條語句時, if else後面的大括号可以省略
// 極其不推薦寫法
    int age = 17;
    if (age >= 18)
        printf("開網卡\n");
    else
        printf("喊家長來開\n");
           
    • 當if else後面的大括号被省略時, else會自動和距離最近的一個if比對
#include <stdio.h>
int main(){
    if(0)
    if(1)
    printf("A\n");
    else // 和if(1)比對
    printf("B\n");
    else // 和if(0)比對, 因為if(1)已經被比對過了
    if (1)
    printf("C\n"); // 輸出C
    else // 和if(1)比對
    printf("D\n");
}
           
    • 如果if else省略了大括号, 那麼後面不能定義變量
#include <stdio.h>
int main(){
    if(1)
        int number = 10; // 系統會報錯
    printf("number = %i\n", number);
}
           
#include <stdio.h>
int main(){
    if(0){
        int number = 10; 
    }else
        int value = 20; // 系統會報錯
    printf("value = %i\n", value);
}
           
    • C語言中分号(;)也是一條語句, 稱之為空語句
// 因為if(10 > 2)後面有一個分号, 是以系統會認為if省略了大括号
// if省略大括号時隻能管控緊随其後的那條語句, 是以隻能管控分号
if(10 > 2);
{
printf("10 > 2");
}
// 輸出結果: 10 > 2
           
    • 但凡遇到比較一個變量等于或者不等于某一個常量的時候,把常量寫在前面
#include <stdio.h>
int main(){
    int a = 8;
//    if(a = 10){// 錯誤寫法, 但不會報錯
    if (10 == a){
      printf("a的值是10\n");
    }else{
     printf("a的值不是10\n");
    }
}
           
  • if練習
    • 從鍵盤輸入一個整數,判斷其是否是偶數,如果是偶數就輸出YES,否則輸出NO;
    • 接收使用者輸入的1~7的整數,根據使用者輸入的整數,輸出對應的星期幾
    • 接收使用者輸入的一個整數month代表月份,根據月份輸出對應的季節
    • 接收使用者輸入的兩個整數,判斷大小後輸出較大的那個數
    • 接收使用者輸入的三個整數,判斷大小後輸出較大的那個數
    • 接收使用者輸入的三個整數,排序後輸出
  • 實作石頭剪刀布
剪刀石頭布遊戲:
1)定義遊戲規則
  剪刀 幹掉 布
  石頭 幹掉 剪刀
  布 幹掉石頭
2)顯示玩家開始猜拳
3)接收玩家輸入的内容
4)讓電腦随機産生一種拳
5)判斷比較
(1)玩家赢的情況(顯示玩家赢了)
(2)電腦赢的情況(顯示電腦赢了)
(3)平局(顯示平局)
           
  • 08-C語言流程控制選擇結構循環結構
  • 08-C語言流程控制選擇結構循環結構
  • 08-C語言流程控制選擇結構循環結構

選擇結構switch

  • 由于 if else if 還是不夠簡潔,是以switch 就應運而生了,他跟 if else if 互為補充關系。switch 提供了點的多路選擇
  • 格式:
switch(表達式){
    case 常量表達式1:
        語句1;
        break;
    case 常量表達式2:
        語句2; 
        break;
    case 常量表達式n:
        語句n;
        break;
    default:
        語句n+1;
        break;
}
           
  • 語義:
    • 計算"表達式"的值, 逐個與其後的"常量表達式"值相比較,當"表達式"的值與某個"常量表達式"的值相等時, 即執行其後的語句, 然後跳出switch語句
    • 如果"表達式"的值與所有case後的"常量表達式"均不相同時,則執行default後的語句
  • 示例:
#include <stdio.h>

int main() {

    int num = 3;
    switch(num){
    case 1:
        printf("星期一\n");
        break;
    case 2:
        printf("星期二\n");
        break;
    case 3:
        printf("星期三\n");
        break;
    case 4:
        printf("星期四\n");
        break;
    case 5:
        printf("星期五\n");
        break;
    case 6:
        printf("星期六\n");
        break;
    case 7:
        printf("星期日\n");
        break;
    default:
        printf("回火星去\n");
        break;
    }
}
           
  • switch注意點
    • switch條件表達式的類型必須是整型, 或者可以被提升為整型的值(char、short)
#include <stdio.h>

int main() {

    switch(1.1){ // 報錯
    case 1:
        printf("星期一\n");
        break;
    case 2:
        printf("星期二\n");
        break;
    default:
        printf("回火星去\n");
        break;
    }
}
           
    • case的值隻能是常量, 并且還必須是整型, 或者可以被提升為整型的值(char、short)
#include <stdio.h>

int main() {

    int num = 3;
    switch(1){ 
    case 1:
        printf("星期一\n");
        break;
    case 'a':
        printf("星期二\n");
        break;
    case num: // 報錯
        printf("星期三\n");
        break;
    case 4.0: // 報錯
        printf("星期四\n");
        break;
    default:
        printf("回火星去\n");
        break;
    }
}
           
    • case後面常量表達式的值不能相同
#include <stdio.h>

int main() {
    switch(1){ 
    case 1: // 報錯
        printf("星期一\n");
        break;
    case 1: // 報錯
        printf("星期一\n");
        break;
    default:
        printf("回火星去\n");
        break;
    }
}
           
    • case後面要想定義變量,必須給case加上大括号
#include <stdio.h>

int main() {
    switch(1){
    case 1:{
        int num = 10;
        printf("num = %i\n", num);
        printf("星期一\n");
        break;
        }
    case 2:
        printf("星期一\n");
        break;
    default:
        printf("回火星去\n");
        break;
    }
}
           
    • switch中隻要任意一個case比對, 其它所有的case和default都會失效. 是以如果case和default後面沒有break就會出現穿透問題
#include <stdio.h>

int main() {

    int num = 2;
    switch(num){
    case 1:
        printf("星期一\n");
        break;
    case 2:
        printf("星期二\n"); // 被輸出
    case 3:
        printf("星期三\n"); // 被輸出
    default:
        printf("回火星去\n"); // 被輸出
        break;
    }
}
           
    • switch中default可以省略
#include <stdio.h>

int main() {
    switch(1){
    case 1:
        printf("星期一\n");
        break;
    case 2:
        printf("星期一\n");
        break;
    }
}
           
    • switch中default的位置不一定要寫到最後, 無論放到哪都會等到所有case都不比對才會執行(穿透問題除外)
#include <stdio.h>

int main() {
    switch(3){
    case 1:
        printf("星期一\n");
        break;
    default:
        printf("Other,,,\n");
        break;
    case 2:
        printf("星期一\n");
        break;
    }
}
           
  • if和Switch轉換
  • 看上去if和switch都可以實作同樣的功能, 那麼在企業開發中我們什麼時候使用if, 什麼時候使用switch呢?
    • if else if 針對于範圍的多路選擇
    • switch 是針對點的多路選擇
  • 判斷使用者輸入的資料是否大于100
#include <stdio.h>

int main() {
    int a = -1;
    scanf("%d", &a);
    if(a > 100){
        printf("使用者輸入的資料大于100");
    }else{
        printf("使用者輸入的資料不大于100");
    }
}
           
#include <stdio.h>

int main() {
    int a = -1;
    scanf("%d", &a);
    // 挺(T)萌(M)的(D)搞不定啊
    switch (a) {
        case 101:
        case 102:
        case 103:
        case 104:
        case 105:
            printf("大于\n");
            break;
        default:
            printf("不大于\n");
            break;
    }
}
           
  • 練習
    • 實作分數等級判定
要求使用者輸入一個分數,根據輸入的分數輸出對應的等級
A 90~100  99/10 = 9  90/10= 9  98/10 = 9 100/10 = 10
B 80~89 89/10 = 8
C 70~79
D 60~69
E 0~59
           
    • 實作+ - * / 簡單電腦

  • C語言中提供了三大循環結構, 分别是while、dowhile和for
  • 循環結構是程式中一種很重要的結構。
    • 其特點是,在給定條件成立時,反複執行某程式段, 直到條件不成立為止。
    • 給定的條件稱為"循環條件",反複執行的程式段稱為"循環體"
  • 08-C語言流程控制選擇結構循環結構

循環結構while

while (  循環控制條件 ) {
    循環體中的語句;
    能夠讓循環結束的語句;
    ....
}
           
  • 構成循環結構的幾個條件
    • 循環控制條件
      • 循環退出的主要依據,來控制循環到底什麼時候退出
    • 循環體
      • 循環的過程中重複執行的代碼段
    • 能夠讓循環結束的語句(遞增、遞減、真、假等)
      • 能夠讓循環條件為假的依據,否則退出循環
int count = 0;
while (count < 3) { // 循環控制條件
    printf("發射子彈~哔哔哔哔\n"); // 需要反複執行的語句
    count++; // 能夠讓循環結束的語句
}
           
  • while循環執行流程
    • 首先會判定"循環控制條件"是否為真, 如果為假直接跳到循環語句後面
    • 如果"循環控制條件"為真, 執行一次循環體, 然後再次判斷"循環控制條件"是否為真, 為真繼續執行循環體,為假跳出循環
    • 重複以上操作, 直到"循環控制條件"為假為止
#include <stdio.h>
int main(){
    int count = 4;
    // 1.判斷循環控制條件是否為真,此時為假是以跳過循環語句
    while (count < 3) { 
        printf("發射子彈~哔哔哔哔\n"); 
        count++; 
    }
    // 2.執行循環語句後面的代碼, 列印"循環執行完畢"
    printf("循環執行完畢\n");
}
           
#include <stdio.h>
int main(){
    int count = 0;
    // 1.判斷循環控制條件是否為真,此時0 < 3為真
    // 4.再次判斷循環控制條件是否為真,此時1 < 3為真
    // 7.再次判斷循環控制條件是否為真,此時2 < 3為真
    // 10.再次判斷循環控制條件是否為真,此時3 < 3為假, 跳過循環語句
    while (count < 3) { 
        // 2.執行循環體中的代碼, 列印"發子彈"
        // 5.執行循環體中的代碼, 列印"發子彈"
        // 8.執行循環體中的代碼, 列印"發子彈"
        printf("發射子彈~哔哔哔哔\n"); 
        // 3.執行"能夠讓循環結束的語句" count = 1
        // 6.執行"能夠讓循環結束的語句" count = 2
        // 9.執行"能夠讓循環結束的語句" count = 3
        count++; 
    }
    // 11.執行循環語句後面的代碼, 列印"循環執行完畢"
    printf("循環執行完畢\n");
}
           
  • while循環注意點
#include <stdio.h>
int main(){
    while (1) { // 死循環
         printf("發射子彈~哔哔哔哔\n");
         // 沒有能夠讓循環結束的語句
    }
}
           
    • 當while後面隻有一條語句時,while後面的大括号可以省略
#include <stdio.h>
int main(){
    while (1)  // 死循環
         printf("發射子彈~哔哔哔哔\n");
         // 沒有能夠讓循環結束的語句
}
           
    • 如果while省略了大括号, 那麼後面不能定義變量
#include <stdio.h>
int main(){
    while (1)  // 死循環
         int num = 10; // 報錯
         // 沒有能夠讓循環結束的語句
}
           
#include <stdio.h>
int main(){
    int count = 0;
    while (count < 3);{ // 死循環
       printf("發射子彈~哔哔哔哔\n"); 
       count++; 
    }
}
           
    • 最簡單的死循環
// 死循環一般在作業系統級别的應用程式會比較多, 日常開發中很少用
while (1);
           
  • while練習
    • 計算1 + 2 + 3 + ...n的和
    • 擷取1~100之間 7的倍數的個數

循環結構do while

do {
    循環體中的語句;
    能夠讓循環結束的語句;
    ....
} while (循環控制條件 );
           
  • 示例
int count = 0;
do {
   printf("發射子彈~哔哔哔哔\n");
   count++;
}while(count < 10);
           
  • do-while循環執行流程
    • 首先不管while中的條件是否成立, 都會執行一次"循環體"
    • 執行完一次循環體,接着再次判斷while中的條件是否為真, 為真繼續執行循環體,為假跳出循環
  • 應用場景
    • 密碼校驗
#include<stdio.h>
int main()
{
    int num = -1;
    do{
        printf("請輸入密碼,驗證您的身份\n");
        scanf("%d", &num);
    }while(123456 != num);
    printf("主人,您終于回來了\n");
}
           
  • while和dowhile應用場景
    • 絕大多數情況下while和dowhile可以互換, 是以能用while就用while
    • 無論如何都需要先執行一次循環體的情況, 才使用dowhile
    • do while 曾一度提議廢除,但是他在輸入性檢查方面還是有點用的

循環結構for

for(初始化表達式;循環條件表達式;循環後的操作表達式) {
    循環體中的語句;
}
           
for(int i = 0; i < 10; i++){
    printf("發射子彈~哔哔哔哔\n");
}
           
  • for循環執行流程

    +首先執行"初始化表達式",而且在整個循環過程中,隻會執行一次初始化表達式

    • 接着判斷"循環條件表達式"是否為真,為真執行循環體中的語句
    • 循環體執行完畢後,接下來會執行"循環後的操作表達式",然後再次判斷條件是否為真,為真繼續執行循環體,為假跳出循環
    • 重複上述過程,直到條件不成立就結束for循環
  • for循環注意點:
    • 和while一模一樣
    • for(;;);

  • for和while應用場景
    • while能做的for都能做, 是以企業開發中能用for就用for, 因為for更為靈活
    • 而且對比while來說for更節約記憶體空間
int count = 0; // 初始化表達式
while (count < 10) { // 條件表達式
      printf("發射子彈~哔哔哔哔 %i\n", count);
      count++; // 循環後增量表達式
}
// 如果初始化表達式的值, 需要在循環之後使用, 那麼就用while
printf("count = %i\n", count);
           
// 注意: 在for循環初始化表達式中定義的變量, 隻能在for循環後面的{}中通路
// 是以: 如果初始化表達式的值, 不需要在循環之後使用, 那麼就用for
// 因為如果初始化表達式的值, 在循環之後就不需要使用了 , 那麼用while會導緻性能問題
for (int count = 0; count < 10; count++) {
     printf("發射子彈~哔哔哔哔 %i\n", count);
}
//     printf("count = %i\n", count);
           
// 如果需要使用初始化表達式的值, 也可以将初始化表達式寫到外面
int count = 0;
for (; count < 10; count++) {
     printf("發射子彈~哔哔哔哔\n", count);
}
printf("count = %i\n", count);
           

四大跳轉

  • C語言中提供了四大跳轉語句, 分别是return、break、continue、goto
  • break:
    • 立即跳出switch語句或循環
  • 應用場景:
    • switch
  • 08-C語言流程控制選擇結構循環結構
  • 08-C語言流程控制選擇結構循環結構
    • 列印 10 的所有加法組和
  • break注意點:
    • break離開應用範圍,存在是沒有意義的
if(1) {
  break; // 會報錯
}
           
    • 在多層循環中,一個break語句隻向外跳一層
while(1) {
  while(2) {
    break;// 隻對while2有效, 不會影響while1
  }
  printf("while1循環體\n");
}
           
    • break下面不可以有語句,因為執行不到
while(2){
  break;
  printf("打我啊!");// 執行不到
}
           
  • continue
    • 結束本輪循環,進入下一輪循環
  • 08-C語言流程控制選擇結構循環結構
  • continue注意點:
    • continue離開應用範圍,存在是沒有意義的
if(1) {
  continue; // 會報錯
}
           
  • goto
    • 這是一個不太值得探讨的話題,goto 會破壞結構化程式設計流程,它将使程式層次不清,且不易讀,是以慎用
    • goto 語句,僅能在本函數内實作跳轉,不能實作跨函數跳轉(短跳轉)。但是他在跳出多重循環的時候效率還是蠻高的
  • 08-C語言流程控制選擇結構循環結構
#include <stdio.h>
int main(){
    int num = 0;
// loop:是定義的标記
loop:if(num < 10){
        printf("num = %d\n", num);
        num++;
        // goto loop代表跳轉到标記的位置
        goto loop;
    }
}
           
#include <stdio.h>
int main(){
    while (1) {
        while(2){
            goto lnj;
        }
    }
    lnj:printf("跳過了所有循環");
}
           
  • return
    • 結束目前函數,将結果傳回給調用者
    • 不着急, 放一放,學到函數我們再回頭來看它

循環的嵌套

  • 循環結構的循環體中存在其他的循環結構,我們稱之為循環嵌套
    • 注意: 一般循環嵌套不超過三層
    • 外循環執行的次數 * 内循環執行的次數就是内循環總共執行的次數
while(條件表達式) {
    while循環結構 or dowhile循環結構 or for循環結構
}
           
for(初始化表達式;循環條件表達式;循環後的操作表達式) {
    while循環結構 or dowhile循環結構 or for循環結構
}
           
do {
     while循環結構 or dowhile循環結構 or for循環結構
} while (循環控制條件 );
           
  • 循環優化
    • 在多重循環中,如果有可能,應當将最長的循環放在最内層,最短的循環放在最外層,以減少 CPU 跨切循環層的次數
for (row=0; row<100; row++) {
  // 低效率:長循環在最外層
  for ( col=0; col<5; col++ ) {
    sum = sum + a[row][col];
  }
}
           
for (col=0; col<5; col++ ) {
  // 高效率:長循環在最内層
  for (row=0; row<100; row++) {
    sum = sum + a[row][col];
  }
}
           
    • 列印好友清單
好友清單1
    好友1
    好友2
好友清單2
    好友1
    好友2
好友清單3
    好友1
    好友2
           
for (int i = 0; i < 4; i++) {
    printf("好友清單%d\n", i+1);
    for (int j = 0; j < 4; j++) {
        printf("    角色%d\n", j);
    }
}
           

圖形列印

  • 一重循環解決線性的問題,而二重循環和三重循環就可以解決平面和立體的問題了
  • 列印矩形
****
****
****
           
// 3行4列
//  外循環控制行數
for (int i = 0; i < 3; i++) {
//        内循環控制列數
    for (int j = 0; j < 4; j++) {
        printf("*");
    }
    printf("\n");
}
           
  • 列印三角形
    • 尖尖朝上,改變内循環的條件表達式,讓内循環的條件表達式随着外循環的i值變化
    • 尖尖朝下,改變内循環的初始化表達式,讓内循環的初始化表達式随着外循環的i值變化
*
**
***
****
*****
           
/*
最多列印5行
最多列印5列
每一行和每一列關系是什麼? 列數<=行數
*/
for(int i = 0; i< 5; i++) {
    for(int j = 0; j <= i; j++) {
        printf("*");
    }
    printf("\n");
}
           
*****
****
***
**
*
           
for(int i = 0; i< 5; i++) {
    for(int j = i; j < 5; j++) {
        printf("*");
    }
    printf("\n");
}
           
    • 列印特殊三角形
1
12
123
           
for (int i = 0; i < 3; i++) {
    for (int j = 0; j <= i; j++) {
        printf("%d", j+1);
    }
    printf("\n");
}
           
1
22
333
           
for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= i; j++) {
        printf("%d", i);
    }
    printf("\n");
}
           
--*
-***
*****
           
for (int i = 0; i <= 5; i++) {
    for (int j = 0; j < 5 - i; j++) {
        printf("-");
    }
    for (int m = 0; m < 2*i+1; m++) {
        printf("*");
    }
    printf("\n");
}
           
    • 列印99乘法表
1 * 1 = 1
1 * 2 = 2     2 * 2 = 4
1 * 3 = 3     2 * 3 = 6     3 * 3 = 9
           
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        printf("%d * %d = %d \t", j, i, (j * i));
    }
    printf("\n");
}
           

繼續閱讀