分支與回圈
這章節我們會講到以下幾個知識:
-
分支陳述句
ifswitch
-
回圈陳述句
while回圈
-for回圈
-do...while回圈
-
goto陳述句
還是那句話,我只是一個剛入門的小菜鳥,哪有有講的不好,還望大家海涵,
先講一個知識點,在C語言中什么是陳述句呢?C語言中由一個分號;隔開的就是一條陳述句,比如:
#include <stdio.h>
int main ()
{
1+2;//這是一條陳述句
printf("Hello\n");//這也是一條陳述句
;//這也是一條陳述句
return 0;
}
在C語言中所有陳述句都分為三大型別:
- 順序結構
- 選擇結構
- 回圈結構
順序結構很簡單,程式從上至下地執行,中間無任何判斷和跳轉,流程示意圖:

下面的我就沒繼續畫了,大家懂就可以了,而下面重點要講的是分支與回圈結構,
分支陳述句(選擇陳述句)
分支陳述句也稱選擇陳述句,什么叫選擇呢?就好比在大學里,如果好好學習,校招時就拿一個好offer,如果不好好學習,那就回家種田吧,而學不學呢就是一種選擇,

我畫的圖描述的清楚嗎?各位客官?分支陳述句也分為以下幾種:
if陳述句switch陳述句
if陳述句
if陳述句,if是啥意思?如果的意思,那相對應的是不是還有else否則的意思?那我們看看if陳述句在C語言中是怎樣描述的呢?
語法形式
if(運算式)
陳述句;
if(運算式)
陳述句1;
else
陳述句2;
//多分支
if(運算式)
陳述句1;
else if(運算式)
陳述句2;
//
....
else
陳述句3;
解釋:就是如果運算式結構為真就執行陳述句1反之執行陳述句2,if(運算式)運算式為真就執行if后面的陳述句,如果為假就執行else后的陳述句,那有人就問了在C語言中怎樣描述真偽的呢?
在C語言中 0代表假,非0代表真,
舉個例子吧,如果if(1>2),這個運算式的結果是什么?1會大于2嗎?顯然是不會的所以這個運算式的結果為假也就是0,
用代碼形式來講吧:
#include <stdio.h>
int main()
{
int age = 9;
if(age<18)
{
printf("未成年\n");
}
return 0;
}
//代碼2
int main()
{
int age = 18;
if(age>=18)
{
printf("成年人\n");
}
else
{
printf("未成年\n");
}
return 0;
}
//代碼3
int main()
{
int age = 25;
if(age<18)
{
printf("未成年\n");
}
else if(age>=18&&age<30)
{
printf("青年");
}
else if(age>=30&&age<55)
{
printf("中年\n");
}
else
{
printf("老年人");
}
return 0;
}
看看效果吧:

效果果然跟預想的是一樣的,有人有點好奇為啥要加大括號呢?我們看看下面:

我們看到報錯了,為啥呢?那為啥下面沒錯呢?

if陳述句默認只能控制一條陳述句所以程式報錯,因為在C語言中,if和else不加括號默認控制一條陳述句,我們可以試試:

看到雖然沒有報錯,但是它多列印了一條陳述句,再換一個:

可以知道確實if陳述句和else陳述句默認只能控制一條陳述句,我們可以加上大括號來防止這些錯誤,
接著我們看代碼3的運行效果:

年齡大家可以自行修改,或者加入一條輸入陳述句,自己輸入想要判斷的年齡,代碼3是屬于if陳述句中的多分支陳述句,也就是有多重選擇,如果怎么怎么樣會怎么怎么樣,又如果怎么怎么樣又會怎么怎么樣,..........最后否則怎么樣,這是屬于if陳述句的知識點,
我們檢測一下:
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a==1)
if(b==2)
printf("hello\n");
else
printf("heihei\n");
return 0;
}
想想結果是啥?是hello還是heihei呢?咱們看看運行效果:

啥也沒輸出,為什么呢?這涉及到一個知識點:
if陳述句中if會與最近的else進行配對
所以這題具體的意思就是:
#include <stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a==1)
if(b==2)
printf("hello\n");
else
printf("heihei\n");
return 0;
}
//也等于
if(a==1)
{
if(b==2)
{
printf("hello\n");
}
else
{
printf("heihei\n");
}
}
//或者想列印heihei這樣改造
int main()
{
int a = 0;
int b = 2;
if(a==1)
{
if(b==2)
{
printf("hello\n");
}
}
else
{
printf("heihei\n");
}
return 0;
}
第一個判斷是否成立呢?0會等于1嘛?肯定不會的,也沒有想匹配的else陳述句所以啥也不會輸出,所以大家要注意哦,書寫規范還是挺重要的,當然知識點也不能忘掉,我們再看兩段代碼:
#include <stdio.h>
int main()
{
int n = 5;
if(n==7)
{
printf("hello");
}
return 0;
}
//代碼2
int main()
{
int n = 5;
if(7==n)
{
printf("hello");
}
return 0;
}
這兩段代碼各位覺得如何?個人覺得代碼2要更好,更嚴謹,如果我們代碼1的形式少了個=號,會怎么樣?

確實是正常運行的,但是n的值被改變了,這可不是我們 想要的結果呀?我們換下:

如果我們換一種寫法,就直接報錯了,所以這種寫法還是嚴謹的,邏輯更加清晰,不容易出錯,
練習:
- 判斷一個數是否為奇數
- 輸出1~100之間的奇數
#include <stdio.h>
int main()
{
int n = 5;
if(n%2!=)
{
printf("奇數\n");
}
else
{
printf("偶數\n");
}
return 0;
}
//2
int main()
{
int i = 1;
while(i<=100)
{
if(i%2!=0)
{
printf("%d ",i);
}
i++;
}
}
Switch陳述句
我們再講分支陳述句中另外一大分支陳述句 -- Switch陳述句,Switch陳述句用于多分支的情況,比如說輸入1~7中的任意數字,然后輸出相對應的日期,
輸入1,輸出星期一
輸入2,輸出星期二
.....
輸入7,輸出星期日
雖然我們使用if..else if ...else if....else的形式可以完成要求,但是太復雜了,代碼會過于冗余也就是太長了,這個時候我們就可以用Switch陳述句,
switch (整型運算式)
{
case 整型常量:
陳述句;
break;
case 整型常量2:
陳述句;
break;
//.....
default:
陳述句;
break;
}
我們用上面的例子:
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d",&day);
switch(day)
{
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;
}
return 0;
}
效果如下:

這里用英語的形式是因為鄙人正在學習英語哈,勿怪勿怪,
看了效果后,帶大家理解理解這玩意,Switch(整型運算式)這里只能是整型或者字符型,因為字符型其實也是整型的一種嘛,然后case后面也必須跟的是整型常量值,這是規定,別問我我也不大了解,至于每條陳述句為啥加了break呢?break是什么意思呢?break在英語中是打破、弄壞、停止運轉的意思,那么在計算機中又是啥意思呢?在初始C語言中,我們也知道這個break是關鍵字,在C語言中break是指跳出,結束的意思,就是跳出程式的意思,我們試著把這個去掉看看:

咋一看全列印出來了,為啥呢?就是因為少了跳出的關鍵字,我們加上一個試試:

我們加上一條break陳述句后,確實后面的沒有列印了,可是我們輸入的是1呀,應該只會輸出一個呀?因為只有一個break陳述句,所以我們為了應對要求所以應該在每條case陳述句后加上break,這樣就可得到之前的效果,注意看我還輸入一條陳述句就是default陳述句,這個又是啥意思呢?我們看效果:

輸出的竟然是輸入錯誤,也確實,我們生活中也沒有星期八的存在呀,default是什么意思呢?默認、違約的意思,同樣的在C語言中,default也是默認的意思,就是除了我們給出的幾個常量值,如果我輸入的值不在這幾個之內,那么我們就可以用這個陳述句提醒用戶輸入是錯誤的,這是一個好的編程習慣,這樣我們可以總結出幾個編程習慣:
- 在case 陳述句的后面加上一條 break陳述句,
- 按要求來給每個case陳述句加break陳述句,
- 在每個 switch 陳述句中都放一條default子句是個好習慣,甚至可以在后邊再加一個 break ,
break陳述句可以把陳述句串列劃分成不同的部分,比如1 ~ 5都是作業日,6 ~ 7是休息日,
#include <stdio.h>
int main()
{
int day = 0;
scanf("%d",&day);
switch(day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");
break;
case 6:
case 7:
printf("playday\n");
break;
default:
break;
}
return 0;
}
我們看看效果:

因為break把1 ~ 5分為一部分,無論是輸入1還是其他1~5之間的任何數輸出都是weekday,同樣的把6 ~7也分為一部分,
下面我們來做一道Switch嵌套Switch的練習:
#include <stdio.h>
int main()
{
int n = 1;
int m = 2;
switch(n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch(n)
{
case 1:
n++;
case 2:
m++;
n++;
break;
}
case 4:
m++;
break;
default:
break;
}
printf("m = %d, n = %d",m,n);
return 0;
}
大家思考一下是多少呢?

大家看到m=5,n=3,為什么呢?決議:
int n = 1; int m = 2; switch(1) { case 1://因為n是1所以執行case1 m++;//m=m+1 = 2+1 = 3 case 2: n++;//n=2 case 3://因為上局case陳述句沒有break陳述句所以會繼續執行下面陳述句 switch(2)//n=2 { case 1: n++; case 2://因為n=2所以執行的是這條陳述句 m++;//m=3+1=4 n++;//n=2+1=3 break;//遇到跳出陳述句了所以跳出這個Switch陳述句 } case 4: m++;//接著上面的資料 m=4+1=5 n = 3 break;//遇到跳出陳述句所以跳出整個Switch陳述句后面的代碼不再執行 }
回圈陳述句
回圈陳述句,也就是重復的做某件事情,比如說我需要列印100行“Hello World”,雖然說可以用100條printf函式列印出來,但是也需要太長的代碼了,所以我們采用回圈陳述句來做,咱們看看流程圖:

在回圈陳述句中又分為3中型別:
- while
- for
- do...while
while回圈
C語言中while回圈的語法規定:
//while語法結構
while(運算式)
{
回圈陳述句;//回圈體
}
int i = 0;//初始化
while(i<10)//條件判斷
{
i++;//回圈變數調整
}
我們用流程圖來說明while回圈:

畫的不是很好大家諒解諒解,這大概就是while回圈的流程圖了,我們來看看實體:
列印1~100的數字
#include <stdio.h>
int main()
{
int i = 1;
while(i<=100)
{
printf("%d ", i);
i = i+1;
}
return 0;
}
效果如下:

回圈條件如果恒為真那就死回圈了,在while回圈也是可以使用break陳述句跳出回圈的,比如說我遇到了20就退出回圈:

可以看到確實到了20就已經退出了回圈,那我只想不要20這個數字,繼續列印后面的呢?請看下面:

可以看到確實跳過了20直接列印后面的數字了,可是數字1也沒有列印出來,原因是i的值在進入回圈后就發生了自增,所以直接跳過了數字1,如果想得到1也很簡單,我們把i的值初始化為0即可,通過觀察break和continue陳述句的作用,我們得出結論:
在回圈中只要遇到break,就停止后期的所有的回圈,直接終止回圈 ,while中的break是用于永久終止回圈的 ,
continue是用于終止本次回圈的,也就是本次回圈中continue后邊的代碼不會再執行,而是直接跳轉到while陳述句的判斷部分,進行下一次回圈的入口判斷,
注意:
while回圈嵌套continue陳述句時注意回圈變數的增值運算式的位置,也就是上面的
i++;
我們把回圈變數的增值運算式放到下面來看看:

20雖然沒有列印,但是后面的21也沒有列印是因為,回圈變數的增值運算式放在后面進行的,一旦i等于20,就直接跳過本次回圈了,后面的陳述句就不會執行,所以i==20不會被改變的,注意這一點,
咱們看幾道練習題:
#include <stdio.h>
int main()
{
int c = 0;
while((c=getchar())!=EOF)
{
putchar(c);
}
return 0;
}
//2
int main()
{
int c=0;
while((c=getchar())!=EOF)
{
if(c<'0'||c>'9')
{
continue;
}
putchar(c);
}
}
大家看到這兩段代碼是不是很陌生?getchar是是啥?getchar是獲取字符的意思,也可理解為輸入字符的意思,跟輸入陳述句有點類似,那與之相對應的輸出字符就是putchar,那EOF又是啥呢?EOF是end of file的縮寫,也就是檔案結束標志,跟字串的‘\0’有點相似,我們看它是怎么定義的:

使用define定義的,實際上是-1,那整段代碼是什么意思呢?getchar讀取失敗的時候會回傳EOF,如果讀取字符不等于EOF就進入回圈,然后列印字符,

可以看見確實輸出了我們輸入的字符,那我們要怎樣才能結束回圈能?Ctrl+Z就可以結束了,那getchar是怎樣讀取字符的呢?是直接從鍵盤上讀取嗎?其實并不是,在getchar和鍵盤之間有一個緩沖區,程式剛開始,緩沖區是空的,需要輸入資料到緩沖區,比如我們輸入字符A然后回車,其實回車也算字符,回車也就是\n,所以會把字符A和\n一起放進緩沖區,然后getchar去讀取字符,讀取字符A放到變數c,然后在螢屏上列印字符A,這時緩沖區只剩下\n,然后getchar繼續讀取,讀取到\n就換行了,然后此時緩沖區就空了,需要繼續輸入字符,這也是后面游標在閃的原因,

那代碼2又是什么意思呢?我們知道了代碼1是輸入字符然后再列印字符,那中間加了一個判斷陳述句,很顯然就是只會列印‘0’~'9'

判斷條件是如果c小于字符0或大于字符9就跳過本次回圈,因為有continue關鍵字嘛,所以只有輸入字符0到字符9之間的任意數都可以在螢屏上列印相對應的字符,這是這兩題的決議,那我們知道這種代碼有什么用呢?我們看個實體:
#include <stdio.h>
int main()
{
char password[10]={0};
int c = 0;
printf("請輸入密碼:");
scanf("%s",password);
printf("請確認密碼(Y/N):\n");
c = getchar();
if(c == 'Y')
{
printf("確認成功\n");
}
else
{
printf("確認失敗\n");
}
return 0;
}
運行結果:

我還沒開始輸入確認與否呢,它直接來一句確認失敗,這不玩兒呢?還記得我們之前畫的那張圖嘛?決議:
程式開始我們輸入:
123456+回車鍵,這就相當于在緩沖區放了123456+\n,我們輸入陳述句scanf會把我們輸入的字串給拿走放到password里去,但是\n還在緩沖區,此時getchar就會去緩沖區里讀取\n所以后面判斷條件是假的,
那我們該咋辦呢?
思路:既然緩沖區還有\n那我們再用一個getchar來讀取這個字符

emmmm確實是可以,但是如果我們如果輸入其他字串呢?比如說中間有空格鍵之類的:

這是為啥呢?不就是加了個空格嗎?這跟scanf函式有關了,scanf函式碰到空格就不會繼續去字符了,這樣緩沖區就還剩下空格加 123然后getchar讀取一個字符空格,后面再判斷,判斷條件也會為假,所以程式結果如圖上所示,使用了幾次scanf陳述句,我來解釋一下scanf的用法:
int i = 0; scanf("%d",&i);//%d以十進制的形式輸入 &i是取i的地址 &是scanf中必須要使用的 上面代碼沒有使用是因為陣列名是陣列首元素的地址使用可以不加&符號,
那我們怎樣解決呢?
思路:既然getchar陳述句是一個一個的讀取,而且我們輸入之后都會按回車鍵(\n),那我們可以使用回圈的方式來讀取后面的字符,如果是\n就跳出回圈,然后再判斷是否需要確認密碼,我們把回車給干掉,這樣也相當清理緩沖區,

如果我們在做題的時候可能會碰到類似的題目,當我們碰到這種題的時候要記住還有個緩沖區的存在,
for回圈
我們已經知道while回圈了,在C語言中還有個常用的另外一個回圈 ---- for回圈,流程圖如圖所示:

畫的不好大家見諒哈,
首先看for回圈的語法:
語法:
for(運算式1;運算式2;運算式3)
{
回圈陳述句;
}
//運算式1為初始化部分,用于初始化回圈變數的,
//運算式2為條件判斷部分,用于判斷回圈時候終止,
//運算式3為調整部分,用于回圈條件的調整,
用法:
#include <stdio.h>
int main()
{
int i = 0;
// 初始化 條件判斷 回圈變數調整
for(i = 1; i < 11; i++)
{
printf("%d ",i);
}
return 0;
}
這段代碼會列印出什么呢?
初始化:i = 1,條件判斷:i < 11為真進入回圈 回圈陳述句: 列印1 回圈變數調整: i++
i = 2 i < 11 列印2
.....
i = 10 i < 11為真 列印10 i++
i = 11 i < 11為假 不進入回圈
經過分析代碼,想必大家也知道這段代碼會列印什么了吧,沒錯就是1~10,在for回圈中也可以使用break和continue陳述句,作用都是一樣的,但是continue有點不一樣:

它不會像while回圈那樣會出現死回圈,因為它調整部分是在外邊進行的,跳過里面的陳述句回傳到上面的調整部分,
continue在for回圈中跳過本次回圈,后面的陳述句不執行,直接跳到調整部分,
for回圈的回圈控制變數
1.不可在for回圈體內修改回圈變數,防止for回圈失控,造成死回圈,
2.建議for陳述句回圈控制變數的取值采用“前閉后開區間”寫法,
試下第一條:

這樣就造成了死回圈,所以我們在使用for回圈是千萬不要再回圈體內改變回圈變數的值,
第二點是什么意思呢?我們可以使用一個陣列來說明一下:
#include <stdio.h>
int main()
{
int arr[10]={0};
int i = 0;
for(i=0;i<10;i++)//這就是前閉后開的寫法 當然也可以寫成for(i=0;i<=9;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
前閉后開,大家應該有聽說過這個數學中有學過前閉后開就是前面等于后面小于或大于的寫法,比如上面的前閉后開在數學的寫法就是[0,10),大于等于0小于10,雖然也可以寫作前閉后閉區間,但是寫成這樣的形式更直觀,一眼就能看出是回圈多少次,
看下面代碼結果是什么呢?
#include <stdio.h>
//1
int main()
{
for(;;)
{
printf("hello\n");
}
return 0;
}
//2.
int main()
{
int i,j;
for(i=0,j=0;i<3&&j<5;++i,j++)//++i或者i++都可以不影響
{
printf("hello\n");
}
return 0;
}
代碼1

- 結果是死回圈列印hello
- 雖然說for陳述句中初始化、條件判斷、調整3部分都能省略,但是判斷部分省略會導致程式死回圈,因為判斷部分省略會導致判斷部分恒為真,
- 除非特殊要求,否則不要省略,
再換個代碼把上面改一下:
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
for(;i<3;i++)
{
for(;j<3;j++)
{
printf("hello\n");
}
}
return 0;
}
那這樣結果是什么呢?

為什么?
i = 0; i < 3為真 : j = 0; j < 3為真;列印hello;j++ j = 1 ; j < 3為真;列印hello; j++; j = 2;j<3為真 列印hello; j++; j = 3 ;j < 3為假 不進入回圈;i++;
i = 1;i < 3為真;j = 3;j < 3為假 不進入回圈,i++
....
除非要求需要,不然還是不要輕易省略for陳述句的三部分的任意部分,
代碼2:

- 結果只列印3次hello
- i = 0;j = 0; i小于3并且j小于5,條件為真進入回圈列印hello
- i = 1;j = 1;條件依然為真 列印hello
- i = 2;j = 2;條件依然為真 列印hello
- i = 3;j = 3;條件為假,不列印 跳出回圈,
- 初始化、判斷、調整這三部分可以是一條陳述句也可以是多條陳述句,
看一道習題:
//請問回圈幾次?
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
for(i=0,j=0;j=0;i++,j++)
j++;
return 0;
}
回圈幾次呢?其實一眼就能看出,回圈0次,為什么呢?因為壓根兒就不會進入回圈,條件判斷部分是賦值,把0賦給j,然后j是0,0為假所以不會進入回圈,
do...while回圈
前兩個回圈是不是都要先判斷才能進入回圈,這個回圈可就不一樣了,它允許先執行然后再判斷是否還需執行,先執行再判斷,流程圖:

語法
do
{
回圈陳述句
}while(運算式);//判斷
特點
回圈至少執行一次,使用場景有限制,所以很少看見do...while的使用,
使用
列印1~10:
#include <stdio.h>
int main()
{
int i = 1;
do
{
printf("%d ",i);
i++;
}while(i<11);
return 0;
}

- 該回圈無論如何一上來就會列印i,然后再接著判斷是否小于11,是的話就會接著執行回圈,
再試試break和continue在do...while回圈中是怎么樣的:
#include <stdio.h>
int main()
{
int i = 1;
do
{
if(5 == i)
break;
printf("%d\n", i);
i++;
}while(i<=10);
return 0;
}
//2
int main()
{
int i = 1;
do
{
if(5 == i)
continue;
printf("%d\n", i);
i++;
}while(i<=10);
return 0;
}
代碼1:

正常跳出回圈,
代碼2:

死回圈了,跟while回圈有點類似,
break:跳出break所在的回圈體,終止回圈,
continue:跳過本次回圈continue后面的陳述句,直接進入下一次回圈,
練習題
- 計算 n的階乘,
- 計算 1!+2!+3!+……+10!
- 在一個有序陣列中查找具體的某個數字n, 撰寫int binsearch(int x, int arr[], int n); 功能:在arr[0]
<=arr[1]<=arr[2]<= ….<=arr[n-1]的陣列中查找x. - 撰寫代碼,演示多個字符從兩端移動,向中間匯聚,
- 撰寫代碼實作,模擬用戶登錄情景,并且只能登錄三次,(只允許輸入三次密碼,如果密碼正確則提示登錄成,如果三次均輸入錯誤,則退出程式 ,
計算n的階乘
階乘怎么算?階乘就是 n * n-1 * n-2 * n-3*...*1,那不就是1乘到n嘛,代碼如下:
#include <stdio.h>
int main()
{
int i = 0;
int n = 0;
scanf("%d", &n);
int t = 1;
for (i = 1; i <= n; i++)
{
t *= i;
}
printf("%d ", t);
return 0;
}
運行結果:

思路:
階乘就是1 * 2 * ....* n,那么我們用回圈,弄出1~n的數字,然后再定義一個變數t=1,然后用t去成 1 ~ n的每一個數字,從而得到最后的結果,
計算1!+....+10!
計算1!+~10!,我們之間有計算了n的階乘,那我們在計算n的階乘之上再嵌套一層回圈是不是就可以解決了?
#include <stdio.h>
int main()
{
int i = 0;
int t = 1;
int sum = 0;
for(i=1;i<=10;i++)
{
int j = 0;
for(j=1;j<=i;j++)
{
t *= j;
}
sum+=t;
}
printf("%d",sum);
return 0;
}

思路:
要求1 ~ 10的階乘和,那么算出每個數的階乘然后再相加在一起就可以了,首先一層回圈控制1 ~ 10的數字,這下數字出來了,然后再定義一個回圈,回圈的初始化為1,第二個回圈用來計算階乘,定義一個變數t,賦值為1,這樣每次相乘都是1去乘j的值,不會出現像計算完2的階乘后,用2的階乘的值再去計算3的階乘,這樣會出錯的,所以在回圈內部定義變數t,這樣階乘后在相加在一起,就可以得到1的階乘加到10的階乘了,
這種求法效率比較低,我們可以優化一下它
4! = 4 * 3 * 2 * 1; = 4*3!
3!= 3 * 2 * 1;=3*2!
2!= 2 * 1;=2*1!
通過觀察我們發現n!會等于n * n-1!,那我們可以用一個回圈就能搞定:
#include <stdio.h>
int main()
{
int i = 0;
int ret = 1;
int sum = 0;
for(i=1;i<=10;i++)
{
ret *= i;//ret=1*1; ret=1 * 2; ret = 2 * 3; ret = 6 * 4;..........
sum += ret;//sum=0+1;sum=1+2;sum=3+6;.....
}
printf("%d",sum);
return 0;
}

很明顯這種方法效率高,
<span id = “3">查數
在有序數列中查找一個數字,這題挺簡單,我們暴力求解就好了:
#include <stdio.h>
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
int x = 6;
int sz = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for(i=0;i<sz;i++)
{
if(x==arr[i])
{
printf("找到了,下標是%d",i);
break;
}
}
if(sz==i)
{
printf("找不到\n");
}
return 0;
}

思路:
我們在一組數字中找一個數首先我們得知道這組數字有多少個,然后再一個一個的去比對,匹配成功就說明找到了,并且退出回圈,如果一組數字全部比對完了都沒有找到那就是找不到了,
其實還有個更優化的演算法,既然是有序的一組數字,那么我先拿這個需要被查找的數字跟最中間的那個數字去做比對,這樣就可以省掉一大半的資料去比對了,如果要查找的數字比中間那個數字要大,那左邊的一半數字可以扔掉不要了,繼續在后面的數字中尋找,然后再用這個方法去比對,最終只剩一個數字再比對,如果沒有那就找不到了,這種方法被稱為 二分查找法,寫成代碼又是怎么樣的呢?
#include <stdio.h>
int main()
{
int arr[]={1,2,3,4,5,6,7,8,9,10};
int x = 6;
int sz = sizeof(arr)/sizeof(arr[0]);
int left = 0;
int right = sz - 1;
while(left<=right)//只有坐下標小于或者是等于右下標時候回圈才能進行,不然找不了
{
int mid = (left+right)/2;
if(x > arr[mid])
{
left = mid+1;
}
else if(x < arr[mid])
{
right = mid -1;
}
else
{
printf("找到了,下標為%d",mid);
break;
}
}
if(left > right)
{
printf("找不到\n");
}
return 0;
}
我們看看實際效果:

是不是就找到了呢?這種方式是不是效率更高了,其實大家也可以拿一張紙,在上面寫上一組有序的數字,然后把紙折半去找,這樣大家會有更深刻的理解,
<span id = “4">多個字符從兩端向中間匯聚
首先我們要明白題目的含義,知道是什么意思,多個字符從兩端向中間匯聚大概就是以下情況:

這樣的話要怎么做呢?我們可以定義兩組陣列,一組存#########另一組存放welcome to China!!!!,因為我們使用的是字串,所以需要使用字串函式求出字串的長度,然后使用回圈,一次把兩端的字符放進##陣列里去,然后列印,然后兩端的下標一加一減,慢慢向中間靠近,就可以列印出這種效果了:
#include <stdio.h>
int main()
{
char arr1[]="####################";
char arr2[]="welcome to China!!!!";
int left = 0;
int right = strlen(arr2)-1;//strlen是求字串長度 需要引頭檔案string.h
while(left<=right)
{
arr1[left]=arr2[left];
arr1[right]=arr2[right];
printf("%s",arr1);
Sleep(1000);//列印完后停留一會,讓我們能更清楚的看是怎樣變換出來的,需要引頭檔案Windows.h
system("cls");//清空螢屏
left++;
right--;
}
printf("%s",arr1);
//for回圈版
for(left=0,right=strlen(arr2)-1;left<=right;left++,right--)
{
arr1[left]=arr2[left];
arr1[right]=arr2[right];
printf("%s",arr1);
Sleep(1000);//列印完后停留一會,讓我們能更清楚的看是怎樣變換出來的,需要引頭檔案Windows.h
system("cls");//清空螢屏
}
return 0;
}

我把所有的都列印出來更直觀點,
模擬登錄
只允許輸入三次密碼,如果密碼正確則提示登錄成功,如果三次均輸入錯誤,則退出程式,
思路:
創建兩個字符陣列,用回圈加判斷結構
易錯點:字串相比較不能直接用==,而是要用字串比較函式strcmp,strcmp(str1,str2),回傳值為0就相等,
#include <stdio.h>
int main()
{
char password[]="admin";
char str[10];
int i = 0;
for(i=0;i<3;i++)
{
printf("請輸入密碼:");
scsanf("%s",str);
if((strcmp(str,password))==0)
{
printf("密碼正確,登錄成功\n");
break;
}
else
{
printf("密碼錯誤,請重新輸入,只有3次機會哦\n");
}
}
if(3==i)
{
printf("機會用完,退出程式\n");
exit(0);//exit是退出程式陳述句
}
return 0;
}

提一下字串比較函式是怎么比較的:
char str1[]=“abcde”;
char str2[]=“abcdf”
在使用strcmp在比較str1和str2的時候,從左到右依次比較每個字符,比較的是字符的ASCII碼值,前4個都是相同的都相等,但是‘e’ 和‘f’就不一樣,e的ASCII碼值是101,f的ASCII碼值是102,所以str1<str2,strcmp回傳的就是小于0的值,
猜數字游戲
學了這么多知識了,我們來玩個游戲吧,猜數字,我們輸入一個數字,程式會提醒我們輸入的數字是大了還是小了,直到我們猜中這個數字,
游戲邏輯:
- 電腦自動生成1~200之間的數字,
- 猜數字
- 猜對了,游戲結束,
- 猜錯了,繼續猜直到猜對為止,
實作程式思路:
- 程式一開始首先列印一個簡單的選單,讓用戶好選擇,
- 因為程式無論如何都會執行一次,所以用do....while回圈,因為有選單所以要有選擇,用Switch來判斷進入哪個環節
- 游戲開始后,要生成1~200之間的亂數
- 接著才游戲,然后判斷猜的數字與隨機生成的數字是否相等,可以用個死回圈,猜中了就提示游戲結束,退出至選單頁面,
難點在生成1~200之間的亂數上,
產生亂數
生成亂數的函式是rand函式,頭檔案<stdlib.h>,rand函式回傳值是整型,rand函式回傳的是0~32767的數字,但是在呼叫rand函式之前需要使用srand函式設定亂數的生成器,就是在rand函式之前需要使用srand函式,srand函式設定一個隨機的起點,需要的引數是個unsigned int無符號整型數字,而srand函式引數如果是一個定值的話,那亂數都是一樣的,所以srand函式中要給個變得值,我們可以傳一個可變化的量 ---時間 ,時間傳進去的實際上是時間戳,怎么獲取時間戳呢?用time函式,給time函式傳個NULL空指標,time函式回傳的是也是整型,而srand需要的是一個unsigned int所以強制型別轉換成unsigned int型別,time函式需要頭檔案<time.h>
srand = ((unsigned int)time(NULL));,我們整個工程中只需要設定一次亂數就可以了,因為需要的是1~200的亂數,所以我們讓rand生成的亂數%200,因為%200的余數是0 ~ 199,我們加上1,就得到了1~200的亂數了,
參考代碼:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("******************************************\n");
printf("************ 1. play ***************\n");
printf("************ 0. exit ***************\n");
printf("******************************************\n");
}
void game()
{
int ret = rand()%200+1;
int k = 0;
while(1)
{
printf("請輸入猜的數字:");
scanf("%d",&k);
if(k<ret)
{
printf("數字小了\n");
}
else if(k > ret)
{
printf("數字大了\n");
}
else
{
printf("恭喜你猜中了\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned int) time(NULL));
do
{
menu();
printf("請輸入選擇:");
scanf("%d",&input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤\n");
}
}while(input);
return 0;
}
代碼效果:

goto陳述句
C語言中提供了可以隨意濫用的 goto陳述句和標記跳轉的標號,
從理論上 goto陳述句是沒有必要的,實踐中沒有goto陳述句也可以很容易的寫出代碼,
但是某些場合下goto陳述句還是用得著的,最常見的用法就是終止程式在某些深度嵌套的結構的處理程序,例如一次跳出兩層或多層回圈,
這種情況使用break是達不到目的的,它只能從最內層回圈退出到上一層的回圈,寫個程式舉個例子:
#include <stdio.h>
int main()
{
flag:
printf("hello\n");
printf("world\n");
goto flag;
return 0;
}
執行順序是:首先進入主函式,然后兩端輸出函式,flag不用它,走到goto 陳述句時,它會跳轉到flag的位置開始執行,然后接著執行到goto陳述句,就造成了死回圈,
再比如寫個關機程式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//關機命令 60秒后自動關機
system("shutdown -s -t 60");//system()執行系統命令函式 參考頭檔案<stdlib.h>
char arr[20]={0};
again:
printf("請注意,你的電腦將1分鐘內關機,如果輸入:我是小豬豬,就關機");
scanf("%s",arr);
if((strcmp(arr,"我是小豬豬"))==0)
{
system("shutdown -a");
}
else
{
goto again;
}
return 0;
}


其實我們用回圈也可以實作這個功能的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//關機命令 60秒后自動關機
system("shutdown -s -t 60");//system()執行系統命令函式 參考頭檔案<stdlib.h>
char arr[20]={0};
while(1)
{
printf("請注意,你的電腦將1分鐘內關機,如果輸入:我是小豬豬,就關機");
scanf("%s",arr);
if((strcmp(arr,"我是小豬豬"))==0)
{
system("shutdown -a");
break;
}
}
return 0;
}
實際上goto陳述句使用的場景是:
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error;
}
}
…
error:
if(disaster)
其實在我們自己寫程式的時候很少會用到goto陳述句的,大家知道這個陳述句就可以了,要是真的要使用的話,查一下資料也會的,
數字炸彈游戲
我自己寫了一個數字炸彈游戲不知大家有木有玩過呀?其實就是猜數字和關機程式的結合,學完之后自己也突發奇想之前有玩過這種游戲所以嘗試一下自己寫這個游戲,參考代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void menu()
{
printf("******************************************\n");
printf("***********歡迎來到數字炸彈游戲!!*********\n");
printf("************ 1. play ***************\n");
printf("************ 0. exit ***************\n");
printf("******************************************\n");
}
void game()
{
int ret = rand() % 200 + 1;
int guess = 0;
char str[20] = { 0 };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("請輸入猜的數字:\n");
scanf("%d", &guess);
if (guess > ret)
{
printf("數字大了\n");
}
else if (guess < ret)
{
printf("數字小了\n");
}
else
{
printf("恭喜你猜中了!\n");
}
}
if (5 == i)
{
printf("你輸了!作為懲罰你的電腦將在1分鐘后關機!!!\n");
system("shutdown -s -t 60");
}
printf("如果你想繼續玩耍,就輸入“我是小豬豬”,只有3次機會哦!\n");
for (i = 0; i < 3; i++)
{
printf("請輸入:\n");
scanf("%s", str);
if ((strcmp(str, "我是小豬豬")) == 0)
{
system("shutdown -a");
break;
}
}
if (3 == i)
{
printf("機會用完了哦,1分鐘后關機\n");
system("shutdown -s -t 60");
exit(0);
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請輸入選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤\n");
}
} while (input);
return 0;
}
有哪些知識點沒講好的大家見諒哈,菜鳥報道哈哈哈哈,大家一起加油呀!!!謝謝大家的收看!!!阿里嘎多,
荊軻刺秦王
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/383987.html
標籤:C
下一篇:Goland的那些實用技巧
