第三章C語言程序的控製結構(3 / 3)

【例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

…………………………………………