【例3-23】使用break語句改寫例【3-21】的程序。
在例【3-21】的循環中,if語句對一個標誌變量sign進行設置,而sign則作為判斷是否應跳出循環的標誌,可以在使用變量sign,而在if語句中直接使用break語句跳出循環。更改後的程序如下:
# include < stdio.h >
# include < string.h >
main()
{ int j,k;
char str[50];
printf("input a str:");
scanf("% s",str);
for(j=0,k=strlen(str)-1;k >j;j+ +,k- -)
break;
if(k>j)
printf("not a symmetrical string. \ n");
else
printf("a symmetrical string. \ n");
從程序中可以看出,當發現不對稱的字符時,立即跳出循環。C語言中規定,break語句隻能用於循環語句和switch語句中,不能用於其他任何語句之中。
2.continue語句
continue語句用於結束本次循環。其一般形式如下:
continue;
continue與break的區別是:continue結束本次循環,而不是結束整個循環結構,break是結束整個循環結構,不再進行循環條件判斷而continue則還要進行循環條件判斷,又可能繼續下一次循環。另外,continue語句隻能用在循環語句中,而不能用在switch和其他語句中。
使用continue語句時需注意:結束本次循環後控製轉移到什麼地方。下麵舉例說明continue的用法。
【例3-24】輸入一個串字符,統計其中小寫字母的個數。
其程序如下:
# include < stdio.h >
main()
{char c;
int num=0;
while((c=getchar())!=' \ n'){
if(c<97 | | c >122)
continue;
num+ +;
}
printf(" % d \ n",num);
}
程序接受用戶輸入的下一個字符串(以回車終止輸入),並使用循環逐一地檢查每一個字符,若發現當前字符不是小寫字母,立即使用continue結束本次循環,因而計算變量的值不增加;否則,執行整個循環體,使計數變量的值加1。
3.4.7 goto語句
goto語句是一個條件分支語句,其功能是將控製轉移到指定位置繼續執行。goto的一般格式如下:
goto 標號;
goto語句中必須有標號,當執行該語句時,控製被轉向標號所標位置的語句繼續執行。標號是一個標識符,它標識程序中的下一個特定位置。標號的構成文法同一般用戶定義標識符。標號被定義在某個執行語句的前麵。可以和該執行語句處在同一行,也可以單獨成行,處在該執行語句的上一行。被定義的標號一定以冒號結尾。它和其所標的語句之間可有一個或多個空格字符,但不許出現別的內容。標號隻能在goto語句中引用,在其他地方都不會被引用。帶標號的語句稱作標號語句。
goto語句的使用範圍隻局限於一個函數內部,也就是說,標號的作用範圍是在其所在的函數內部。因此,隻能用goto語句把控製從函數的一個位置轉到另一個位置,而不可能將控製從一個函數的某點轉到另一函數的指定位置。goto在程序中最常見的用法有兩種:一是實現控製從多重循環內部退出;二是構成循環。
在結構化程序設計中,不提倡使用goto語句,因為控製的自由分支會使程序的基本結構受到破壞,從而降低程序的可讀性和可維護性。但是,在有些特定情況下,使用goto又為程序設計帶來方便和提高程序執行速度。因此,隻能有節製地使用它。下麵是表示goto語句作用的例子。
【例3-25】用戶輸入一串字符,以' \ n '作為結束標誌,請使用goto語句跳出循環。
其程序如下:
# include < stdio.h >
main()
{ char c;
printf("input a $");
do{
scanf("% c",& c);
if(c = = ' \ n')
goto end;
}while(1);
end:
printf("end! \ n");
}
顯然,可以使用break語句或更改for語句中的循環結束的條件來去掉goto語句。
【例3-26】利用goto語句構成循環,計算:12+22+32+42+…202。
其程序如下:
# include < stdio.h >
main()
{int k=1;
long result=0;
loop:
result + = k* k;
k+ +;
if(k < =20)
goto loop;
printf("result: % ld \ n",result);
}
由於for循環、while循環、do-while循環能圓滿而方便地解決所有的循環問題,所以由goto語句構成循環的方法並不經常使用。
3.5 結構化程序舉例
【例3-27】將小於n的所有個位不等於9的素數在屏幕上打印出,n的具體值由用戶輸入來確定。素數即為隻能被1和本身整除的整數。要求每行輸出10個數,分行輸出。
分析:可以使用循環從2到n逐一檢查每一個數i,在循環體中判斷其是否滿足“是素數且個位不等於9”的條件,判斷數i是否是素數時,可以再使用一個內層循環,從2到i -1逐一檢查每一個數是否是它的約數,若都不是,則證明其為素數。然後,使用表達式i %10求出i的個位的數字(注:請讀者自己考慮兩個問題,一是是否需要逐一檢查從1到n的每一個數,二是判斷i是否為素數時檢查約婁得否有必要從1循環到i-1)。
其程序如下:
# include < stdio.h >
main()
{ long int n;
int line=0;
printf(" \ n please input n:");
scanf(" % d",& n);
if(n < =1)
{printf("No number to output ! \ n");
return(1);
}
{printf("No number to output ! \ n");
return(1);
}
for(int i=2;i< =n;i+ +) / *逐一地判斷各個數是否是素數 * /
{for(int j=2;j
if(i/j= =i) / * 若此數有約數.* /
break;
if(j= =i &&i%10! =9) / 若此數為素數且個數不等於9. / *
{printf(" % d,",i);
line + +;
if(line= =10)
{printf(" \ n");
line=0;
}
}
}
return(1);
}
【例3-28】編程求0~9的有一個數字x、y、z使其滿足:xyz+zyx=123(注:xyz指由x、y、z在三個數字組成的三位數)。
算法設計:使用三重循環窮舉x、y、z在取值範圍內的所有組合,對每一種組合代入方程進行驗證。其程序如下:
# include < stdio.h >
main()
{int i,j,k;
for(i=1;i< =9;i+ +)
{for(j=0;j< =9;j+ +)
{for(k=0;k< =9;k+ +) / * 窮舉了X,Y,Z所有的取值的組合 * /
{if(101 * i +20 * j +101 * k= =1231) / * 若滿足方程 * /
printf(" x= % d,y=% d,z=% d:xyz=%d % d % d,zyx=% d % d % d \ n",
i,j,k,i,k,k,j,i);
}
}
}
return(1);
}
【例3-29】本程序為一個菜單程序。運行時,首先顯示下一個菜單畫麵用以提示輸入操作選擇,這時,操作員從菜單上選擇一個操作(即輸入相應的代碼1,2,…),程序接收該選擇後調用相應的函數完成操作。設菜單畫麵格式如圖3-17所示,並且係統提供了select()、Insert()、update()和delete()函數,用以實現相應的操作。
圖3-17 菜單格式
算法設計:程序編製過程主要有五個方麵,即:生成菜單畫麵、提示和接收操作員選擇、判斷操作員選擇、執行相應操作和重複以上操作。其程序如下:
# include < stdio.h >
void insert(),select(),delete(),update();
main()
{
char op; / * generate menu * /
printf(" \ n* * * * * * * * * * * * * * * * * * * * * * * * * * ** * *"); / *生成菜單 */
printf(" \ n * Menu section *");
printf(" \ n * 1. Insert *");
printf(" \ n * 2. Select *");
printf(" \ n * 3. Delete *");
printf(" \ n * 4. Update *");
printf(" \ n * 5. Exit *");
printf(" \ n* * * * * * * * * * * * * * * * * * * * * * * * * * ** * *"); / *生成菜單 */
while (1) / * selection opration * /
{
printf(" \ n Please enter selection:");
scantf("% d,& op);
switch(op) / * 根據輸入,選擇分支走向 * /
{
case ' 1 ': insert();
break;
case' 2 ':select();
break;
case ' 3 ':delete();
break;
case ' 4 ':update();
break;
case' 5 ':break;
default:
printf(" \ n Selection error !");
break;
}
if(op = = ' 5 ')
break; / * 退出循環 * /
}
}
【例3-30】打印某月的日曆,已知當月共有30天,而1號是星期三。
算法設計:本題的關鍵是打印格式的控製。第一行等間隔地打印好周日至周六七個符號後,下一行開始打印日期,每一個日期與其對應的星期對齊。其中,本月1號對齊星期三,每次打印到星期六對應的那一天後換行。判斷換行的方法是:當(data+2)%7==6時換行。其程序如下:
# include < stdio.h >
main()
{ int k;
printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ n"); / * 打印前分隔符 * /
printf( " Sun Mon Tue Wed Thu Fri Sat \ n");
printf(" ");
for(k=1;k< =30;k+ +){ / * 打印日期 * /
printf( " % - 2d",k);
if((k+2)% 7 = =6) / * 打印到星期六時,換行 * /
printf(" \ n");
}
printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ n"); / * 打印後分隔符 * /
return 1;
}
【例3-31】用…公式求π的近似值,直到最後一項的絕對值小於10-6為止。
程序如下:
#include
main()
{
int s;
float n,t,pi;
t=1;pi=0;n=1.0;s=1;
while((fabs(t))>=1e-6)
{pi=pi+t;
n=n+2;
s=-s;
t=s/n;
}
pi=pi*4;
printf("pi=%10.6f
",pi);
}
運行結果為
pi= 3.141397
【例3-32】求Fibonacci數列:1,1,2,3,5,8,……的前40個數,即
F1=1 (n=1)
F2=1 (n=2)
Fn=Fn-1+Fn-2 (n≥3)
程序如下:
main()
{
long int f1,f2;
int i;
f1=1;f2=1;
for(i=1;i<=20;i++)
{
printf("%12ld %12ld ",f1,f2);
if(i%2= =0)printf("
");
f1=f1+f2;
f2=f2+f1;
}
}
運行結果為:
1 1 2 3
5 8 13 21
34 55 89 144
233 377 610 987
1597 2584 4181 6765
10946 17711 28657 46368
75025 121393 196418 317811
514229 832040 1346269 2178309
3524578 5702887 9227465 14930352
24157817 39088169 63245986 102334155
程序中在printf函數中輸出格式符用“%12 ld”,而不是用“%12d”,這是由於在第22個數之後,整數值已超過微型機的整數最大值32767,因此必須用“%ld”格式輸出。
if語句的作用是使輸出4個數後換行。因為i是循環變量,當i為偶數時換行,而i每增值1,就要計算和輸出2個數(f1,f2),因此i每隔2換一次行相當於每輸出4個數後換行。
【例3-33】判斷m是否素數。
我們采用的算法是這樣的:讓m被2到除,如果m能被2~之中任何一個整數整除,則提前結束循環,此時i必然小於或等於k(即);如果m不能被2~k(即)之間的任一整數整除,則在完成最後一次循環後,i還要加1,因此i=k+1,然後才終止循環。在循環之後判別i的值是否大於或等於k+1,若是,則表明未曾被2~k之間任一整數整除過,因此輸出“是素數”。
程序如下:
#include
main()
{
int m,i,k;
scanf("%d",&m);
k=sqrt(m);
for(i=2;i<=k;i++)
if(m%i= =0)break;
if(i>=k+1)
printf("%d is a prime number
"n",m);
else
printf("%d is not a prime number
",m);
}
運行情況如下:
17↙
17 is a prime number
【例3-34】求100~200間的全部素數。
在【例3-33】的基礎上,對本題用一個嵌套的for循環即可處理。程序如下:
#include
main()
{
int m,k,i,n=0;
for(m=101;m<=200;m=m+2)
{
if(n % 10 = =0)
printf("
");
k=sqrt(m);
for(i=2;i<=k;i++)
if(m % i = =0)break;
if(i>=k+1)
printf("%d ",m);n=n+1;
}
}
運行結果如下:
101 103 107 109 113 127 131 137 139 149
151 157 163 167 173 179 181 191 193 197
199
n的作用是累計輸出素數的個數,控製每行輸出10個數據。
【例3-35】輸入一行字符,分別統計出其中英文字母、空格、數字和其他字符的個數。
程序如下:
#include
main()
{
char c;
int letters=0,space=0,digit=0,other=0;
printf("請輸入一行字符:
");
while((c=getchar())!='
')
{
if(c>='a'&&c<='z'‖c<='A'&&c<='z')
letters++;
else if(c= =' ')
space++'
else if(c>='0'&&c<='9')
digit++;
else
other++;
}
printf("其中:字母數=%d空格數=%d數字數=%d其他字符數=%d
",letters,space,digit,other);
}
運行結果:
請輸入一行字符:
I am 16.at 156――3.↙
其中:字母數=5 空格數=4 數字數=6 其他字符數=4
【例3-36】打印出所有的“水仙花數”,所謂“水仙花數”是指一個三位數,其各位數字立方和等於該數本身。例如:153是一“水仙花數”,因為153=13+33+53。
程序代碼如下:
main()
{
int i,j,k,n;
printf(" '水仙花'數是:");
for(n=100;n<1000;n++)
{
i=n/100;
j=n/10-i*10;
k=n%10;
if(i*100+j*10+k= =i*i*i+j*j*j+k*k*k)
{
printf("%d",n);
}
}
printf("%n");
}
運行結果:
'水仙花'數是:153 370 371 407
【例3-37】一個數如果恰好等於它的因子之和,這個數就稱為“完數”。例如:6的因子為1、2、3,而6=1+2+3,因此6是“完數”。編程序找出1000以內的所有完數,並按下麵格式輸出其因子。
6 是一個‘完數’,它的因子是1,2,3.
程序代碼如下:
#define M 1000/*定義尋找範圍*/
main()
{
int k0,k1,k2,k3,k4,k5,k6,k7,k8,k9;
int i,j,n,s;
for(j=2;j<-M;j++)
{
n=0;
s=j;
for(i=1;i {
if((j%i)= =0)
{
n++;
s=s-i;
switch(n)/*將每個因子賦給k0,k1……k9*/
{
case 1:
k0=i;
break;
case 2:
k1=i;
break;
case 3:
k2=i;
break;
case 4:
k3=i;
case 5:
k4=i
berak;
case 6:
k5=i
berak;
case 7:
k6=i;
berak;
case 9:
k8=i;
break;
case 10:
k9=i;
break;
}
}
}
if(s= =0)
{
printf("%d是一個'完數'.它的因子是",j);
if(n>1)
printf("%d,%d",k0,k1);
if(n>2)
printf(",%d",k2);
if(n>3)
printf(",%d",k3);
if(n>4)
printf(",%d",k4);
if(n>5)
printf(",%d",k5);
if(n>6)
printf(",%d",k6);
if(n>7)
printf(",%d",k7);
if(n>8)
printf(",%d",k8);
if(n>9)
printf(",%d",k9);
printf("
");
}
}
}
運行結果:
6 是一個'完數',它的因子是1,2,3
28 是一個'完數',它的因子是1,2,4,7,14
496 是一個'完數',它的因子是1,2,4,8,16,31,62,124,248
3.6 小 結
(1)算法就是處理問題的方法和步驟。在編寫程序之前首先要進行算法設計。任何一個算法必須具有“有窮性、確定性、有效性、有0個或多個輸入和有一個或多個輸出”等特征。算法有三種基本結構:順序、分支和循環。任何一個程序都可由這三種基本結構組成。
(2)C語言提供了四類語句:控製語句、表達式語句、空語句和複合語句。控製語句有if、for、while、do-while、continue、break、switch、goto和return等九個語句。
(4)表達式語句是用分號結尾的表達式。C語言表達式的多樣性,也就決定了表達式語句的多樣性。函數調用語句也屬表達式語句。
(5)空語句是隻包含一個分號的語句。
(6)複合語句是由花括號括起來的一段程序,它可以包含說明部分,複合語句又叫局部程序塊或分程序。
(7)C語言提供了if和switch兩種語句來實現分支結構。if語句還有if、if-else和if-else if三種形式,其中,if-else是最基本的形式。if後麵的表達式不限於關係表達式或邏輯表達式,可以是任意表達式。if語句可以嵌套,在嵌套的if中,else子句總是與前麵最近的還沒else的if相配對。if-else if語句是if-else語句嵌套的簡化表示形式,用它可以方便地實現多分支結構。
switch語句用於實現多分支結構,如果有兩個以上基於同一個數字型變量的條件表達式時,選用switch要比選用if更好。
(8)C語言提供了while、for、do-while三種語句來實現循環結構。for語句功能最強、更靈活、使用最多。for和while語句是先判斷後執行循環體,而do-while則是執行一次循環體後才判斷。
(9)break語句用於結束其所在的switch分支結構或循環結構,continue語句用於結束本次循環。
(10)goto語句用於使控製轉向指定點執行,在結構化程序設計中要求有節製地使用goto語句。
習 題
1.在C語言中,有哪幾種基本結構?
2.編寫程序,從鍵盤上輸入4個整數,輸出其中最小的一個。
3.求12/(1+1)+22/(2+1)+32/(3+1)+……+n2/(n+1)的值,n由用戶確定。請使用兩種以上的不同循環分別編寫本題。
4.編寫程序,輸入一個字符串,將其中的空格和數字刪除後輸出。
5.編寫程序,打印出sinx在-1800~1800之間的值,要求每100計算一次,結果以下列形式輸出,要求:每輸出10行停頓一次,按下回車鍵後繼續執行。
sin:
-180-------------------------xxx
-170-------------------------xxx
…………………………………………