目錄
循環結構又稱重複結構,是按照一定的條件重複執行某段語句的程序控制結構。
基本的循環結構:
1)goto語句和if語句構成的循環結構;
2)while語句構成的循環結構
3)do-while語句構成的循環結構
4)for語句構成的循環結構
5.1 while語句
while語句用來構成當型循環,多用於解決循環次數事先不確定的問題。形式:
while(表達式)
{
循環體
}
功能:先判斷表達式值的真假,若爲真(非零)時,就執行循環體;否則,退出循環結構。
例:編程實現1+2+3+4+……+100。
#include "stdio.h"
main()
{
int a=1,sum;
sum=0;
while(a<=100)
{
sum=sum+a;
a++;
}
printf("%d",sum);
}
① 從何處來
② 到何處去
③ 如何修改循環變量在
④ 條件滿足做什麼事情
循環的初始值+循環條件+循環體+循環變量的增量+具有唯一真值的表達式
注意:
- while語句中的表達式一般是關係表達式或邏輯表達,也可以是數值表達式或字符表達式,只要其值爲真(非0)即可繼續執行循環體
- 循環體語句可以爲任意類型,循環體如果包含一個以上的語句,應該用花括號起來,以複合語句的形式出現。如果不用花括號,則while語句的範圍只到while後面第一個分號處。
- 在循環體中應該有使循環趨向於結束的語句,以避免死循環
- 允許while語句的循環體中包含另一個while語句,從而形成循環的嵌套
例:印數程序
#include "stdio.h"
main()
{
int a=0;
while(a<=1)
{
a++;
printf("%d\n",a);
}
}
while(n++<=1);
n++爲前綴式,先判斷n<=1,是否爲真後,再加1;
如果++n,則先再1,再判斷n<=1。
例:輸入一行字符,按字母、數字、和其他分成三類,分別統計各類字符的數目('\n’)不在統計範圍內。
#include "stdio.h"
#define IN 1
#define OUT 0
main()
{
int c,nl,nw,nc,state; //nc:字符數 nl:行數 //nw:字數
state=OUT;
nl=nw=nc=0;
printf("請輸入內容並以ctrl+z爲結束:\n");
while((c=getchar())!=EOF) //不等於-1,即爲真
{
++nc;
if(c=='\n')
{
++nl;
}
if(c=='\t'||c==' '||c=='\n')
{
state=OUT;
}
else
{
if(state==OUT)
{
state=IN;
++nw;
}
}
}
printf("字符數:%d\n",nc);
printf("行 數:%d\n",nl);
printf("字 數:%d\n",nw);
return 0;
}
解析:
正文一行以'\n'爲結束標誌;
一個字以''爲結束標誌的一串字符;
EOF是End Of File的意思,在C語言中定義的一個宏,用作文件結束標誌。從數值角度看,就是-1。從一個終端的輸入從來不會真的“結束”(除非設備被斷開),但把從終端輸入的數據分區成多個“文件”卻很有用,因此一個關鍵的序列被保留下來來指明輸入結束
行數統計:對輸入中的'\n'字符進行統計;
字數統計:對空格符''、製表符'\t'、換行符'\n'
字符數統計:對每個輸入的字符(不包含EOF)進行計數;
算法:
(1)將標誌位state置爲初值0,表示字符不在子字,各計數器變量均爲0;
(2)讀一個字符c,如果不是EOF,則進行:
① 字符數+1;
② 若c是行數則行數+1;
③ 若c是空格符、換行符、製表符,則將標誌置爲0,表示c字符不在字中;
若c爲非空白符,如果標誌位爲0(表示c是字符的第一個字符)則將字數+1,並修改標誌位爲1(表示當前字符c是一個字中的字符)
④ 循環步驟2
⑤ 如果c是EOF,則循環結束,轉步驟3
(3)輸出結果
窮舉法:窮舉法的基本思想是根據題目的部分條件確定答案的大致範圍,並在此範圍內對所有可能的情況逐一驗證,直到全部情況驗證完畢。若某個情況驗證符合題目的全部條件,則爲本問題的一個解;若全部情況驗證後都不符合題目的全部條件,則本題無解。窮舉法也稱爲枚舉法。
(1)順序列舉 是指答案範圍內的各種情況很容易與自然數對應甚至就是自然數,可以按自然數的變化順序去列舉。
(2)排列列舉 有時答案的數據形式是一組數的排列,列舉出所有答案所在範圍內的排列,爲排列列舉。
(3)組合列舉 當答案的數據形式爲一些元素的組合時,往往需要用組合列舉。組合是無序的。
從值域中取一個值,然後求其他兩個數,滿足條件就是解答。
5.2 do-while語句
直到型循環,多用於循環次數事先不確定的問題。
形式:
do
{
循環體
}while(表達式);
先執行一次循環體,再判斷表達式的真假。若表達式爲真(非0)則繼續執行循環體,一直到表達式爲假(0)時退出循環。
注意:while後面的“;”號不能少。
while與do-while的比較
while:先判斷後執行
do-while:先執行後判斷,語句中的循環體至少要被執行一次
當while後面的表達式的第一次的值爲真時,兩種循環得到的結果相同;否則,二者結果不相同。
5.3 for語句
可以用於循環次數已經確定的情況,也可以用於循環次數不確定而給出了循環結束條件的情況。
形式:
for(表達式1;表達式2;表達式3)
循環體
執行過程:
先求解表達式1,再求解表達式2,若真(非0),則執行for語句中指定的內嵌語句,然後求解表達式3;若表達式2爲假(0),則結束循環;循環結束,執行for語句下面的一條語句。
for(循環變量賦初值;循環條件;循環變量增值)
{
循環體;
}
一般情況,等價於:
表達式1;
while(表達式2)
{
語句
表達式3;
}
注意:
- 一般格式爲(p1;p2;p3),p1可以省略,分號不能省略;如“for(;i<=100;i++)”,省略的p1必須在for前面給予確定,即省略前給初值。
- p2可以省略,但要保留分號;這時無結束循環的條件,即循環不停地執行下去,成爲死循環。如“for(i=1,sum=0;;i++)sum=sum+i”,省略的部分必須在循環體中給出
- p3後面沒有分號,也可以省略。省略時,應在循環體內設置能改變循環變量值的語句,避免死循環。如“for(i=1,sum=0;i<=100;){sum=sum+i;i++}”
- 循環體可以是空語句,產生延時效果。如“for(i=0;i<5000;i++);”
- 雖然p1,p2,p3均能省略,但初學者不要嘗試
例:求自然數前n項和。
#include "stdio.h"
main()
{
int sum=0,i,n;
printf("請輸入:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
sum=sum+i;
}
printf("sum=%d",sum);
}
例:從鍵盤輸入10個整數,求平均值。
#include "stdio.h"
main()
{
int i;
float f,sum;
for(i=0,sum=0.0; ;i++)
{
scanf("%f",&f);
sum+=f;
if(f==0.0)
{
break;
}
}
if(i==0)
{
printf("沒有數據!");
}
else
{
printf("%f",sum/i);
}
}
例:求2000至2050之間的閏年。
#include "stdio.h"
main()
{
int i=2000;
for(i;i<=2050;i++)
{
if(i%4==0&&i%100!=0||i%100==0||i%400==0)
{
printf("%d ",i);
}
}
}
例:兔子繁殖。斐波那鍥數列。
算法分析:
① 輸入繁殖的總時間
② 繁殖的起始時間是3;1、2月數量是1
③ 從3月直到n月結束,前兩個月的總數等於第三個月
即f=f1+f2。輸出第三個月的數量即可。
#include <stdio.h>
main()
{
int n; //月(總時間)
long int f,f1,f2; //f=f1+f2
int i=3; //3月開始繁殖 起始月
f1=1;
f2=1;
printf("請輸入月:");
scanf("%d",&n);
for(i;i<=n;i++)
{
f=f1+f2; //第3項=前兩項的和
f1=f2; //放第一個數字
f2=f; //放第二個數字
printf("%5ld",f);
}
}
例:放米粒。
算法分析:
① 循環變量初值n是0;sum作爲存放器;t做爲平方變量
② n如果小於64,則向sum中放入數,t再此基礎乘2,作爲平方變量。
注意:sum、t應用double類型,數據較大
#include "stdio.h"
main()
{
int n; //循環變量
double sum,t;
sum=0.0;
t=1.0;
for(n=0;n<64;n++)
{
sum=sum+t;
t=t*2;
}
printf("%e",sum);
}
5.4 三種循環的比較
- 一般情況下可相互代替
- while循環結構:
- 只設置了結束循環的條件,循環體內需要設置打破循環條件而使循環趨向結束的語句。
- do-while循環和while循環相似,但do-while循環運行循環體,然後再進行循環結束條件的測試,循環體至少要執行一次
- 對於已知重複次數的循環,使用for結構更加方便、清晰。
- 僅知道循環結束的條件,不知道循環次數的用while循環和do-while循環更簡潔
5.5 循環的嵌套
算法分析:
- 輸入n
- 採用二重循環,外循環控制項目,內循環控制連乘次數
- 外循環:如果i<n(即i小於輸入的n),將連乘次數置1,控制內循環的j也置1
- 內循環:如果j<i(即j小於循環的次數),則連乘次數乘i次,用term存放結果;而i的變化取決於n的值
- 如果內循環j>i,則跳出內循環,執行sum
- 外循環控制內循環
#include "stdio.h"
main()
{
int i,j,n; //i是底;n是鍵入;j控制內循環
long sum,term; //各項之和sum;i的次方term
sum=0,i=1;
printf("請輸入n:\n");
scanf("%d",&n);
for(i;i<=n;i++)
{
term=1;
j=1;
do
{
term=term*i;
}
while(++j<=i);
sum=sum+term;
}
printf("%ld",sum);
}
例:求整數3~100中的素數。
算法分析:
- n是整數的範圍0至100;i是條件
- 外循環for,取值範圍從3循環至100
- 內循環while,判斷是否爲素數;如果是則將其輸出
#include "stdio.h"
main()
{
int n,i,a;
n=3;
for(n;n<=100;n++)
{
i=2; //i=2條件
while(n%i!=0)
{
i++;
if(i==n)
{
printf("%d ",n);
a++;
}
}
}
printf("\n個數爲:%d",a);
}
例:輸入一個字母,輸出由這個字母決定其高度的字符“金字塔”
算法分析:
- 外循環變量c1;並列內循環變量c2
- 輸入字符如果是小寫,top置爲a;大寫top置爲A;否則置爲0
- top非0;打印圖形
- ① 外循環c1控制行數;c1<=c,則輸出一行
- ② 內循環輸出4個內容:左邊所有的空格、一行前半段、一行後半段、換行
- ③ c1=c1+1,繼續輸出下一行
- c1>c,則結束循環
注意:內循環中的每一個for循環,結束後都重新開始。
#include "stdio.h"
#include "ctype.h"
main()
{
printf("請輸入字符:\n");
char c,top,c1,c2;
int i;
top=isupper(c=getchar())?'A':(islower(c)?'a':'\0');
if(top)
{
for(c1=top;c1<=c;++c1)
{
for(i=c;i>=c1+1;--i)
{
putchar('-');
}
for(c2=top;c2<=c1;++c2)
{
printf("%c",c2);
}
for(c2=c1-1;c2>=top;--c2)
{
printf("%c",c2);
}
printf("\n");
}
}
}
例:打印輸出乘法表
算法分析:
- 輸出表頭部分:*、1-9、換行
- 輸出表體
① 外循環i控制行號;初值爲1,即外循環控制行數
② 如果i<=9,就輸出一行:
輸出行號(被乘數);
列號j(乘數)從1~9;如果j>=i則輸出i*j,否則輸出空格;
換行;
繼續循環
- 如果i>9就結束
#include "stdio.h"
main()
{
int j,i; //i表示行號;j表示列
printf("%4c",'*');
for(i=1;i<10;++i)
{
printf("%4d",i);
}
printf("\n");
for(i=1;i<=9;i++)
{
printf("%4d",i);
for(j=1;j<10;++j)
{
if(j>=i)
{
printf("%4d",i*j);
}
else
{
printf("%4c",' ');
}
}
printf("\n");
}
}
多重循環的使用:
- 給與循環有關的變量賦初值:只需執行一次的賦初值操作,應放在最外層循環開始執行之前。
- 對內層循環的變量賦初值應該放在內層循環開始執行之前、外層循環的循環體內
- 內、外循環不能同名,否則將造成循環控制的混亂,導致死循環或計算結果錯誤
- 正確的書寫:在內循環中執行的所有語句必須用{}括起來組成複合語句作爲內循環體;外層循環的語句應放在內循環體之外、外循環體之中
- 不應在循環中執行的操作應放在進入最外層循環之前或最外層循環結束之後
5.6 break語句和continue語句
break和continue語句一般將其放在if語句中
break語句:
遇到break語句。循環將無條件終止,程序跳出循環結構。三種循環都可以使用break
break可跳出for{}循環
continue語句:
終止本次循環,continue語句後面的語句不執行而進入下一次循環
break語句只能跳出一重循環;
在while和do-while語句中,continue語句將使程序直接轉向條件測試處,當爲真是進入下一輪循環。
在for語句中,將首先執行循環控制變量的增值表達式,然後再判斷條件表達式,當爲真是進入下一輪循環。
例:從鍵盤輸入任意個數,求其平均值,當輸入值爲0時,計算結束。
#include "stdio.h"
main()
{
int i;
float f,sum;
for(i=0,sum=0.0; ;i++)
{
scanf("%f",&f);
sum+=f;
if(f==0.0)
{
break;
}
}
if(i==0)
{
printf("沒有數據!");
}
else
{
printf("%f",sum/i);
}
}
例:用break語句打印九九乘法表
#include "stdio.h"
main()
{
int i,j; //i控制行號;j控制列
for(i=1;i<=9;i++)
{
for(j=1;j<=9;j++)
{
if(i<j)
{
break;
}
printf("%d*%d=%-4d",i,j,i*j);
}
printf("\n");
}
}
例:輸出100以內能被7整除的數。
#include "stdio.h"
main()
{
int i,j;
for(i=1;i<=100;i++)
{
if(i%7!=0)
{
continue;
}
printf("%4d",i);
}
}
5.7 綜合案例
列舉算法
根據提出的問題,列舉所有可能的情況,並根據條件檢驗哪些是需要的,哪些是不需要的。關鍵是根據問題的性質確定判定的條件,從而對列舉的所有條件進行判斷。
試探算法
列舉量事先不知,只能從初始情況開始,往後逐步進行試探,直到滿足給定的條件爲止。
#include "stdio.h"
main()
{
int n,flag,x,k,a,b,c,d,e; //k是孩子;abced是五個小孩分到的蘋果
n=11; //n是蘋果
flag=1;
while(flag)
{
x=n;
flag=0;
for(k=1;k<=4&&flag==0;k++)
{
if((n+1)%(k+1)==0)
{
n=n-(n+1)/(k+1);
}
else
{
flag=1;
}
}
if(flag==0&&n!=11)
{
flag=1;
}
n=x+1;
}
printf("總蘋果:%d\n",x);
a=(x+1)/2;
b=(x-a+1)/3;
c=(x-a-b+1)/4;
d=(x-a-b-c+1)/5;
e=11;
printf("A=%d\n",a);
printf("B=%d\n",b);
printf("C=%d\n",c);
printf("D=%d\n",d);
printf("E=%d\n",e);
}
- 假設蘋果的數量爲x,設5個小孩分蘋果的數爲a,b,c,d,e a=(x+1)/2;b=(x-a+1)/3…
- 設當前試探點蘋果數量爲n:第k個小孩得到全部剩下蘋果的:(k+1)/1+k(k+1)/1 ;即(n+1)/(k+1)個蘋果。可被整除。
- 發完第k個小孩後,剩下的蘋果爲n-(n+1)/(k+1)=>n
- 進行4次分配,如果每次分配時均滿足其中的條件,並且剩下11個蘋果,則試探的n即爲原來的蘋果數x。
- while循環進行試探,for循環模擬4次的發放。
- 當4次模擬條件均滿足,且最後剩下11個蘋果,則當前試探的n即爲原來的蘋果數x5
密碼問題
#include "stdio.h"
main()
{
char c;
int k;
printf("請輸入k的值:");
scanf("%d",&k);
getchar();
c=getchar();
while(c!='\n')
{
if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))
{
c=c+k;
if(c>'z'||(c>'z'&&c<='z'+k))
{
c=c-26;
}
}
printf("%c",c);
c=getchar();
}
}