c語言高級教程第四章.ppt_第1頁
c語言高級教程第四章.ppt_第2頁
c語言高級教程第四章.ppt_第3頁
c語言高級教程第四章.ppt_第4頁
c語言高級教程第四章.ppt_第5頁
已閱讀5頁,還剩24頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

李堂秋 廈門大學計算機科學編寫,C與C+程序設計 第四章 函數(shù)和程序結構,前言,使用函數(shù),可以把大的計算任務分解,換句話說,可以使用許多函數(shù)的組合來完成復雜的任務。而且在C中,并非所有的函數(shù)都要自己定義,可以使用別人已做好的程序模塊。在設計主函數(shù)的時候,可以將不必要的細節(jié)蘊藏起來,以便更容易把握主線和全局。如果程序太大,還可以將C語言寫的程序分放多個文件,分別編譯,最后再聯(lián)接起來成為整體。,4.1 函數(shù)的基礎,看看我們?nèi)绾尉幰粋€程序, 首先要明確我們要做什么事請,比如要讀一個文件,找出所有包含某一字符串的行并把它打印出來。 思路: while (讀入一個新行) if (如果這個新行包含指定的字符串) 打印這個新行,讀入一個新行,打印這一行,判斷這一行是否指定的字符串,函數(shù)的基礎(續(xù)), () 除了和()、 其他都可以省略,如: dummy( ) ;,數(shù)據(jù)傳入,數(shù)據(jù)通過 return ; 傳回給調用函數(shù),#include #define MAXLINE 1000 int getline(char line , int max); int strindex(char source , char searchfor ); char pattern = “ould”; /* pattern to search for */ /* find all lines matching pattern */ main ( ) char lineMAXLINE; int found = 0; while (getline(line, MAXLINE) 0) if (strindex(line, pattern) = 0) printf(“%s”, line); found+; return found; ,主函數(shù),/*getline: get line into s, return length*/ int getline (char s , int lim) int c, i; i = 0; while ( -lim 0 ,子函數(shù),4.2 返回非整數(shù)的函數(shù),在使用返回值不是整數(shù)的函數(shù)時,正確地進行函數(shù)的定義和函數(shù)說明十分重要。 函數(shù)定義時一定要說明返回值類型,否則缺省為整數(shù)。 為了使調用函數(shù)知道被調用函數(shù)的類型,函數(shù)調用前一定要進行原形說明,否則,如果函數(shù)定義的類型與調用類型出現(xiàn)不一致: 如果調用和被調用函數(shù)在同一個文件中定義,編譯器會提出警告,這是實行原型說明的好處。 如果不在一個文件中定義,編譯器不會發(fā)現(xiàn)問題,即: 在調用前沒有原型說明的函數(shù),被理解為返回整數(shù),而對它的變元毫無假定。 函數(shù)原型說明中沒有給出變量說明的,編譯器對變元不做任何檢查。,子函數(shù)把字符串轉換成浮點數(shù),#include /* atof: convert string s to double*/ double atof (char s ) double val, power; int i, sign; for (i = 0; isspace(si); i+) /*skip leading spaces*/ ; sign = (si = -) ? -1 : 1; if (si = + | si = -) i+; for ( val = 0.0; isdigit(si); i+) val = 10 * val + (si - 0); if (si = .) i+; for (power = 1.0; isdigit(si); i+) val = 10 * val + (si - 0); power *= 10.0; return sign * val / power; ,主函數(shù)讀入數(shù)字并把它們累加起來,#include #define MAXLINE 100 /* a rudimentary calculator */ main ( ) double sum, atof(char ); char lineMAXLINE; int getline(char line , int max); sum = 0; while (getline(line, MAXLINE) 0) printf(“t%gn”, sum += atof(line); return 0; ,4.3 外部變量-全局變量,全局變量是在所有函數(shù)外部定義的變量,它有如下的特性: 全程可見性:對程序中全局變量,通過適當說明,所有函授都可以通過它的唯一的“名字”對它存取,即使這些函數(shù)是在不同文件并且是分別編譯的。 可見性可控:當然,也可以通過適當?shù)恼f明,使某些全局變量只在一個文件中有效。 全程生命周期:全局變量從程序執(zhí)行時就存在,并且一直存在直到程序結束。 可增加效率:可以用來保留中間結果,如果許多函數(shù)使用大量的共同數(shù)據(jù),適度的使用外部變量,可以避免大量數(shù)據(jù)的傳遞,對于簡化程序是有益的。 函數(shù)是全局的:C程序是由一系列外部變量和函數(shù)組成的,C中所有的函數(shù)都是全局的,不能在函數(shù)中定義函數(shù)。,局部變量或內(nèi)部變量(2),全局變量又叫外部變量,它與內(nèi)部變量相對應,函數(shù)的參數(shù)變量和函數(shù)內(nèi)部定義的變量叫內(nèi)部變量。 內(nèi)部變量的可見性是局部的:內(nèi)部變量又稱局部變量,只在函數(shù)內(nèi)可見,當局部變量與某全局變量同名時,全局變量受到屏蔽。其好處是,不同的函數(shù)的局部變量可以同名,他們之間不會產(chǎn)生混淆。 局部變量的生命周期短:從函數(shù)被調用的時刻起存在,到函數(shù)調用結束時消亡。 函數(shù)的局部動態(tài)變量在兩次調用之間沒有關系,更不會相互影響。 使用局部變量,可以保證程序的模塊化 但在特定的情況下使用全局變量會簡化參數(shù)的傳遞。權衡,例子:說明外部變量的正確使用,設計一個可以做加減乘除的計算器,輸入采用反序波蘭表達式: 1 2 - 4 5 + * 表示:(1 - 2)*(4 + 5) 處理的算法如下: while(下一個字符是操作數(shù)或操作符并且不是文件結束) if (是數(shù)字) 壓入棧中 else if (是操作符) 彈出操作數(shù) 實行操作 壓入棧中 else if (是新行) 彈出操作數(shù)并打印結果 else 出錯 這里的主要問題是決策:公共存取的變量放在何處?-外部還是局部?,主程序,#include #include #define MAXOP 100 #define NUMBER 0 int getop(char ); /*原型說明*/ void push(double); double pop(void): /*reverse polish calculator*/ main ( ) int type; double op2; char sMAXOP; while (type = getop(s) != EOF) switch(type) case NUMBER: push(atof(s); break; case +: push(pop( ) + pop( ); break; case *: push(pop( ) * pop( ); break; case -: op2 = pop(); push(pop( ) - op2); break; case /: op2 = pop(); if (op2 != 0.0) push(pop( ) / op2); else printf(“error: zero divisorn”); break; case n:printf(“t%.8gn”, pop( ); break; default: printf(“error: unknown command %sn”, s); break; return 0; ,子程序1,/*解決堆棧和出棧的數(shù)據(jù)存儲和操作* /#define MAXVAL 100 int sp = 0; double valMAXVAL; /*value stack*/ /*push: push f onto value stack*/ void push (double f) if (sp 0) return val-sp; else printf(“error: stack emptyn”): return 0.0; ,子程序2,#include int getch(void); void ungetch(int); /*getch: get next operator or numeric operand 解決數(shù)據(jù)和操作符的輸入*/ int getop (char s ) int i, c; while(s0 = c = getch( ) = | c = t) ; s1 = 0; if ( !isdigit(c) ,子程序3,/*緩沖式的字符輸入*/ #define BUFSIZE 100 char bufBUFSIZE; /* buffer for ungetch*/ int bufp = 0; /*next buffer position*/ /* get a character (possibly pushed back) */ int getch(void) return (bufp 0) ? buf-bufp : getchar( ); /* ungetch: push character back on input */ void ungetch(int c) if (bufp = BUFSIZE) printf(“ungetch: too many charactersn”); else bufbufp+ = c; ,4.4 變量轄域,某變量的轄域是指可以通過該變量的名字對之存取的程序部分。 函數(shù)的形式參數(shù)和在函數(shù)前部定義或說明的局部變量的定義域是整個函數(shù)。不同函數(shù)中同名的變量間沒有任何關系。 在程序開頭定義的全局變量的轄域是所在文件的這個變量定義以后的其余部分。 但是一個程序可以分放在幾個文件中,預先編譯好的程序也可以從程序庫中導入,連接成更大的程序。由于存在一個文件使用另一個文件中定義的全程變量,此時存在如下問題: 如何寫變量的說明使得能正確編譯? 如何安排變量說明,使得程序裝入內(nèi)存時能正確地連接? 如何保證是外部變量只有一份拷貝? 如何對全局變量初始化? 下面回答這個問題:,變量轄域(續(xù)),外部變量的轄域是從定義或說明它們的地方起直到文件的結束: main( ) . int sp = 0; double valMAXVAL; void push(double f) . double pop(viod) . 如果要在定義函數(shù)時需要訪問尚未定義的外部變量或需要訪問另一文件中定義的外部變量,則在使用它的文件(或函數(shù))的開頭必須加外部變量說明。說明以后它在文件(或函數(shù))的其余部分是可見的了。 要注意外部變量的定義和說明之間的區(qū)別,說明只指出變量的類型,定義還涉及內(nèi)存的分配。在整個程序中一個外部變量只能定義一次,其它文件用extern說明加以關聯(lián)。 外部變量只能在定義的地方初始化一次,不能在extern說明時進行初始化。,正常的情況是:main無法存取它后面定 義的變量和函數(shù)。如果main要存取sp,val, push,和pop,則必須在這里或main 的開頭加: extern int sp; extern double val ; void push(double); double pop(void):,4.5 頭文件,當程序分成好幾個文件時,為了共享外部變量和函數(shù),一般的做法是把說明集中寫在一個頭文件中,然后在必要的文件中加以包含:,/*calc.h*/ #define NUMBER 0 void push(double); double pop(void); int getop(char ); int getch(void); void ungetch(int);,/*getop.c*/ #include #include #include “calc.h” getop( ) ,/*getch.c*/ #include #define BUFSIZE 100 char bufBUFSIZE; int bufp = 0; int getch(void) . void ungetch(int c) . ,/*main.c*/ #include #include #include “calc.h” #define MAXOP 100 main( ) ,/*stack.c*/ #include #include “calc.h” #define MAXVAL 100 int sp = 0; double valMAXVAL; void push(double f) double pop( ) . ,針對性問題:只有在 特別大的程序中才考 慮使用多個頭文件,4.6 靜態(tài)變量,為了使一個外部變量的轄域僅限于一個文件,不讓其它文件存取這個變量,或者讓其它文件可以使用同樣的外部變量名而不與這個變量相混淆,可以在該外部變量之前加static前綴: 函數(shù)也可以說明成為static,說明成static的函數(shù)只在本文件可見。 局部變量也可以說明成static, 靜態(tài)局部變量仍然是局部的,但它有永久的、私有的內(nèi)存空間,因此函數(shù)調用的結果可以保留下來,直到此函數(shù)以后的調用中將之改變。這一特性十分重要!,/*getch.c*/ #include #define BUFSIZE 100 static char bufBUFSIZE; static int bufp = 0; int getch(void) . void ungetch(int c) . ,/*stack.c*/ #include #include “calc.h” #define MAXVAL 100 static int sp = 0; static double valMAXVAL; void push(double f) double pop( ) . ,4.7 寄存器變量,對于常用的變量(特別是循環(huán)變量)可以說明成寄存器變量,要求編譯器將其安排在機器的寄存器中,其格式是在說明之間加register前綴: register int x; register char c; 寄存器變量存取的速度快,但只能把局部變量和函數(shù)的形式參數(shù)說明成寄存器變量,而且也只有一定類型(整型)的變量能被指定成寄存器變量: fun (register unsigned n, register long n) register int i; 根據(jù)機器的不同,可同時指定為寄存器變量的數(shù)目不同,編譯器可對過多的寄存器變量說明不予理會。一般說來,只把使用頻繁的循環(huán)變量指定為寄存器變量。 寄存器變量沒有地址,不管它實際存放在寄存器上與否。,4.8 塊結構,C語言不是嚴格的塊結構語言,不能在函數(shù)內(nèi)定義函數(shù),但可以在函數(shù)內(nèi)甚至程序塊內(nèi)定義局部變量: if (n 0) int i; for (i = 0; i n; i+) /* 這變量只在程序執(zhí)行這個塊時建立,塊結束時消亡*/ 局部變量對塊外的同名變量和函數(shù)會起屏蔽作用,如: int x; int y; fun (double x) double y; /* 在函數(shù)內(nèi),這兩個變量與外部的變量無關,這也是一個十分重要的特點,編程時最好避免這種情況 */,這個 i 是局部于這個程序塊,4.9 變量初始化,在沒有明確指定初始化公式情況下:全程變量和靜態(tài)變量初始化為0。自動變量(局部和參數(shù))和寄存器變量的初值是不確定的。 數(shù)值性的變量可以初始化: char squote = ; long day = 1000L*60L*60L*24L; 全局變量和靜態(tài)變量的初始化公式只能是常數(shù)表達式,并且只初始化一次(程序執(zhí)行前);局部的非靜態(tài)變量初始化公式可以是任意的,而且在每一次進入函數(shù)時進行一次初始化。 int bisearch (int x, int v , int n) int low = 0, high = n - 1, mid; 數(shù)組的初始化: int days = 31,28,31,30,31,30,31,31,30,31,30,31; 對于任何類型的變量,在指明元素個數(shù)時,初始化不足的元素為0;初始化過多時出錯;沒有辦法表示元素值重復;無法省略前導元素 字符數(shù)組的初始化可以使用如下特殊的形式: char s = “hello”; /*它是下式的簡寫*/ char s = h,e,l,l,o,0;,4.10 遞歸,C語言允許遞歸調用,即一個函數(shù)直接或間接地調用它自身。有許多需要遞歸調用的場合,例一,打印一個整數(shù),由于最先得到的是最低位,但最先要打印的是最高位,遞歸可以解決此類問題: #include /* printd:print n in decimal */ void printd(int n) if (n 0) putchar(-); n = -n; if (n / 10) printd(n / 10); putchar(n % 10 + 0); 另一個例子是快速排序,給定一個數(shù)組,選擇一個元素,把其它元素根據(jù)比該元素大小分成兩個集合,然后遞歸調用快速排序算法,直到集合的元素少于兩個,排序完成:,遞歸(續(xù)),/*qsort: sort vleft . vright into increasing order */ void qsort(int v , int left, int right) int i, last; void swap(int v , int i, int j); if (left = right) return; swap(v, left, (left + right) / 2); /* move partition element to elem */ last = left; for (i = left+1; i = right; i+) if (vi vleft) swap(v, +last, i); swap(v, left, last); /* restore partition elem */ qsort(v, left, last - 1); qsort(v, last + 1, right); /* swap: interchange vi, and vj */ void swap(int v , int i, int j) int temp; temp = vi; vi = vj; vj = temp; ,許多問題既可以用遞歸方法,也可以用非遞歸方法:在許多情況下,用遞歸寫的程序會更緊湊、更容易理解,特別對于處理遞歸設計的數(shù)據(jù)特別方便,但是遞歸在內(nèi)存和時間上都不會節(jié)省。,4.11 C預處理器,C在文件編譯之前對被編譯的文件提供預了許多預處理手段,其中包括:文件包含;宏定義;條件編譯。 1.文件包含: 一般格式: #include /* 在缺省的文件目錄尋找filename */ #include “filename” /* 在原程序所在的目錄尋找,若找不到 在缺省的文件目錄尋找filename */ #include將由filename的文件內(nèi)容所取代。,應用文件包含的目的是把個文件共同需要的宏定義, 外部變量說明,庫函數(shù)的原型說明等(stdio.h)插入到文 件的開頭。這樣可更好地保證每一個文件需要的常數(shù) 定義和子函數(shù)的定義都是一樣的。,C預處理器(續(xù)),#define(宏代換) 一般格式: #define #define forever for( ; ; ); /*在編譯前將文本中的前者(不 包括在字符串中的)用后者替換*/ 可帶變量 #define max(A, B) (A) (B) ? (A) : (B) x = max(p+q,r+s) 替換成x = (p+q) (r+s) ? (p+q) : (r+s) 盡管宏定義是十分有用的,但要注意如下的調用或定義的問題-特別要注意重復執(zhí)行問題和運算的優(yōu)先級問題: max(i+, j+); #define square(x) x*x #把實參變成字符串 #define dpri

溫馨提示

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

評論

0/150

提交評論