C語言程序設(shè)計(jì)項(xiàng)目化教程課件第6章_第1頁
C語言程序設(shè)計(jì)項(xiàng)目化教程課件第6章_第2頁
C語言程序設(shè)計(jì)項(xiàng)目化教程課件第6章_第3頁
C語言程序設(shè)計(jì)項(xiàng)目化教程課件第6章_第4頁
C語言程序設(shè)計(jì)項(xiàng)目化教程課件第6章_第5頁
已閱讀5頁,還剩145頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

提高篇

本篇以學(xué)生成績(jī)統(tǒng)計(jì)項(xiàng)目為背景,學(xué)習(xí)函數(shù)、數(shù)組和指針的內(nèi)容。該項(xiàng)目分解為四個(gè)子任務(wù),分別貫穿于第6章至第8章中進(jìn)行分析和實(shí)現(xiàn)。通過本篇的學(xué)習(xí),學(xué)生應(yīng)掌握分析問題和解決問題的思路和方法,并能靈活運(yùn)用函數(shù)、數(shù)組和指針編寫程序,解決科學(xué)計(jì)算和工程設(shè)計(jì)中的一般性問題。學(xué)生成績(jī)統(tǒng)計(jì)項(xiàng)目概述

一、項(xiàng)目涉及知識(shí)要點(diǎn)項(xiàng)目涉及的知識(shí)點(diǎn)主要包括程序的三種基本結(jié)構(gòu)、函數(shù)、數(shù)組和指針等內(nèi)容。其中程序的三種基本結(jié)構(gòu)已在第一篇中進(jìn)行了介紹,在此不再重復(fù)。函數(shù)、數(shù)組和指針三部分的知識(shí)將在第6章至第8章中詳細(xì)介紹。二、項(xiàng)目主要目的和任務(wù)該項(xiàng)目主要鞏固和加深學(xué)生對(duì)C語言基本知識(shí)的學(xué)習(xí),使學(xué)生理解和掌握模塊化程序設(shè)計(jì)的基本思想和方法,掌握數(shù)組和指針的定義和應(yīng)用,培養(yǎng)學(xué)生利用C語言進(jìn)行軟件設(shè)計(jì)的能力。

三、項(xiàng)目功能描述

該項(xiàng)目主要實(shí)現(xiàn)學(xué)生某門課程成績(jī)的統(tǒng)計(jì)。其功能包括:錄入和顯示學(xué)生成績(jī)、統(tǒng)計(jì)總分和平均分、統(tǒng)計(jì)最高分和最低分、統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)。系統(tǒng)功能模塊結(jié)構(gòu)圖如圖B-1所示。系統(tǒng)各模塊的功能說明如下:(1)密碼驗(yàn)證模塊,主要實(shí)現(xiàn)登錄密碼的驗(yàn)證工作。系統(tǒng)初始密碼為123456。(2)錄入學(xué)生成績(jī)模塊,主要實(shí)現(xiàn)學(xué)生考試成績(jī)的錄入。假設(shè)輸入的第1名學(xué)生的學(xué)號(hào)為1,第2名學(xué)生的學(xué)號(hào)為2,依次類推,最多可以錄入30個(gè)學(xué)生的成績(jī),可輸入-1結(jié)束整個(gè)錄入過程。(3)顯示學(xué)生成績(jī)模塊,主要實(shí)現(xiàn)學(xué)生成績(jī)的顯示。(4)統(tǒng)計(jì)總分和平均分模塊,主要實(shí)現(xiàn)某門課程總分和平均分的統(tǒng)計(jì),并顯示統(tǒng)計(jì)結(jié)果。(5)統(tǒng)計(jì)最高分和最低分模塊,主要實(shí)現(xiàn)某門課程最高分和最低分的統(tǒng)計(jì),并顯示統(tǒng)計(jì)結(jié)果。(6)統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)模塊,主要實(shí)現(xiàn)某門課程各分?jǐn)?shù)段人數(shù)的統(tǒng)計(jì)。要求將百分制成績(jī)轉(zhuǎn)化為優(yōu)、良、中、及格和不及格五個(gè)等級(jí),并顯示相應(yīng)的統(tǒng)計(jì)結(jié)果。(7)退出系統(tǒng)模塊,主要實(shí)現(xiàn)系統(tǒng)的正常退出。需要說明的是,學(xué)生成績(jī)統(tǒng)計(jì)系統(tǒng)重在以一個(gè)小項(xiàng)目為突破口,讓學(xué)生靈活掌握函數(shù)、數(shù)組和指針等重要知識(shí)并提升應(yīng)用能力。所以其實(shí)現(xiàn)的功能相對(duì)比較簡(jiǎn)單,所處理的學(xué)生信息也不太全面,在學(xué)習(xí)了結(jié)構(gòu)體和文件內(nèi)容之后,將給出更完善、更實(shí)用的學(xué)生信息管理系統(tǒng)。四、項(xiàng)目界面設(shè)計(jì)

1.密碼驗(yàn)證界面。在用戶登錄系統(tǒng)時(shí),要輸入密碼進(jìn)行驗(yàn)證,如圖B-2所示。2.主界面。如果密碼正確,則進(jìn)入主界面,如圖B-3所示。用戶可選擇0~5之間的數(shù)字,調(diào)用相應(yīng)功能進(jìn)行操作。當(dāng)輸入0時(shí),退出系統(tǒng)3.錄入學(xué)生成績(jī)界面。當(dāng)用戶在主界面中輸入1并按回車鍵后,進(jìn)入錄入學(xué)生成績(jī)界面,如圖B-4所示。

4.顯示學(xué)生成績(jī)界面。當(dāng)用戶在主界面中輸入2并按回車鍵后,進(jìn)入顯示學(xué)生成績(jī)界面,如圖B-5所示。5.統(tǒng)計(jì)總分和平均分界面。當(dāng)用戶在主界面中輸入3并按回車鍵后,進(jìn)入統(tǒng)計(jì)總分和平均分界面,如圖B-6所示。6.統(tǒng)計(jì)最高分和最低分界面。當(dāng)用戶在主界面中輸入4并按回車鍵后,進(jìn)入統(tǒng)計(jì)最高分和最低分界面,如圖B-7所示。7.統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)界面。當(dāng)用戶在主界面中輸入5并按回車鍵后,進(jìn)入統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)界面,如圖B-8所示五、項(xiàng)目任務(wù)分解該項(xiàng)目分解為四個(gè)子任務(wù),每個(gè)子任務(wù)及其對(duì)應(yīng)的章節(jié)如下:第6章:任務(wù)一項(xiàng)目的整體框架設(shè)計(jì)第7章:任務(wù)二用一維數(shù)組實(shí)現(xiàn)項(xiàng)目中學(xué)生成績(jī)的統(tǒng)計(jì)第7章:任務(wù)三用字符數(shù)組實(shí)現(xiàn)項(xiàng)目中的密碼驗(yàn)證第8章:任務(wù)四用指針實(shí)現(xiàn)項(xiàng)目中學(xué)生成績(jī)的統(tǒng)計(jì)第6章項(xiàng)目的整體框架設(shè)計(jì)

函數(shù)是C語言程序的基本組成單位,也是程序設(shè)計(jì)的重要手段。使用函數(shù)可以將一個(gè)復(fù)雜程序按照其功能分解成若干個(gè)相對(duì)獨(dú)立的基本模塊,并分別對(duì)每個(gè)模塊進(jìn)行設(shè)計(jì),最后將這些基本模塊按照一定的關(guān)系組織起來,完成復(fù)雜程序的設(shè)計(jì)。這樣可以使程序結(jié)構(gòu)清晰、便于編寫、閱讀和調(diào)試。在C語言程序中進(jìn)行模塊化程序設(shè)計(jì)時(shí),這些基本模塊就是用一個(gè)個(gè)函數(shù)來實(shí)現(xiàn)的。本章將結(jié)合學(xué)生成績(jī)統(tǒng)計(jì)項(xiàng)目的整體框架設(shè)計(jì),介紹C語言函數(shù)的定義和調(diào)用、函數(shù)間的數(shù)據(jù)傳遞、變量的作用域和存儲(chǔ)類型、嵌套和遞歸調(diào)用、編譯預(yù)處理等相關(guān)內(nèi)容。掌握函數(shù)的這些內(nèi)容是進(jìn)行模塊化程序設(shè)計(jì)的基礎(chǔ)。學(xué)習(xí)目標(biāo):理解和掌握“自頂向下,逐步求精”的模塊化程序設(shè)計(jì)方法;正確理解函數(shù)在程序設(shè)計(jì)中的作用和地位;掌握函數(shù)的定義和調(diào)用方法;正確理解和使用變量的作用域;正確理解和使用變量的存儲(chǔ)類型;熟悉函數(shù)的嵌套調(diào)用和遞歸調(diào)用的方法;了解編譯預(yù)處理命令的作用和特點(diǎn),掌握宏定義和文件包含處理方法。6.1任務(wù)一項(xiàng)目的整體框架設(shè)計(jì)

一、任務(wù)描述項(xiàng)目的整體框架是程序的總體結(jié)構(gòu),是程序設(shè)計(jì)中非常重要的部分。該任務(wù)要求采用結(jié)構(gòu)化編程的思想,實(shí)現(xiàn)學(xué)生成績(jī)統(tǒng)計(jì)項(xiàng)目的整體框架設(shè)計(jì)。二、任務(wù)涉及知識(shí)要點(diǎn)

該任務(wù)涉及到的新知識(shí)點(diǎn)主要有結(jié)構(gòu)化程序設(shè)計(jì)思想與函數(shù),具體內(nèi)容將在本章的理論知識(shí)中進(jìn)行詳細(xì)介紹。三、任務(wù)分析從項(xiàng)目功能描述中可知,系統(tǒng)主模塊應(yīng)包含顯示主菜單模塊、密碼驗(yàn)證模塊、錄入學(xué)生成績(jī)模塊、顯示學(xué)生成績(jī)模塊、統(tǒng)計(jì)總分和平均分模塊、統(tǒng)計(jì)最高分和最低分模塊、統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)模塊,每個(gè)模塊都定義為一個(gè)功能相對(duì)獨(dú)立的函數(shù),各函數(shù)名如下:(1)顯示主菜單模塊,函數(shù)名MainMenu()(2)密碼驗(yàn)證模塊,函數(shù)名PassWord()(3)錄入學(xué)生成績(jī)模塊,函數(shù)名InputScore(intscore[])(4)顯示學(xué)生成績(jī)模塊,函數(shù)名DisplayScore(intscore[],intn)(5)統(tǒng)計(jì)總分和平均分模塊,函數(shù)名SumAvgScore(intscore[],intn)(6)統(tǒng)計(jì)最高分和最低分模塊,函數(shù)名MaxMinScore(intscore[],intn)(7)統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)模塊,函數(shù)名GradeScore(intscore[],intn)

由于錄入、顯示和統(tǒng)計(jì)學(xué)生成績(jī)模塊均用到學(xué)生的成績(jī)信息,因此在相應(yīng)函數(shù)中用存儲(chǔ)成績(jī)信息的一維數(shù)組score[]作為形參,以接受來自主調(diào)函數(shù)中實(shí)參數(shù)組的值。

為了提高程序的可讀性,給函數(shù)起名時(shí)應(yīng)盡量做到見名知意,而且要用注釋的方法將有關(guān)函數(shù)的功能和作用一一說明,以備查閱。四、任務(wù)實(shí)現(xiàn)項(xiàng)目的整體框體如下://===========編譯預(yù)處理命令部分===========#include<stdio.h>#include<conio.h>#include<time.h>#include<string.h>#include<stdlib.h>#defineMAXSTU30//最大學(xué)生人數(shù)為30//==========函數(shù)原型聲明部分============voidPassWord();//密碼驗(yàn)證函數(shù)聲明voidMainMenu();//主菜單函數(shù)聲明intInputScore(intscore[]);//錄入學(xué)生成績(jī)函數(shù)聲明voidDisplayScore(intscore[],intn);//顯示學(xué)生成績(jī)函數(shù)聲明voidSumAvgScore(intscore[],intn);//統(tǒng)計(jì)課程總分和平均分函數(shù)聲明voidMaxMinScore(intscore[],intn);//統(tǒng)計(jì)課程最高分和最低分函數(shù)聲明voidGradeScore(intscore[],intn);//統(tǒng)計(jì)課程各分?jǐn)?shù)段人數(shù)函數(shù)聲明//=============主函數(shù)部分================main()//主函數(shù){ intstu_score[MAXSTU];//定義一維數(shù)組,存放學(xué)生某門課程的成績(jī)

intstu_count=0;//存放學(xué)生實(shí)際人數(shù)

intchoose;//定義整型變量,存放主菜單選擇序號(hào)

PassWord();//調(diào)用密碼驗(yàn)證函數(shù)

while(1) { MainMenu();//調(diào)用顯示主菜單函數(shù)printf("\t\t請(qǐng)選擇主菜單序號(hào)(0

5):"); scanf("%d",&choose); switch(choose) { case1:stu_count=InputScore(stu_score);//調(diào)用錄入學(xué)生成績(jī)函數(shù)

break; case2:DisplayScore(stu_score,stu_count);//調(diào)用顯示學(xué)生成績(jī)函數(shù)

break; case3:SumAvgScore(stu_score,stu_count);//調(diào)用統(tǒng)計(jì)總分和平均分函數(shù)

break;case4:MaxMinScore(stu_score,stu_count);//調(diào)用統(tǒng)計(jì)最高分和最低分函數(shù)break; case5:GradeScore(stu_score,stu_count);//調(diào)用統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)函數(shù)break; case0:return; default:printf("\n\t\t輸入無效,請(qǐng)重新選擇!\n"); } printf("\n\n\t\t按任意鍵返回主菜單"); getch(); }}//========各函數(shù)定義部分=======voidPassWord()//密碼驗(yàn)證函數(shù){printf("輸入密碼函數(shù)\n");getch();}voidMainMenu()//顯示主菜單函數(shù){system("cls");//清屏

printf("\n\n");printf("\t\t|-------------------------------------|\n");printf("\t\t|學(xué)生成績(jī)統(tǒng)計(jì)系統(tǒng)|\n");printf("\t\t|-------------------------------------|\n");printf(“\t\t|1---錄入學(xué)生成績(jī)|\n"); printf(“\t\t|2---顯示學(xué)生成績(jī)|\n");printf(“\t\t|3---統(tǒng)計(jì)總分和平均分|\n");printf("\t\t|4---統(tǒng)計(jì)最高分和最低分|\n");printf("\t\t|5---統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)|\n");printf(“\t\t|0---退出|\n");printf("\t\t|------------------------------------|\n");}intInputScore(intscore[])//錄入學(xué)生成績(jī)函數(shù){ printf("錄入學(xué)生成績(jī)\n");return(0);//返回錄入的學(xué)生人數(shù),現(xiàn)假設(shè)為0}voidDisplayScore(intscore[],intn)//顯示學(xué)生成績(jī)函數(shù){ printf("顯示學(xué)生成績(jī)\n"); return;}voidSumAvgScore(intscore[],intn)//統(tǒng)計(jì)課程總分和平均分函數(shù){ printf("統(tǒng)計(jì)總分和平均分\n");return;}voidMaxMinScore(intscore[],intn)//統(tǒng)計(jì)課程最高分和最低分函數(shù){ printf("統(tǒng)計(jì)最高分和最低分\n");return;}voidGradeScore(intscore[],intn)//統(tǒng)計(jì)課程各分?jǐn)?shù)段人數(shù)函數(shù){ printf("統(tǒng)計(jì)各分?jǐn)?shù)段人數(shù)\n");return;}

程序說明:(1)由于目前還沒有學(xué)到數(shù)組和字符串的內(nèi)容,所以該任務(wù)只給出了顯示主菜單函數(shù)MainMenu()的完整代碼,其他函數(shù)中僅使用了一條printf()語句,以表示能正確調(diào)用,在學(xué)習(xí)第7章數(shù)組時(shí),再完善相應(yīng)函數(shù)。(2)需要注意的是,該任務(wù)中主函數(shù)的位置在所有被調(diào)函數(shù)之前,也可以將主函數(shù)放在所有被調(diào)函數(shù)之后或兩個(gè)被調(diào)函數(shù)之間。五、要點(diǎn)總結(jié)在實(shí)際開發(fā)中,當(dāng)編寫由多函數(shù)組成的程序時(shí),一般情況下先編寫主函數(shù),并進(jìn)行測(cè)試與調(diào)試。對(duì)于尚未編寫的被調(diào)函數(shù),先使用空函數(shù)占位,以后再用編好的函數(shù)代替它,這樣容易找出程序中的各種錯(cuò)誤。切忌把所有函數(shù)編寫并輸入完再進(jìn)行測(cè)試和調(diào)試,這樣做會(huì)因程序過長(zhǎng)而不易檢查出錯(cuò)誤。可采用逐步擴(kuò)充功能的方式分批進(jìn)行,即編寫一個(gè),測(cè)試一個(gè)。6.2理論知識(shí)6.2.1結(jié)構(gòu)化程序設(shè)計(jì)思想與函數(shù)的分類一、結(jié)構(gòu)化程序設(shè)計(jì)思想結(jié)構(gòu)化程序設(shè)計(jì)是一種最基本的程序設(shè)計(jì)方法,其基本思想是“自頂向下、逐步求精”。所謂“自頂向下,逐步求精”,是指一種先整體、后局部的設(shè)計(jì)方法。即將一個(gè)較復(fù)雜的問題,劃分為若干個(gè)相互獨(dú)立的模塊,每一個(gè)模塊完成不同的功能,然后將這些模塊通過一定的方法組織起來,成為一個(gè)整體。例如,學(xué)生成績(jī)統(tǒng)計(jì)項(xiàng)目的開發(fā),先給出項(xiàng)目的整體框架設(shè)計(jì),然后再具體實(shí)現(xiàn)每個(gè)功能模塊。這種設(shè)計(jì)思想很像搭積木,單個(gè)的積木就像是一個(gè)個(gè)模塊,它們的功能單一,便于開發(fā)和維護(hù)。

在C語言中進(jìn)行模塊化程序設(shè)計(jì)時(shí),這些基本模塊就是用一個(gè)個(gè)函數(shù)來實(shí)現(xiàn)的,一般由主函數(shù)來完成模塊的整體組織。函數(shù)在一般情況下要求完成的功能單一,這樣做的好處是便于函數(shù)設(shè)計(jì)與重用。二、函數(shù)的分類C語言函數(shù)從不同的角度可以分為不同的類型。1.從用戶角度上可分為庫函數(shù)與用戶自定義函數(shù)(1)庫函數(shù)。又稱標(biāo)準(zhǔn)函數(shù)。這些函數(shù)由系統(tǒng)定義,用戶在程序中可以直接使用它們,例如前面學(xué)過的輸出函數(shù)printf()和輸入函數(shù)scanf()等都是庫函數(shù)。系統(tǒng)為我們提供了大量的庫函數(shù),為程序設(shè)計(jì)帶來極大的方便。(2)自定義函數(shù)。這些函數(shù)由用戶根據(jù)自己的需要來定義。如§6.1節(jié)任務(wù)一中的MainMenu(),PassWord()都是自定義函數(shù)。對(duì)于該類函數(shù),要先定義,然后才能使用。2.從函數(shù)自身形式上可分為無參函數(shù)和有參函數(shù)(1)無參函數(shù)。函數(shù)名后的括號(hào)中沒有參數(shù),如§6.1節(jié)任務(wù)一中的MainMenu(),PassWord()都是無參函數(shù)。調(diào)用無參函數(shù)時(shí),在主調(diào)函數(shù)與被調(diào)函數(shù)之間沒有數(shù)據(jù)傳遞。(2)有參函數(shù)。函數(shù)名后的括號(hào)中有參數(shù),如§6.1節(jié)任務(wù)一中的InputScore(intscore[]),DisplayScore(intscore[],intn)等都是有參函數(shù)。調(diào)用有參函數(shù)時(shí),在主調(diào)函數(shù)與被調(diào)函數(shù)之間有數(shù)據(jù)傳遞。6.2.2函數(shù)的定義與調(diào)用盡管C語言本身提供了眾多的庫函數(shù),但與實(shí)際應(yīng)用的需要相比,還是遠(yuǎn)遠(yuǎn)不夠的,因此,C語言允許用戶按需要定義和編寫自己的函數(shù)。對(duì)于用戶自定義函數(shù),不僅要在程序中定義函數(shù)本身,即定義函數(shù)功能,而且在主調(diào)函數(shù)中,還必須對(duì)被調(diào)用函數(shù)進(jìn)行聲明。下面將對(duì)用戶自定義函數(shù)進(jìn)行詳細(xì)介紹。一、函數(shù)的定義函數(shù)的定義就是編寫函數(shù)的程序代碼以實(shí)現(xiàn)函數(shù)的功能。下面先給出一個(gè)函數(shù)定義及調(diào)用的例子。【例6.1】編寫程序,從鍵盤輸入兩個(gè)整數(shù),求其中較大的數(shù)并輸出。#include<stdio.h>main(){ intmax(intx,inty);//聲明max()函數(shù)inta,b,result; printf("請(qǐng)輸入兩個(gè)整數(shù):"); scanf("%d,%d",&a,&b);result=max(a,b);//調(diào)用max()函數(shù),將返回值賦給result printf("兩數(shù)之中較大的數(shù)是:%d\n",result);}intmax(intx,inty)//定義max()函數(shù){ intz; if(x>y)z=x; else z=y; return(z);//返回函數(shù)值}

程序運(yùn)行結(jié)果:請(qǐng)輸入兩個(gè)整數(shù):5,9↙

兩數(shù)之中較大的數(shù)是:9

該程序由兩個(gè)函數(shù)組成,一個(gè)是主函數(shù)main(),另一個(gè)是自定義函數(shù)max(),max()函數(shù)有兩個(gè)參數(shù)x和y,其功能是求兩數(shù)之中的較大數(shù),并由return語句把所求得的較大數(shù)(函數(shù)值)返回給main()函數(shù)。為了說明方便,通常將該例中的main()函數(shù)稱為主調(diào)函數(shù),而把max()函數(shù)稱為被調(diào)函數(shù)。通過這個(gè)程序可以看出函數(shù)定義的一般形式。

根據(jù)函數(shù)是否需要參數(shù),可將函數(shù)分為有參函數(shù)和無參函數(shù)兩種,下面分別予以說明。1.有參函數(shù)的定義有參函數(shù)定義的一般形式如下:函數(shù)類型說明符函數(shù)名(形式參數(shù)說明表列){聲明部分;執(zhí)行部分;}說明:(1)第一行為函數(shù)首部;花括號(hào)中的部分為函數(shù)體,函數(shù)體由聲明部分和執(zhí)行部分組成,聲明部分用來聲明執(zhí)行部分中用到的變量和函數(shù),執(zhí)行部分用來描述函數(shù)完成的具體操作(2)“函數(shù)類型說明符”用來說明該函數(shù)返回值的類型。例如,在例6.1中max()函數(shù)的類型說明符為int,其返回值是一個(gè)整數(shù)。當(dāng)函數(shù)需要返回一個(gè)確定的值時(shí),須通過“return(表達(dá)式);”或“return表達(dá)式;”語句來實(shí)現(xiàn),其中表達(dá)式就是函數(shù)的返回值。如果沒有return語句或return語句不帶表達(dá)式,并不表示沒有返回值,而是返回一個(gè)不確定的值。若不希望函數(shù)有返回值,則其類型說明符應(yīng)為“void”,即空類型。如果函數(shù)的返回值是整型,可省略類型說明。(3)形式參數(shù)簡(jiǎn)稱形參,可以是變量、指針或數(shù)組名等,但不能是表達(dá)式或常量,各參數(shù)之間用逗號(hào)間隔。(4)函數(shù)定義不允許嵌套。在C語言中,所有函數(shù)(包括主函數(shù)main())都是平行的。在一個(gè)函數(shù)的函數(shù)體內(nèi),不能再定義另一個(gè)函數(shù),即不能嵌套定義。(5)當(dāng)一個(gè)C語言程序由多個(gè)函數(shù)構(gòu)成時(shí),必須有一個(gè)惟一的main()函數(shù)。main()函數(shù)在源程序中的位置可以任意,程序的執(zhí)行總是從main()函數(shù)開始,最終從main()函數(shù)結(jié)束。2.無參函數(shù)的定義無參函數(shù)與有參函數(shù)基本一樣,不同的只是它沒有形參(但圓括號(hào)不能省略),調(diào)用時(shí)不需要實(shí)參?!纠?.2】定義一個(gè)無參函數(shù),在屏幕上顯示“Hello,world!”。#include<stdio.h>main(){ voidhello();//對(duì)被調(diào)函數(shù)的聲明

hello();//調(diào)用hello()函數(shù)}voidhello()//定義hello()函數(shù){ printf("Hello,world!\n");}程序運(yùn)行結(jié)果:Hello,world!

該函數(shù)的類型說明為“void”,所以為無返回值的函數(shù)。另外,在定義函數(shù)時(shí),可以定義空函數(shù)。所謂空函數(shù),是指既無參數(shù)又無函數(shù)體的函數(shù)。其一般形式為:

void函數(shù)名(){}

例如:

voidempty(){}

即定義了一個(gè)空函數(shù)empty()。調(diào)用空函數(shù)時(shí),什么操作也不做,沒有任何實(shí)際作用。在程序設(shè)計(jì)中,通常將未編寫好的功能模塊用一個(gè)空函數(shù)暫時(shí)占一個(gè)位置,便于將來擴(kuò)充。二、函數(shù)的調(diào)用定義一個(gè)函數(shù)的目的是為了使用,因此要在程序中調(diào)用該函數(shù)才能執(zhí)行它的功能。

1.函數(shù)調(diào)用的一般形式

函數(shù)名(實(shí)際參數(shù)表列);

調(diào)用無參函數(shù)時(shí),圓括號(hào)不能省略。“實(shí)際參數(shù)表列”中的參數(shù)簡(jiǎn)稱為實(shí)參,它們可以是常量、變量或表達(dá)式。如果實(shí)參不止一個(gè),則相鄰實(shí)參之間用逗號(hào)分隔,并且實(shí)參的個(gè)數(shù)、類型和順序,應(yīng)該與該函數(shù)形參的個(gè)數(shù)、類型和順序一致,這樣才能正確地進(jìn)行參數(shù)傳遞

如例6.1中的函數(shù)調(diào)用語句“result=max(a,b);”,其實(shí)參個(gè)數(shù)、類型和順序,都與被調(diào)函數(shù)max()的形參所要求的個(gè)數(shù)、類型和順序一致。2.函數(shù)調(diào)用的方式按函數(shù)在程序中出現(xiàn)的位置來分,有三種函數(shù)調(diào)用方式。(1)函數(shù)語句這種方式把函數(shù)調(diào)用作為一條單獨(dú)的語句。其一般形式為:函數(shù)名(實(shí)際參數(shù)表列);

該方式常用于調(diào)用一個(gè)沒有返回值的函數(shù),函數(shù)的功能只是完成某些操作。如例6.2中的hello()函數(shù),調(diào)用方式為:

hello();

又如前面各章用到的printf()和scanf()等庫函數(shù)都是以函數(shù)語句的方式調(diào)用的。(2)函數(shù)表達(dá)式即函數(shù)作為表達(dá)式的一項(xiàng),出現(xiàn)在主調(diào)函數(shù)的表達(dá)式中,以函數(shù)返回值參與表達(dá)式的運(yùn)算。這種方式要求函數(shù)具有返回值。如例6.1中的“result=max(a,b);”是一個(gè)賦值表達(dá)式語句,它把max()函數(shù)的返回值賦予變量result。(3)函數(shù)實(shí)參函數(shù)調(diào)用作為另一個(gè)函數(shù)調(diào)用的實(shí)參出現(xiàn)。這種情況是把被調(diào)用函數(shù)的返回值作為實(shí)參進(jìn)行傳送,因此要求被調(diào)用函數(shù)必須有返回值。這種調(diào)用方式其本質(zhì)與函數(shù)表達(dá)式的調(diào)用方式相同。如例6.1中的“result=max(a,b);printf("兩數(shù)之中較大的數(shù)是:%d\n",result);”也可以合寫成“printf("兩數(shù)之中較大的數(shù)是:%d\n",max(a,b));”,即把max(a,b)函數(shù)調(diào)用的返回值作為printf()函數(shù)的實(shí)參來使用。其執(zhí)行過程是:先調(diào)用max(a,b)函數(shù),然后將其返回值作為printf()函數(shù)的實(shí)參。3.函數(shù)聲明同變量一樣,函數(shù)的調(diào)用也遵循“先聲明,后使用”的原則。前面已經(jīng)介紹過,C語言函數(shù)可分為庫函數(shù)和用戶自定義函數(shù)。因此,被調(diào)用函數(shù)有以下兩種情況:(1)調(diào)用庫函數(shù)時(shí),一般需要在程序的開頭用“#include”命令。例如,當(dāng)調(diào)用getchar()函數(shù)時(shí)要在程序的開頭加一條命令“#include<stdio.h>”;調(diào)用數(shù)學(xué)庫中的函數(shù),應(yīng)該在程序的開頭加一條命令“include<math.h>”,這是因?yàn)閷?duì)該函數(shù)的說明等一些信息包含在.h文件中。故調(diào)用某個(gè)庫函數(shù),必須包含相應(yīng)的頭文件。(2)調(diào)用自定義函數(shù),而且該函數(shù)與主調(diào)函數(shù)在同一個(gè)程序中,一般應(yīng)該在主調(diào)函數(shù)中對(duì)被調(diào)用的函數(shù)作聲明。即向編譯系統(tǒng)聲明將要調(diào)用哪些函數(shù),并將被調(diào)用函數(shù)的有關(guān)信息通知編譯系統(tǒng)。如例6.1主函數(shù)main()中的“intmax(intx,inty);”語句;例6.2主函數(shù)main()中的“voidhello();”語句,都是對(duì)被調(diào)用函數(shù)的聲明。函數(shù)聲明的一般形式為:

函數(shù)類型說明符被調(diào)函數(shù)名(類型1形參1,類型2形參2…);

或:

函數(shù)類型說明符被調(diào)函數(shù)名(類型1,類型2…);

如在例6.1的主函數(shù)中,對(duì)max()函數(shù)的聲明也可寫成如下形式:

intmax(int,int);

即在函數(shù)聲明中省略形參名,僅有形參類型。這種函數(shù)聲明形式又稱為函數(shù)原型。

C語言中規(guī)定,以下幾種情況可以省去主調(diào)函數(shù)中對(duì)被調(diào)函數(shù)的函數(shù)聲明。(1)如果被調(diào)函數(shù)的返回值是整型或字符型,可以不對(duì)被調(diào)函數(shù)聲明,而直接調(diào)用。(2)當(dāng)被調(diào)函數(shù)定義出現(xiàn)在主調(diào)函數(shù)之前時(shí),在主調(diào)函數(shù)中可以省略對(duì)被調(diào)函數(shù)的聲明而直接調(diào)用。因?yàn)橄榷x的函數(shù)先編譯,在編譯主調(diào)函數(shù)時(shí),被調(diào)函數(shù)已經(jīng)編譯,其函數(shù)首部已經(jīng)起到了聲明的作用,即編譯系統(tǒng)已經(jīng)知道了被調(diào)函數(shù)的函數(shù)類型、參數(shù)個(gè)數(shù)、類型和順序,編譯系統(tǒng)可以據(jù)此檢查函數(shù)調(diào)用的合法性,因而在主調(diào)函數(shù)中不必再聲明。(3)如果在所有函數(shù)定義之前,在函數(shù)外部(例如源文件開始處)預(yù)先對(duì)各個(gè)被調(diào)函數(shù)進(jìn)行了聲明,則在主調(diào)函數(shù)中可省略對(duì)被調(diào)函數(shù)的聲明。如例6.1可改為:#include<stdio.h>intmax(intx,inty);//聲明max()函數(shù)main(){ inta,b,result; printf("請(qǐng)輸入兩個(gè)整數(shù):"); scanf("%d,%d",&a,&b);result=max(a,b);//調(diào)用max()函數(shù),將返回值賦給result printf("兩數(shù)之中較大的數(shù)是:%d\n",result);}intmax(intx,inty)//定義max()函數(shù){ intz; if(x>y)z=x; else z=y; return(z);//返回函數(shù)值}

程序功能未發(fā)生任何變化。應(yīng)該注意,函數(shù)定義和函數(shù)聲明是兩個(gè)不同的概念。函數(shù)定義是對(duì)函數(shù)功能的確立,包括定義函數(shù)名、函數(shù)值的類型、函數(shù)參數(shù)及函數(shù)體等,它是一個(gè)完整的、獨(dú)立的函數(shù)單位。在一個(gè)程序中,一個(gè)函數(shù)只能被定義一次,而且是在其他任何函數(shù)之外進(jìn)行的。

函數(shù)聲明(有的書上也稱為“說明”)則是把函數(shù)的名稱、函數(shù)值的類型、參數(shù)的類型、個(gè)數(shù)和順序通知編譯系統(tǒng),以便在調(diào)用該函數(shù)時(shí)系統(tǒng)對(duì)函數(shù)名稱正確與否、參數(shù)的類型、個(gè)數(shù)及順序是否一致等進(jìn)行對(duì)照檢查。在一個(gè)程序中,除上述可以省略函數(shù)聲明的情況外,所有主調(diào)函數(shù)都必須對(duì)被調(diào)函數(shù)進(jìn)行聲明。6.2.3函數(shù)間的數(shù)據(jù)傳遞調(diào)用函數(shù)時(shí),大多數(shù)情況下,主調(diào)函數(shù)與被調(diào)函數(shù)之間有數(shù)據(jù)傳遞關(guān)系。主調(diào)函數(shù)向被調(diào)函數(shù)傳遞數(shù)據(jù)主要是通過函數(shù)的參數(shù)進(jìn)行的,而被調(diào)函數(shù)向主調(diào)函數(shù)傳遞數(shù)據(jù)一般是利用return語句實(shí)現(xiàn)的。在使用函數(shù)的參數(shù)傳遞數(shù)據(jù)時(shí),可以采用兩種方式,即傳值方式和傳址方式。從本質(zhì)上講,C語言中只有傳值方式,因?yàn)榈刂芬彩且环N值,傳址實(shí)際上是傳值方式的一個(gè)特例,只是為了講述方便,將它們分開討論。本節(jié)只介紹傳值方式,傳址方式將在第7章數(shù)組和第8章指針中進(jìn)行詳細(xì)介紹

函數(shù)調(diào)用時(shí),主調(diào)函數(shù)的參數(shù)稱為“實(shí)參”,被調(diào)函數(shù)的參數(shù)稱為“形參”,主調(diào)函數(shù)把實(shí)參的值按數(shù)據(jù)復(fù)制方式傳給被調(diào)函數(shù)的形參,從而實(shí)現(xiàn)調(diào)用函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳遞。使用傳值方式在函數(shù)間傳遞數(shù)據(jù)時(shí)應(yīng)注意以下幾點(diǎn):(1)實(shí)參和形參的類型、個(gè)數(shù)和順序都必須保持一致。實(shí)參可以是常量、變量、表達(dá)式或數(shù)組元素,但必須有確定的值,以便把這些值傳送給形參。因此,應(yīng)預(yù)先用賦值、輸入等方法,使實(shí)參獲得確定的值。(2)形參變量只有在函數(shù)被調(diào)用時(shí),才分配存儲(chǔ)單元,函數(shù)調(diào)用結(jié)束后,即刻釋放所分配的存儲(chǔ)單元,因此,形參只有在該函數(shù)內(nèi)有效。函數(shù)調(diào)用結(jié)束返回主調(diào)函數(shù)后,則不能再使用該形參變量。(3)實(shí)參對(duì)形參的數(shù)據(jù)傳送是單向的值傳遞,即只能把實(shí)參的值傳送給形參,而不能把形參的值反向傳送給實(shí)參?!纠?.3】傳值方式在函數(shù)間傳遞數(shù)據(jù)應(yīng)用舉例。#include<stdio.h>voidswap(intx,inty)//定義swap()函數(shù){inttemp;temp=x;x=y;y=temp;printf("x=%d,y=%d\n",x,y);//交換x,y的值}main(){inta=2,b=3;swap(a,b);//調(diào)用swap()函數(shù)

printf("a=%d,b=%d\n",a,b);}程序運(yùn)行結(jié)果:x=3,y=2a=2,b=3

在該程序中,函數(shù)間的數(shù)據(jù)傳遞采用傳值方式。當(dāng)執(zhí)行到main()函數(shù)中的函數(shù)調(diào)用語句“swap(a,b);”時(shí),給swap()函數(shù)中的兩個(gè)形參x和y分配存儲(chǔ)空間,并將實(shí)參a,b的值2和3分別傳遞給x和y。此時(shí)數(shù)據(jù)傳遞如圖6-1(a)所示。在執(zhí)行swap()函數(shù)時(shí),確實(shí)交換了x和y的值,但當(dāng)函數(shù)調(diào)用結(jié)束返回主函數(shù)時(shí),形參x和y所占的存儲(chǔ)空間被釋放,形參值的改變并不能影響實(shí)參,因此,主函數(shù)中a和b的值維持不變,并未實(shí)現(xiàn)兩數(shù)的交換。返回main()函數(shù)時(shí)實(shí)參和形參的情況如圖6-1(b)所示,其中虛框表示形參所占內(nèi)存空間已被釋放。

在C語言中還可以使用全局變量在函數(shù)間傳遞數(shù)據(jù),關(guān)于全局變量的內(nèi)容將在§6.2.4節(jié)進(jìn)行詳細(xì)介紹。

6.2.4變量的作用域變量的有效范圍稱為變量的作用域。所有變量都有自己的作用域,變量定義的位置不同,其作用域也不同,作用域是從空間角度對(duì)變量特性的一個(gè)描述。按照變量的作用域,可將C語言中的變量分為局部變量和全局變量。一、局部變量在一個(gè)函數(shù)(包括main()函數(shù))或復(fù)合語句內(nèi)部定義的變量稱為局部變量。局部變量只在該函數(shù)或復(fù)合語句范圍內(nèi)有效。在函數(shù)或復(fù)合語句之外就不能使用這些變量了。所以,局部變量又稱為內(nèi)部變量。局部變量的作用域如下所示:說明:(1)主函數(shù)main()中定義的局部變量,只能在主函數(shù)中使用,其他函數(shù)不能使用。同時(shí),主函數(shù)中也不能使用其他函數(shù)中定義的局部變量。因?yàn)橹骱瘮?shù)也是一個(gè)函數(shù),與其他函數(shù)是平行關(guān)系。(2)形參變量也是局部變量,屬于被調(diào)函數(shù);實(shí)參變量則是主調(diào)函數(shù)的局部變量。(3)允許在不同的函數(shù)中使用相同的變量名,它們代表不同的對(duì)象,被分配不同的存儲(chǔ)單元,互不干擾,也不會(huì)發(fā)生混淆(4)在復(fù)合語句中也可以定義變量,其作用域只限于復(fù)合語句范圍內(nèi)。【例6.4】局部變量應(yīng)用舉例。#include<stdio.h>main(){ inta=10; { inta=20; printf("a=%d\n",a); } printf("a=%d\n",a);}程序運(yùn)行結(jié)果:a=20a=10

該程序中,定義了兩個(gè)變量a,值為10的a的作用域?yàn)檎麄€(gè)main()函數(shù),值為20的a的作用域?yàn)槠渌诘膹?fù)合語句。但在該復(fù)合語句中,值為10的a被屏蔽,所以第一個(gè)printf()語句輸出20;當(dāng)結(jié)束復(fù)合語句時(shí),值為20的a消失,值為10的a變?yōu)橛行?,所以第二個(gè)printf()語句輸出10二、全局變量全局變量又稱外部變量,它是指在函數(shù)外部定義的變量。全局變量不屬于任何一個(gè)函數(shù),其作用域從定義的位置開始,到整個(gè)源程序結(jié)束。全局變量可被作用域內(nèi)的所有函數(shù)直接引用。全局變量的作用域如下所示:【例6.5】輸入圓的半徑(r),求圓的周長(zhǎng)(d)及面積(s)。#include<stdio.h>#definePI3.1415926floatd,s;//全局變量定義voidfun_ds(floata){ d=2*PI*a;//計(jì)算周長(zhǎng)

s=PI*a*a;//計(jì)算面積}main(){ floatr; printf("請(qǐng)輸入圓的半徑:"); scanf("%f",&r); fun_ds(r);//調(diào)用函數(shù)

printf("圓的周長(zhǎng)為:%.2f,面積為:%.2f\n",d,s);}程序運(yùn)行結(jié)果:請(qǐng)輸入圓的半徑:4↙圓的周長(zhǎng)為:25.13,面積為:50.27

從該例可以看出,全局變量是函數(shù)之間進(jìn)行數(shù)據(jù)傳遞的又一種方式。由于C語言中的函數(shù)只能返回一個(gè)值,因此,當(dāng)需要增加函數(shù)的返回值時(shí),可以使用全局變量。該例中,在函數(shù)fun_ds()中求得的全局變量d和s的值,在main()函數(shù)中仍然有效,從而實(shí)現(xiàn)了函數(shù)之間的數(shù)據(jù)傳遞。讀者可參照此例,改寫例6.3,用全局變量實(shí)現(xiàn)兩個(gè)整數(shù)的交換。說明:(1)全局變量可加強(qiáng)函數(shù)之間的數(shù)據(jù)聯(lián)系,因而使得函數(shù)的獨(dú)立性降低。從模塊化程序設(shè)計(jì)的觀點(diǎn)來看,這是不利的,因此在不必要時(shí)盡量不要使用全局變量。(2)在同一源文件中,允許全局變量和局部變量同名。同名時(shí)在局部變量的作用域內(nèi),全局變量將被屏蔽而不起作用,如例6.6所示?!纠?.6】全局變量與局部變量同名舉例。#include<stdio.h>inta=3,b=5;//全局變量定義intmax(inta,intb){intc;if(a>b)c=a;elsec=b;returnc;}main(){inta=8;//局部變量定義

printf("max=%d\n",max(a,b));}程序運(yùn)行結(jié)果如下:max=8

該例中,main()函數(shù)中定義的局部變量a與全局變量同名,max()函數(shù)中定義的形參a,b也與全局變量同名。因此,在main()函數(shù)中,全局變量a被屏蔽,調(diào)用max()函數(shù)的實(shí)參a是局部變量,值為8,實(shí)參b是全局變量,值為5。在max()函數(shù)中,全局變量a、b均被屏蔽,形參a,b的值為實(shí)參所傳遞,分別為8和5,所以輸出結(jié)果為8。從例6.6可以看出,全局變量與局部變量同名時(shí)容易混淆其作用域,因此在程序設(shè)計(jì)中應(yīng)盡量避免其同名。(3)全局變量的作用域是從定義點(diǎn)開始到本源文件結(jié)束為止的。如果定義點(diǎn)之前的函數(shù)需要引用這些全局變量,則需要在函數(shù)內(nèi)對(duì)被引用的全局變量進(jìn)行聲明。全局變量聲明的一般形式為:

extern類型說明符全局變量1[,全局變量2…];可通過對(duì)全局變量的聲明將其作用域延伸到定義它的位置之前的函數(shù)中。如例6.5的程序也可以編寫成如下形式:#include<stdio.h>#definePI3.1415926voidfun_ds(inta){ externfloatd,s;//全局變量聲明

d=2*PI*a;//計(jì)算周長(zhǎng)

s=PI*a*a;//計(jì)算面積}floatd,s;//全局變量定義main(){ intr; printf("請(qǐng)輸入圓的半徑:"); scanf("%d",&r); fun_ds(r); printf("圓的周長(zhǎng)為:%.2f,面積為:%.2f\n",d,s);}

上面程序的功能和運(yùn)行結(jié)果與例6.5完全相同。全局變量d,s的定義位置在fun_ds()函數(shù)的定義之后,因此,在fun_ds()函數(shù)中要引用全局變量d,s就必須先聲明,使其作用域延伸到該函數(shù)中才能引用。這種作用域的擴(kuò)展,也稱為作用域的“提升”。全局變量的定義和全局變量的聲明是兩回事。全局變量的定義,必須在所有函數(shù)之外,且只能定義一次。而全局變量的聲明,出現(xiàn)在要使用該全局變量的函數(shù)內(nèi),而且可以在不同的函數(shù)中出現(xiàn)多次。全局變量在定義時(shí)分配內(nèi)存單元,并可以初始化;全局變量聲明時(shí),不能再賦初值,只是表明在該函數(shù)內(nèi)要使用這些全局變量。6.3知識(shí)擴(kuò)展6.3.1變量的存儲(chǔ)類型在C語言中,每個(gè)變量都有兩個(gè)屬性:數(shù)據(jù)類型和存儲(chǔ)類型。數(shù)據(jù)類型在第2章已經(jīng)作了詳細(xì)介紹,存儲(chǔ)類型是指變量在內(nèi)存中存儲(chǔ)的方式。變量的存儲(chǔ)類型分為靜態(tài)存儲(chǔ)和動(dòng)態(tài)存儲(chǔ)兩大類。靜態(tài)存儲(chǔ)變量通常是在變量定義時(shí)就分配存儲(chǔ)單元,并一直占有,直至整個(gè)程序運(yùn)行結(jié)束才釋放。前面介紹的全局變量即屬于此類存儲(chǔ)方式。

動(dòng)態(tài)存儲(chǔ)變量是在程序執(zhí)行過程中,使用它時(shí)才分配存儲(chǔ)單元,使用完畢立即釋放。典型的例子是函數(shù)的形參,在函數(shù)定義時(shí)并不給形參分配存儲(chǔ)單元,只是在函數(shù)被調(diào)用時(shí),才予以分配,調(diào)用完畢立即釋放。如果一個(gè)函數(shù)被多次調(diào)用,則反復(fù)地分配、釋放形參變量的存儲(chǔ)單元。由此可知,靜態(tài)存儲(chǔ)變量是一直存在的,而動(dòng)態(tài)存儲(chǔ)變量則“用之則建,用完即撤”。這種由于變量存儲(chǔ)方式的不同而產(chǎn)生的特性,稱為變量的生存期。生存期表示了變量存在的時(shí)間。生存期和作用域分別從時(shí)間和空間兩個(gè)不同的角度描述了變量的特性。兩者之間既有聯(lián)系,又有區(qū)別。

因此,對(duì)一個(gè)變量的定義,不僅應(yīng)定義其數(shù)據(jù)類型,還應(yīng)定義其存儲(chǔ)類型。變量定義的完整形式應(yīng)為:

[存儲(chǔ)類型]數(shù)據(jù)類型變量名1[,變量名2…];在C語言中,對(duì)變量的存儲(chǔ)類型定義有以下四種:自動(dòng)變量(auto)、靜態(tài)變量(static)、寄存器變量(register)和外部變量(extern)。這里只介紹常用的自動(dòng)變量和靜態(tài)變量。1.自動(dòng)變量(auto)在定義變量時(shí),用關(guān)鍵字auto指定存儲(chǔ)類型的局部變量稱為自動(dòng)變量。由于C語言默認(rèn)局部變量的存儲(chǔ)類型為auto,所以在定義局部變量時(shí),通常省略auto。前面各章的程序中所定義的變量,都是自動(dòng)變量。例如:inta,b,c;

等價(jià)于

autointa,b,c;

自動(dòng)變量具有以下特點(diǎn)(1)自動(dòng)變量屬于動(dòng)態(tài)存儲(chǔ)方式,只有在定義它的函數(shù)被調(diào)用時(shí),才為其分配存儲(chǔ)單元,當(dāng)函數(shù)調(diào)用結(jié)束,其所占用的存儲(chǔ)單元自動(dòng)被釋放。函數(shù)的形參也屬于此類變量。自動(dòng)變量的生存期為函數(shù)被調(diào)用期間。(2)自動(dòng)變量的賦初值操作是在函數(shù)被調(diào)用時(shí)進(jìn)行的,且每次調(diào)用都要重新賦一次初值。2.靜態(tài)變量(static)靜態(tài)變量又分為靜態(tài)局部變量和靜態(tài)全局變量?jī)煞N。當(dāng)用關(guān)鍵字static定義局部變量時(shí),稱該變量為靜態(tài)局部變量。當(dāng)用關(guān)鍵字static定義全局變量時(shí),則稱該變量為靜態(tài)全局變量。在此主要介紹靜態(tài)局部變量。靜態(tài)局部變量具有以下特點(diǎn):(1)靜態(tài)局部變量屬于靜態(tài)存儲(chǔ)方式,在編譯時(shí)為其分配存儲(chǔ)單元,在程序執(zhí)行過程中,靜態(tài)局部變量始終存在,即使所在函數(shù)被調(diào)用結(jié)束也不釋放。靜態(tài)局部變量的生存期為整個(gè)程序執(zhí)行期間。(2)靜態(tài)局部變量的作用域與自動(dòng)變量相同,即只能在定義它的函數(shù)內(nèi)使用,退出該函數(shù)后,盡管它的值還存在,但不能被其他函數(shù)引用。(3)靜態(tài)局部變量是在編譯時(shí)賦初值,對(duì)未賦初值的靜態(tài)局部變量,C編譯系統(tǒng)自動(dòng)為它賦初值0(整型或?qū)嵭停┗?\0'(字符型)。每次調(diào)用靜態(tài)局部變量所在的函數(shù)時(shí),不再重新賦初值,而是使用上次調(diào)用結(jié)束時(shí)的值,所以靜態(tài)局部變量的值具有可繼承性?!纠?.7】自動(dòng)變量和靜態(tài)局部變量應(yīng)用舉例。#include<stdio.h>intfun(inta){ autointb=0;//自動(dòng)變量定義

staticintc;//靜態(tài)局部變量定義

b=b+1; c=c+1; return(a+b+c);}main(){ inta=2,i; for(i=1;i<=3;i++) printf("%2d",fun(a));}程序運(yùn)行結(jié)果:456

該例fun()函數(shù)中定義了自動(dòng)變量b和靜態(tài)局部變量c,由于自動(dòng)變量在函數(shù)調(diào)用時(shí)才分配存儲(chǔ)單元,函數(shù)調(diào)用結(jié)束時(shí)存儲(chǔ)單元釋放,值不保留。因此,三次調(diào)用fun()函數(shù)時(shí),b變量都將重新賦值0;而靜態(tài)局部變量在編譯時(shí)分配存儲(chǔ)單元,且系統(tǒng)自動(dòng)賦初值0,在函數(shù)調(diào)用結(jié)束時(shí)存儲(chǔ)單元不釋放,值具有繼承性,下次調(diào)用該函數(shù)時(shí),靜態(tài)局部變量的初值就是上一次調(diào)用結(jié)束時(shí)變量的值。因此,三次調(diào)用fun()函數(shù)結(jié)束時(shí),c變量的值分別為1,2,3,函數(shù)的返回值相應(yīng)為4,5,6。

當(dāng)多次調(diào)用一個(gè)函數(shù)且要求在調(diào)用之間保留某些變量的值時(shí),可考慮采用靜態(tài)局部變量。但由于靜態(tài)局部變量的作用域與生存期不一致,降低了程序的可讀性,因此,除對(duì)程序的執(zhí)行效率有較高要求外,一般不提倡使用靜態(tài)局部變量。6.3.2函數(shù)的嵌套調(diào)用和遞歸調(diào)用前面介紹的函數(shù)調(diào)用方式,只是一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù),這種調(diào)用屬于簡(jiǎn)單調(diào)用。C語言還允許函數(shù)的嵌套調(diào)用和遞歸調(diào)用。一、函數(shù)的嵌套調(diào)用

C語言的函數(shù)定義都是互相平行、獨(dú)立的。也就是說,在定義一個(gè)函數(shù)時(shí),該函數(shù)體內(nèi)不能再定義另一個(gè)函數(shù),即不允許嵌套定義函數(shù)。但可以嵌套調(diào)用函數(shù),即在調(diào)用一個(gè)函數(shù)的過程中,又調(diào)用另一個(gè)函數(shù)。其調(diào)用關(guān)系如圖6-2所示。

圖6-2表示了兩層嵌套調(diào)用的情形。其執(zhí)行過程是:首先執(zhí)行main()函數(shù),當(dāng)遇到調(diào)用f1()函數(shù)的語句時(shí),即轉(zhuǎn)去執(zhí)行f1()函數(shù);在f1()函數(shù)的執(zhí)行過程中,當(dāng)遇到調(diào)用f2()函數(shù)的語句時(shí),又轉(zhuǎn)去執(zhí)行f2()函數(shù);f2()函數(shù)執(zhí)行完畢返回f1()函數(shù)的調(diào)用點(diǎn)繼續(xù)執(zhí)行,f1()函數(shù)執(zhí)行完畢返回main()函數(shù)的調(diào)用點(diǎn)繼續(xù)執(zhí)行,直到整個(gè)程序結(jié)束?!纠?.8】計(jì)算12+22+32+42+52之和。#include<stdio.h>intsqare(intn)//定義求平方值函數(shù){ intt; t=n*n; return(t);}intsum(intm)//定義求和函數(shù){ inti,s; s=0; for(i=1;i<=m;i++) s=s+sqare(i);//調(diào)用求平方值函數(shù)

return(s);}main(){ intp; p=sum(5);//調(diào)用求和函數(shù)

printf("result=%d\n",p);}程序運(yùn)行結(jié)果:result=55

該程序由主函數(shù)main()、求和函數(shù)sum()和求平方值函數(shù)sqare()組成。主函數(shù)main()先調(diào)用sum()函數(shù),在sum()中又發(fā)生對(duì)sqare()函數(shù)的調(diào)用,同時(shí)把i值(i值分別取1,2,3,4,5)作為實(shí)參傳給sqare(),在sqare()中完成求i的平方值計(jì)算。sqare()執(zhí)行完畢,把i的平方值返回給sum(),在sum()中通過循環(huán)實(shí)現(xiàn)累加,計(jì)算出結(jié)果后返回主函數(shù)。二、函數(shù)的遞歸調(diào)用一個(gè)函數(shù)在其函數(shù)體內(nèi)直接或間接地調(diào)用自身,稱為函數(shù)的遞歸調(diào)用。這是函數(shù)嵌套調(diào)用的一種特殊情況。在遞歸調(diào)用中,主調(diào)函數(shù)同時(shí)又是被調(diào)函數(shù)。執(zhí)行遞歸函數(shù)將反復(fù)調(diào)用其自身,每調(diào)用一次就進(jìn)入新的一層。例如函數(shù)f()定義如下:

intf(intn){ inty; y=f(n-1); returny;}

這是一個(gè)遞歸函數(shù)。但是運(yùn)行該函數(shù)將無休止地調(diào)用其自身,這當(dāng)然是不正確的。為了防止遞歸調(diào)用無終止地進(jìn)行,在函數(shù)內(nèi)必須有終止遞歸調(diào)用的語句。常用的方法是采用條件語句來控制,滿足某種條件后就不再進(jìn)行遞歸調(diào)用,然后逐層返回。這個(gè)條件稱為遞歸結(jié)束條件。構(gòu)造遞歸函數(shù)的關(guān)鍵是尋找遞歸算法。例如,計(jì)算n!遞歸算法的數(shù)學(xué)表達(dá)式為:n!=1n=0或n=1n×(n-1)!n>1

滿足遞歸算法的三個(gè)條件如下:(1)有明確的遞歸結(jié)束條件。如在n=0或n=1的條件下,可以直接得出n!=1,從而結(jié)束遞歸。(2)要解決的問題總是可以轉(zhuǎn)化為相對(duì)簡(jiǎn)單的同類問題。如n!可轉(zhuǎn)化為n×(n-1)!,而(n-1)!是比n!稍簡(jiǎn)單的同類問題。(3)隨著問題的逐次轉(zhuǎn)換,最終能達(dá)到結(jié)束遞歸的條件。算法中的參數(shù)n在遞歸過程中逐次減少,必然會(huì)達(dá)到n=0或n=1【例6.9】用遞歸方法計(jì)算n!。#include<stdio.h>longfac(intn){ longf; if(n==1||n==0)f=1; else f=n*fac(n-1);//遞歸調(diào)用

return(f);}main(){ intn; longy; scanf("%d",&n); y=fac(n); printf("%d!=%ld\n",n,y);}程序運(yùn)行結(jié)果:4↙4!=24

運(yùn)行該程序時(shí),輸入值為4,即求4!。在主函數(shù)中的調(diào)用語句即為y=fac(4),進(jìn)入fac()函數(shù)后,由于n=4,大于1,故執(zhí)行f=n*fac(n-1),即f=4*fac(4-1)。該語句對(duì)fac()函數(shù)作遞歸調(diào)用,即調(diào)用fac(3),逐次展開遞歸。進(jìn)行三次遞歸后,fac()函數(shù)形參取得的值變?yōu)?,故不再繼續(xù)遞歸調(diào)用,而開始逐層返回主調(diào)函數(shù),fac(1)的函數(shù)返回值為1,fac(2)的返回值為1*2=2,fac(3)的返回值為2*3=6,最后返回fac(4)的值為6*4=24。其遞歸調(diào)用過程如圖6-3所示。6.3.3編譯預(yù)處理

C語言系統(tǒng)提供了編譯預(yù)處理功能。所謂編譯預(yù)處理,是指在對(duì)源程序作正常編譯之前,先對(duì)源程序中一些特殊的命令進(jìn)行預(yù)先處理,產(chǎn)生一個(gè)新的源程序,然后再對(duì)新的源程序進(jìn)行通常的編譯,最后得到目標(biāo)代碼。這些在編譯之前預(yù)先處理的特殊命令稱為預(yù)處理命令。在C源程序中,所有預(yù)處理命令都以符號(hào)“#”開頭,每條預(yù)處理命令單獨(dú)占用一行,且尾部不加分號(hào),以區(qū)別于C語言的語句

引入編譯預(yù)處理命令是為了簡(jiǎn)化C源程序的書寫,便于大型軟件開發(fā)項(xiàng)目的組織,提高C語言程序的可移植性和代碼可重用性,方便C語言程序的調(diào)試等。例如,在源程序中調(diào)用一個(gè)庫函數(shù)時(shí),只需在調(diào)用位置之前用包含命令包含相應(yīng)的頭文件即可。

C語言提供的預(yù)處理命令有宏定義、文件包含和條件編譯三種。一、宏定義所謂宏定義是指用一個(gè)指定的標(biāo)識(shí)符代表一個(gè)具有特殊意義的字符串。命令中的標(biāo)識(shí)符稱為宏名。在編譯預(yù)處理時(shí),對(duì)程序中出現(xiàn)的宏名,都用宏定義中的字符串去替換,這種將宏名替換成字符串的過程稱為宏展開或宏代換。宏定義由源程序中的宏定義命令完成,宏代換則由預(yù)處理程序自動(dòng)完成。C語言的宏定義可分為無參宏定義和帶參宏定義兩種。1.無參宏定義無參宏的宏名后不帶參數(shù)。其定義的一般形式為:

#define標(biāo)識(shí)符字符串其中,“define”是宏定義的關(guān)鍵字,“標(biāo)識(shí)符”是程序中將使用的宏名,“字符串”是程序在執(zhí)行時(shí)所使用的真正數(shù)據(jù),可以是常量、表達(dá)式等。前面介紹過的符號(hào)常量的定義其實(shí)就是一種無參宏定義。如:

#definePI3.1415926

它的作用是用指定的標(biāo)識(shí)符PI代替“3.1415926”這個(gè)字符串。在編譯預(yù)處理時(shí),程序中在該命令以后出現(xiàn)的所有PI都用“3.1415926”代替。這樣做的好處是見名知意、簡(jiǎn)化書寫、方便修改?!纠?.10】無參宏定義應(yīng)用舉例。#include<stdio.h>#definePRICE100main(){ intnum,total; printf("inputanumber:"); scanf("%d",&num); total=PRICE*num; printf("total=%dyuan\n",total);}程序運(yùn)行結(jié)果:inputanumber:20↙total=2000yuan說明:(1)宏名一般用大寫字母表示,以區(qū)別于小寫的變量名。(2)宏定義不是C語句,在行尾不能加分號(hào),如果加上分號(hào)則連分號(hào)也一起代換。例如:#definePRICE100;…total=PRICE*num;經(jīng)過宏展開后,該語句變?yōu)椤皌otal=100;*num;”,這顯然會(huì)引起語法錯(cuò)誤。(3)宏定義可以出現(xiàn)在程序中的任何位置,但必須位于引用之前,通常將宏定義放在源程序的開始。宏名的作用域從宏定義命令開始到本源程序結(jié)束,在同一作用域內(nèi),不允許重復(fù)定義宏名。如要終止其作用域,可使用#undef命令。例如:#definePRICE100main(){ …}#undefPRICEfun(){…}使用#undef后,使得PRICE只在main()函數(shù)中有效,而在fun()函數(shù)中無效(4)宏代換時(shí),只對(duì)宏名作簡(jiǎn)單的字符串替換,不進(jìn)行任何計(jì)算和語法檢查。若宏定義時(shí)書寫不正確,會(huì)得到不正確的結(jié)果或編譯時(shí)出現(xiàn)語法錯(cuò)誤。例如:#definePRICE100誤寫為:#definePRICE100ab預(yù)處理時(shí)會(huì)把所有的PRICE替換成100ab,而不管含義是否正確,語法有無錯(cuò)誤。(5)C語言規(guī)定,對(duì)于程序中出現(xiàn)在字符串常量中的字符,即使與宏名相同,也不對(duì)其進(jìn)行宏代換。如:#definePRICE100…printf("THETOTALPRICEIS:%d\n",PRICE);輸出結(jié)果為:THETOTALPRICEIS:100而不是以下結(jié)果:THETOTAL100IS:100(6)宏定義允許嵌套,即在宏定義的字符串中可以使用已經(jīng)定義的宏名,并且在宏展開時(shí)由預(yù)處理程序?qū)訉哟鷵Q。如:#defineNUM20#definePRICE100#defineTOTALPRICE*NUM…printf("total=%d\n",TOTAL);最后一個(gè)語句經(jīng)過宏展開后為“printf("total=%d\n",100*20);”(7)宏定義與變量的定義不一樣,宏定義只作字符替換,不分配內(nèi)存空間。2.帶參宏定義C語言允許宏定義帶有參數(shù)。在宏定義中的參數(shù)稱為形參,在宏調(diào)用中的參數(shù)稱為實(shí)參。對(duì)帶參數(shù)的宏,在調(diào)用時(shí),不僅要宏展開,而且要用實(shí)參去代換形參。帶參宏定義的一般形式為:#define標(biāo)識(shí)符(形參表)字符串

其中,“形參表”由一個(gè)或多個(gè)形參組成,當(dāng)有一個(gè)以上的形參時(shí),形參之間用逗號(hào)分隔?!白址睉?yīng)該含有形參名。如:

#defineM(y)y*y+3*y…k=M(5);

在宏調(diào)用時(shí),用實(shí)參5去代替形參y。宏展開后的語句為:

k=5*5+3*5;

帶參宏常用來取代功能簡(jiǎn)單、代碼短小、運(yùn)行時(shí)間較短、調(diào)用頻繁的程序代碼?!纠?.11】帶參宏定義應(yīng)用舉例。#include<stdio.h>#defineMAX(a,b)((a)>(b)?(a):(b))main(){ intx,y,z; x=10;y=20; z=10*MAX(x+1,y+1); printf("z=%d\n",z);}程序運(yùn)行結(jié)果:z=210該程序經(jīng)過預(yù)處理后,語句:z=10*MAX(x+1,y+1);變?yōu)?z=10*((x+1)>(y+1)?(x+1):(y+1));請(qǐng)讀者思考:如果將宏定義中字符串的最外層圓括號(hào)去掉,即為:#defineMAX(a,b)(a)>(b)?(a):(b)程序運(yùn)行的結(jié)果是什么?說明:(1)帶參宏定義中,宏名和形參表之間不能有空格出現(xiàn)。否則,C語言編譯系統(tǒng)將空格以后的所有字符均作為替代字符串,而將該宏視為無參宏。(2)帶參宏定義中,字符串內(nèi)的形參通常要用括號(hào)括起來,以避免出錯(cuò)。如以下宏定義:#defineS(a)a*a當(dāng)調(diào)用“y=S(2+3);”時(shí),將替換成“y=2+3*2+3;”,這顯然與設(shè)計(jì)者的原意不符。應(yīng)改為:#defineS(a)(a)*(a)宏展開后的語句為“y=(2+3)*(2+3);”,這樣就達(dá)到了設(shè)計(jì)者的目的。(3)帶參宏和帶參函數(shù)雖然很相似,但兩者有本質(zhì)區(qū)別,主要有:①函數(shù)調(diào)用時(shí),先求出實(shí)參表達(dá)式的值,再傳送給形參;而帶參宏只是進(jìn)行簡(jiǎn)單的字符替換,不進(jìn)行計(jì)算。②函數(shù)中的形參和實(shí)參有類型要求,因?yàn)樗鼈兪亲兞浚欢甓x與宏調(diào)用之間參數(shù)沒有類型的概念,只有字符序列的對(duì)應(yīng)關(guān)系。③函數(shù)調(diào)用是在程序運(yùn)行時(shí)進(jìn)行的,分配臨時(shí)的內(nèi)存單元,并占用運(yùn)行時(shí)間;而宏調(diào)用在編譯之前進(jìn)行,不分配內(nèi)存單元,不占用運(yùn)行時(shí)間。二、文件包含文件包含是指一個(gè)程序文件將另一個(gè)指定文件的全部?jī)?nèi)容包含進(jìn)來,使之成為源程序的一部分。文件包含在前面章節(jié)中已經(jīng)多次出現(xiàn),如“#include<stdio.h>”。文件包含的一般形式為:#include<文件名>或者#include"文件名"

文件包含命令一般放在源文件的開始部分。包含命令中的文件名可以用雙引號(hào),也可以用尖括號(hào)。但是這兩種形式是有區(qū)別的。使用雙引號(hào),系統(tǒng)先在本程序文件所在的磁盤和路徑下尋找包含文件,若找不到,再按系統(tǒng)規(guī)定的路徑搜索包含文件;如果用尖括號(hào),則系統(tǒng)僅按規(guī)定的路徑搜索包含文件。用戶編程時(shí)可根據(jù)自己文件所在的目錄來選擇某一種命令形式。

文件包含在程序設(shè)計(jì)中很有用。一個(gè)大的程序通常分為多個(gè)模塊,由多個(gè)程序員分別編程。有些共用的數(shù)據(jù)(如符號(hào)常量和數(shù)據(jù)結(jié)構(gòu))或函數(shù)可組成若干個(gè)文件,凡是要使用其中數(shù)據(jù)或調(diào)用其中函數(shù)的程序員,只要使用文件包含命令將所需文件包含進(jìn)來即可,不必再定義它們,從而減少程序員的重復(fù)勞動(dòng)?!纠?.12】文件包含應(yīng)用舉例。假如有下列兩個(gè)源程序文件file1.c和file2.c,它們的文件內(nèi)容如下:file1.c文件內(nèi)容:intmax(inta,intb)//定義max()函數(shù){ intc; if(a>b)c=a; elsec=b; return(c);}file2.c文件內(nèi)容:#include<stdio.h>#include"f:\file1.c"http://文件包含命令main(){ intx,y; scanf("%d,%d",&x,&y); printf("max=%d\n",max(x,y));}程序運(yùn)行結(jié)果:8,6↙max=8

該例中,編譯預(yù)處理把文件file1.c的內(nèi)容插入到文件file2.c中命令行“#include"f:\file1.c"”的位置,從而把file2.c和file1.c連成一個(gè)源文件。在使用文件包含時(shí),還應(yīng)注意以下幾點(diǎn):(1)一個(gè)include命令只能指定一個(gè)被包含文件,若有多個(gè)文件要包含,則需用多個(gè)include命令。(2)文件包含允許嵌套,即在一個(gè)被包含的文件中又可以包含另一個(gè)文件。(3)當(dāng)一個(gè)源文件

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論