




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、C語言程序設計For 123高計網上學期有點失敗C語言用于做什么?學習高級程序設計的基礎編制程序C程序設計語言的地盤C語言最擅長什么?與硬件打交道資源消耗少效率要求高現狀?關系族譜圖專業(yè)中的作用?網頁網站設計計算機二級C?軟件設計難不難?聽說:除了難,還是難!我們怎么學?程序設計訣竅:多看,多練,多動手抓住原理人的腦袋對數據的處理對比程序對數據的處理!一點建議自己多看書!考核方法平時考勤 20%上機實驗上機實驗 30%期末項目期末項目 30%期末考試20%What is a computer?What is a computer?硬件(hardware) 鍵盤、鼠標、顯示器、硬盤、DVDs、內
2、存、CPU 硬件成本下降很快 摩爾定律 每過18個月微芯片的集成度翻一番,而芯片價格保持不變軟件(software) 運行于計算機之上的程序(Program)如何降低軟件開發(fā)成本?計算機如何工作 很像廚師的菜譜,定義了執(zhí)行某個任務所需的步驟 但不幸和不同的是,你不能使用你自己的母語來寫CodeWhat is programming language? C程序設計語言的地盤 以往的擅長: 與操作系統(tǒng)和基礎工具有關的編程任務 操作系統(tǒng)核心,設備驅動程序,系統(tǒng)工具,網絡應用,編輯器,字處理工具,編譯器,某些圖形和GUI應用,以及數據庫應用 未來的發(fā)展: 高性能、實時中間件,嵌入式領域,并發(fā)程序設計等
3、機器語言 計算1+1匯編語言BASIC語言C語言C語言的創(chuàng)世紀 一切從一個叫“Space Travel”的電子游戲開始 為了讓他的游戲能在PDP-7上運行,Ken Thompson用匯編語言給PDP-7寫了一個操作系統(tǒng)UNIX 匯編太不好用了,Thompson需要高級語言 試驗了一些高級語言,包括Fortran,都不理想 他在BCPL基礎上,自己設計了一個B語言 UNIX開始發(fā)展,B也不夠用了 Dennis Ritchie加入,把B改造成C 開始用C重寫UNIXRitchie和Thompson在開發(fā)UNIX接受美國國家技術勛章C程序設計語言 是一種高級語言 高級語言并不是“高級”,只是相對低級
4、語言,在一個高的級別上進行編程 歷史悠久,戰(zhàn)勛卓著 誕生于上世紀70年代初,成熟于80年代(C89),修訂與90年代(C99) 很多重量級軟件都是用C寫的 上天入地,無所不能 幾乎沒有不能用C寫出來的軟件,沒有不支持C的系統(tǒng) 很多流行語言、新生語言都借鑒了它的思想、語法 從C+,到Java,再到C#,還有php等C語言的祖師爺Dennis M. RitchieRitchie漫畫像C is quirky, flawed, and an enormous success.計算機基本工作過程 整個過程的執(zhí)行者是硬件,但硬件是受軟件控制的 編程,就是編寫軟件,使硬件按照人的意圖工作編譯運行 編譯過程
5、程序員(Programmer)編寫程序源代碼(Source Code) 編譯器(Compiler)把源代碼轉換為可被計算機理解的機器代碼(Machine Code),并把機器代碼以可執(zhí)行文件(Executable File)的形式保存在磁盤上 軟件的運行 計算機把機器代碼讀入到內存(Memory),由CPU運行這些代碼,讀取輸入(Input),產生輸出(Output),完成程序員預定的功能編譯語言 一種編譯語言對應一種編譯器 程序員按照該語言的語法編寫程序源代碼,把自己的意圖融入到代碼中 編譯器讀入源代碼,把程序員的意圖轉換成可執(zhí)行程序,供他人使用解釋運行 解釋運行過程 程序員編寫程序源代碼
6、解釋器讀入源代碼,并執(zhí)行源代碼 解釋運行的語言特點 執(zhí)行速度慢 好學易用 先編譯、后解釋 把源代碼編譯成更容易解釋的中間代碼,然后再解釋運行C程序設計語言第1章 觀其大略簡單數學題目求解步驟題目:題目:yxz簡單程序求解步驟題目:題目:yxz簡單程序實現方式1void main()/主函數(程序入口)int x,y,z;/設變量x=10;/變量賦值y=40;z=x+y;/得出結果50元x=8;/變量賦值y=40;z=x+y;/得出結果48元簡單程序實現方式1void main()/主函數(程序入口)int x,y,z;/設變量z=huijia(10,40);z=huijia(8,40);解答數
7、學與編程之相同 設變量作為存儲數據 如:x,y,z 表達式 如:z=x+y;z=x*y; 函數 實現某一功能 Y=f(x);解答數學與編程之不同 變量存儲空間 如:x,y,z不管空間,因在腦子里 變量有類型 如:x因在腦子里,你想它放什么就放什么 但電腦是具體存放地方必須有類型,如口袋 函數 是將多個計算式子包括起來,數學僅僅是一個表達式如:拋物線函數C語言編程幾個關鍵概念 變量 用于存放數據 表達式 如:z=x+y; 如:xy 函數 多個表達式構成的一個功能模塊C語言程序結構C語言程序運行Hello, World#include main()printf(hello, worldn); 超級
8、無敵考考你:如何把“hello”和“world” 分別打印在兩行?打印華氏溫度與攝氏溫度對照表 計算公式:C=(5/9)(F-32)打印華氏溫度與攝氏溫度對照表#include /* 對 fahr = 0, 20, ., 300 打印華氏溫度與攝氏溫度對照表 */main()int fahr, celsius;int lower, upper, step;lower = 0; /* 溫度表的下限 */upper = 300; /* 溫度表的上限 */step = 20; /* 步長 */fahr = lower;while (fahr = upper) celsius = 5 * (fahr-
9、32) / 9;printf(%dt%dn, fahr, celsius);fahr = fahr + step;代碼風格#include /* 對 fahr = 0, 20, ., 300 打印華氏溫度與攝氏溫度對照表 */main() int fahr, celsius; int lower, upper, step; lower = 0; /* 溫度表的下限 */ upper = 300; /* 溫度表的上限 */ step = 20; /* 步長 */ fahr = lower; while (fahr = upper) celsius = 5 * (fahr-32) / 9; pri
10、ntf(%dt%dn, fahr, celsius); fahr = fahr + step; 更簡單、精確的對照表打印程序#include #define LOWER 0 /* 表的下限 */#define UPPER 300 /* 表的上限 */#define STEP 20 /* 步長 */* 打印華氏-攝氏溫度對照表 */main ( )int fahr;for ( fahr = LOWER; fahr = UPPER; fahr = fahr + STEP )printf ( %3d # %6.1fn, fahr, (5.0 / 9.0) * (fahr - 32 ) );字符輸入輸
11、出 c = getchar() 從鍵盤讀入一個字符,賦值給變量c putchar(c) 把c輸出到屏幕 拷貝的基本思想:讀一個字符while ( 該字符不是文件結束指示符 )輸出剛讀進的字符讀下一個字符拷貝(Copy)#include /* 用于將輸入復制到輸出的程序;第1個版本 */main ( )int c;c = getchar ( );while ( c != EOF ) putchar ( c );c = getchar ( );一個更好的版本#include /* 用于將輸入復制到輸出的程序;第2個版本 */main ( )int c;while ( (c = getchar (
12、) ) != EOF ) putchar ( c );計算行數#include /* 統(tǒng)計輸入的行數 */main ( )int c;long nl;nl = 0;while ( (c = getchar ( ) ) != EOF )if ( c = n )nl+;printf(%dn, nl);加法器#include /* 計算輸入的兩個整數的和 */main ( )int a, b;printf(Please input two integers:);scanf(%d%d, &a, &b);printf(Sum=%dn, a+b);平均分#include /* 計算某科成績的平均值 */#
13、define TOTAL_NUMBER 10 /* 總人數 */main ( )float sum=0, scoreTOTAL_NUMBER;int i;printf(Input %d scores:n, TOTAL_NUMBER);for (i=0; i=0 */int power(int base, int n)int i, p;p = 1;for ( i = 1; i = n; +i )p = p * base;return p;power函數的調用(Call)#include int power(int base, int n);/* 測試power函數 */main ( )int m
14、, n;m = power(2, 1);n = power(-3, 3);printf(%d %dn, m, n);return 0;這一章我們學到了 #include #define main() printf(), scanf() getchar(), putchar() =, =, != int, long, float 數組 while, for, if 代碼風格 注釋、縮進、空行、命名 函數C程序設計語言第2章 類型、運算符與表達式標識符(Identifiers) 用戶自定義的符號叫標識符 如變量名、函數名、宏和類型名 標識符由字母、數字和下劃線組成,大小寫敏感 不可以是數字開頭 標
15、識符要直觀,能表達它的功能 下劃線和大小寫通常用來增強可讀性 variablename variable_name, VARIABLE_NAME VariableName, variableName 關鍵字(keyword)不可作為標識符 int, float, for, while, if等(教材164頁) 某些功能的變量采用習慣命名 如:for語句所采用的循環(huán)變量習慣用i, j, k基本數據類型(Data Type) int 整數,在目前絕大多數機器上占4個字節(jié) TC2中是2個字節(jié) 所占字節(jié)數取決于機器字長 float 單精度浮點數,一般是4個字節(jié)長 double 雙精度浮點數,一般是8個
16、字節(jié)長 char 字符,一般是1個字節(jié)長 用來表示256個ASCII字符,或者0255的整數數據類型修飾符 short short int,短整數,一般2個字節(jié)長。通常簡寫為short long long int,長整數,一般是4個字節(jié)長。通常簡寫為long long double,高精度浮點數,一般是10個字節(jié)長。 signed 用來修飾char、int、short和long,說明他們是有符號的整數(正整數、0和負整數)。一般缺省都是有符號的,所以這個修飾符通常省略 unsigned 用來修飾char、int、short和long,說明他們是無符號的整數(正整數和0)超出取值范圍會怎樣? T
17、C2中int的范圍是-3276732767 如果我們給它一個小于-32767或者大于32767的數會如何呢? 現場編程測驗溢出(Overflow)造成的危害 一臺安裝了Windows 95/98的機器,如果連續(xù)運行49.7天沒有重新啟動,可能死機 原因: Windows自啟動時刻起,有一個計數器,記錄系統(tǒng)已經運行了多少毫秒。這個計數器是個unsigned long 類型的變量 unsigned long的最大值是:4294967295 一天有 24*60*60*1000 = 86400000毫秒 4294967295 / 86400000 = 49.71026961805 當49.7天的時候,
18、此計數器會溢出,引起死機浮點數的陷阱#include main()float f;f = 123.456;if (f = 123.456)printf(f is equal to 123.456 indeed.);elseprintf(In fact, f is equal to %fn, f);運行結果會是什么?浮點數的陷阱 float的精度低,較易發(fā)生精度帶來的相等性判斷問題 double精度高,這個問題發(fā)生的概率小一些,但也存在 解決辦法:if (fabs(f 123.456) 1E-5)使用變量要注意 不要對變量所占的字節(jié)數想當然 用sizeof獲得變量或者數據類型的長度 用ANSI
19、C定義的宏確定數據的表示范圍,解決溢出問題常數(Constant) 整型常數 123、456 123456 123l、123L、123456l、123456L 浮點常數 123.45、456.78 1e-2、4.5e3 123.45f、 456.78F、1e-2f、4.5e3F 123.45l、 456.78L、1e-2l、4.5e3L八進制與十六進制常數 以數字“0”開始的整型常數是八進制數 010和10大小不一樣 因為八進制并不常用,所以此種表示法比較少見,因而常被用錯 以“0 x”或者“0X”開始的整型常數是十六進制 AF和af用來表示十進制的1015 0 x11, 0 x05, 0 x
20、FA, 0 xFF 十六進制的形式比較常用,尤其在進行位一級的控制的時候字符常數 字符常數的表示方法 a,A,5,%,$ 單引號內只能有一個字符,除非用“”開頭 就是一個普通整數,也可以參與各種數學運算 每個字符具有一個0255之間的數值,可從ASCII表查出 注意:5和5的區(qū)別,A和A的區(qū)別 字符的數學運算在密碼學內用得比較多字符常數 轉義字符 一些特殊字符(無法從鍵盤輸入或者在C語言里有它用)用轉義字符表示 轉義的思想在網絡協(xié)議和文件格式中經常使用字符串(String)常數 用雙引號括住的由0個或多個字符組成的字符序列 I am a string 表示空字符串 轉義字符也可以在字符串中使用
21、 引號只作為字符串開始和結束的標志 C語言內部用0表示字符串的結束 除注釋外,是唯一可以出現中文的地方 x和x是不同的 里定義了一系列專門的字符串處理函數枚舉(Enumeration)常數一個幾乎被遺忘的角色從程序來窺其一斑 enum weeks MON, TUE, WED, THU, FRI, SAT, SUN ; enum weeks today, tomorrow; today = MON; tomorrow = today + 1; if (tomorrow = TUE) printf(Tomorrow is Tuesday.n); else printf(Tomorrow is NO
22、T Tuesday.n);變量聲明 變量必須“先定義,后使用” 所有變量必須在第一條可執(zhí)行語句前定義 聲明的順序無關緊要 一條聲明語句可聲明若干個同類型的變量,變量名之間用逗號分隔 變量定義后,即占用內存,可向其存入各種數據,并可通過變量名使用數據 聲明變量,是初始化變量的最好時機 不被初始化的變量,其值為危險的隨機數char esc = ;int i = 0;int limit = MAXLINE + 1;float eps = 1.0e-5;常量 用const修飾定義的變量為常量 const int i=0; 常量只能在定義時賦值,然后不能再改變其值 常數、常量、宏和枚舉,都可以用來表示一
23、個永遠不會改變的數 前者不建議直接使用,而用后三者代替 后三者的工作機理是完全不同的,達到的效果也不盡相同 計算機只會計算 任何事物都要被表示成數字和公式的形式后,才能被計算機計算(被計算機處理) 事物到數字和公式的轉換過程叫數學建模 因為:事物在計算機內的處理都是一種計算 又因為:計算就要有操作數、運算法則和計算結果 所以:事物在計算機內的處理都有操作數、運算法則和計算結果 計算結果你可以留用,也可以忽略算術運算符 +,-,*,/ 加、減、乘、除運算 四則混合運算中,先算乘除,后算加減,先算左,后算右 % 求余運算關系運算符 ,=, b & b c);a大于b,并且b大于c | 或運算 (
24、a b | b c); a大于b,或者b大于c ! 求反 ( !a );如果a是0,結果非0;如果a是非0,結果是0 并不改變a的值類型轉換 在進行賦值操作時,會發(fā)生類型轉換 將取值范圍小的類型轉為取值范圍大的類型是安全的 反之是不安全的 如果大類型的值在小類型能容納的范圍之內,則平安無事 但是,浮點數轉為整數,會丟失小數部分(非四舍五入) 反之,轉換后的結果必然是錯誤的,具體結果與機器和實現方式有關。避免如此使用字符串與數值類型之間的轉換 int i = 123 這樣用是不行地 atof(),atoi(),atol() 把字符串轉為double,int和long 定義在stdlib.h中 s
25、printf() 可以用來把各種類型的數值轉為字符串 定義在stdio.h中自動類型轉換 兩個同種數據類型的運算結果,還是該類型 兩個不同種數據類型的運算結果,是兩種類型中取值范圍更大的那種 long double double float long int short char 只要兩者中有一個是unsigned,就都轉為unsigned再計算 把數據賦值給另外一種類型變量也會發(fā)生自動類型轉換 從小到大,順利轉換 從大到小,發(fā)出警告(好的編譯器會給出)類型強轉 可以通過“(類型)表達式”的方式把表達式的值轉為任意類型 強轉時,你必須知道你在做什么 強轉與指針,并稱C語言兩大神器,用好了可以呼
26、風喚雨,用壞了就損兵折將加一和減一運算符 i+,i-,+i,-i +讓參與運算的變量加1,-讓參與運算的變量減1 運算符為后綴,先取i的值,然后加/減1 運算符為前綴,先加/減1,然后取i的值 在一行語句中,使用加1或者減1運算的變量只能出現 不僅可讀性差,而且因為編譯器實現的方法不同,容易導致不同編譯器運行效果不一樣,貽害無窮位操作運算符 & 按位與運算 | 按位或運算 按位異或運算 按位右移運算 按位求反賦值運算符 賦值運算的結果是被賦值變量賦值后的值 a = b = c = 0; 下面兩個語句是等價的 i = i + 2; i += 2; +、-、*、/、%、&、|運算符都可以按此種方式
27、處理 這種形式看起來更直觀,而且執(zhí)行效率一般也能更高一些條件表達式 把a和b中的最大值放入z中 if (a b) z = a;else z = b; z = (a b) ? a : b; 此種表達式切忌用得過于繁雜優(yōu)先級( ) - .! + - + - * & (類型) sizeof* / %+ - = !=&|&|? := += -= *= /= %= &= = |= =,優(yōu)先級 能背下優(yōu)先級表的人鳳毛麟角 腦細胞太寶貴了,不能用來死記硬背 用括號來控制運算順序更直觀、方便,并減少出錯的概率 先算乘除,后算加減,有括號就先算括號里的 括號太多,有時候不清晰 注意用空格做好分隔 實在不行就拆分
28、表達式C程序設計語言第3章 控制流三種基本結構 順序結構、選擇結構、循環(huán)結構 已經證明,任何程序均可只用這三種結構實現 Bhm, Corrado, and Jacopini Guiseppe. Flow diagrams, Turing machines and languages with only two formation rules. Communication of ACM, 9(5):366-371, May 1966. 只用這三種結構的程序,叫結構化程序 程序“必須”符合結構化規(guī)則流程圖語句塊(Block) 括住的若干條語句構成一個語句塊 語句塊內可以定義變量 變量必須在語句塊的
29、開頭定義 變量僅在定義它的語句塊內(包括下層語句塊)有效(scope.c) 同一個語句塊內的變量不可同名,不同語句塊可以同名(homonym.c) 各司其職、下層優(yōu)先 盡量不要在下層語句塊內定義變量,也盡量不要定義同名變量 語句塊可以用在任何可以使用語句的地方,但沒有道理要亂加語句塊if-else 選擇結構的一種最常用形式 if (表達式)語句塊1;else語句塊2;語句塊3 表達式值非0時,執(zhí)行語句塊1,然后語句塊3;表達式值為0時,執(zhí)行語句塊2,然后語句塊3 else部分可以沒有。當表達式值為0時,直接執(zhí)行語句3 if-else嵌套使用時,注意else和誰配套的問題else-if if的一
30、種擴展 if (表達式1) 語句塊1;else if (表達式2)語句塊2;else if (表達式3)語句塊3;else語句塊4;語句塊5; else部分可以沒有switch 多路選擇 switch (表達式) case 整型常數1:語句1;case 整型常數2:語句2;default:語句3; default可以沒有 現場編程完成計算器 不要忘記breakswitch和else-if的比較 else-if比switch的條件控制更強大一些 else-if可以依照各種邏輯運算的結果進行流程控制 switch只能進行=判斷,并且只能是整數判斷 switch比else-if更清晰 兩者都要盡量避
31、免用得過多、過長,尤其不要嵌套得太多 它們大大增加程序的分支,使邏輯關系顯得混亂,不易維護,易出錯循環(huán)while,for while (表達式)語句塊; for (表達式1; 表達式2; 表達式3)語句塊;while while (表達式)語句塊1;語句塊2; 只要表達式的值為非0,就重復執(zhí)行語句塊1,直到表達式值為0時止,開始執(zhí)行語句塊2for for (表達式1; 表達式2; 表達式3)語句塊; 首先執(zhí)行表達式1。如果表達式2的值為非0,就重復執(zhí)行語句塊和表達式3,直到表達式2的值為0時止 相當于:表達式1; while (表達式2)語句塊;表達式3; for的所有表達式均可省略注意 在f
32、or和while語句之后一般沒有分號 有分號表示循環(huán)體就是分號之前的內容,即循環(huán)體不存在 while (i 100);i+; for (i = 0; i 100; i+);printf(%d, i); for通常有一個循環(huán)變量控制循環(huán)的次數,不要在循環(huán)體內改變這個變量循環(huán)do-while do語句塊1;while (表達式);語句塊2; 首先執(zhí)行語句,然后判斷表達式的值。如果表達式為0,繼續(xù)向下執(zhí)行,否則,再次執(zhí)行語句,再次判斷表達式的值 語句塊1會被執(zhí)行至少一次選擇三種循環(huán)的一般思路 如果循環(huán)次數已知,用for 如果循環(huán)次數未知,用while 如果循環(huán)體至少要執(zhí)行一次,用do-while 只
33、是思路,不是定律break和continue 對for、while、do-while循環(huán)進行內部手術 break,退出循環(huán) continue,中斷此次循環(huán)的執(zhí)行,開始下一次 break和continue少用為妙 它們增加了循環(huán)執(zhí)行的分支,break更增加了循環(huán)的出口 它們可以用來處理程序異常,而盡量不要用來處理正常流程C程序設計語言第4章 函數與程序結構函數(function)和模塊(module) 函數是C語言中模塊化編程的最小單位 可以把每個函數看作一個模塊 若干相關的函數可以合并作一個“模塊”函數的分類 函數生來都是平等的,沒有高低貴賤之分,只有main()稍微特殊一點點 庫函數 ANS
34、I C定義的標準庫函數 符合標準的C語言編譯器必須提供這些函數 函數的行為也要符合ANSI C的定義 第三方庫函數 由其它廠商自行開發(fā)的C語言函數庫 不在標準范圍內,能擴充C語言的功能 自定義函數 自己編寫的函數 包裝后,也可成為函數庫,供別人使用函數定義(definition)類型 函數名(類型 參數1, 類型 參數2, )函數體;return 表達式;函數定義(definition) 函數是這樣的一種運算: 函數名說明運算規(guī)則 參數是運算的操作數 返回值是運算的結果 當函數執(zhí)行到return語句或時,函數的運算停止。程序從當次調用函數的地方繼續(xù)執(zhí)行 函數可以有多個return,但最好只有一
35、個且是最后一行 用void定義返回值類型 函數沒有運算結果,沒有返回值 return語句之后不需要任何表達式 用void定義參數,表示沒有參數 參數表里的參數(叫形式參數,parameter)也是函數的語句塊內的變量函數調用(call) 函數名(表達式1, 表達式2, ); 調用一個函數之前,先要對其返回值類型、函數名和參數進行聲明(declare) 不對函數進行聲明是非常危險的 函數定義也有聲明函數的效果 調用函數時,提供的表達式(叫實際參數, argument)和該函數的形式參數必須匹配 數目一致 類型一一對應(會發(fā)生自動類型轉換) 表達式的值賦值給對應的參數 返回值可以按需處理函數調用的
36、過程 函數的每次執(zhí)行都會建立一個全新的獨立的環(huán)境 在“?!敝袨楹瘮档拿總€變量(包括形式參數)分配內存 把實際參數的值復制給形式參數 開始執(zhí)行函數內的第一條語句 函數內的代碼在這個獨立的環(huán)境內工作 函數退出時 求出返回值,將其存入一個可以被調用者訪問的地方(x86中通常使用EAX寄存器) 收回分配給所有變量(包括形式參數)的內存 程序控制權交給調用者,調用者拿到返回值,將其作為函數調用表達式的結果main()、printf()和scanf()特 殊 嗎? main() C語言允許不對函數參數和返回值類型進行說明 甚至可以連函數名都不聲明 此時默認 該函數的參數是不定個數的int型 該函數返回值為
37、int型 永遠不要利用此特性! printf()、scanf() 變長參數表, 缺點:對參數類型和個數無法嚴格驗證,易使用出錯使用函數要注意 每個函數只完成一個功能(包括main()) 對函數的功能可以用不含連詞的一句話描述 函數不能過長 1986年IBM在OS/360的研究結果:大多數有錯誤的函數都大于500行 1991年對148,000行代碼的研究表明:小于143行的函數比更長的函數更容易維護 函數一定要對傳進來的非法參數做點什么 向調用者提供錯誤信息 assert()全局變量(Global Variable) 在所有函數之外定義的變量是全局變量,在定義它的位置以后都有效 全局變量自動初始
38、化為0 全局變量使函數之間的數據交換更容易,效率也高一些 但是不推薦使用,甚至禁止使用 程序的任何部分都可以改寫全局變量,很難確定在程序的哪里改寫了它,程序結構混亂 不得不用的時候(這種情況比較少見),要嚴格控制對它的改寫靜態(tài)變量(static) 函數的內部變量在函數退出后失效(內存釋放)。再次進入函數,變量重新定義 每次函數執(zhí)行都建立一個全新的執(zhí)行環(huán)境,不受其它函數的干擾 把此變量定義為static,則變量的值可以保存到下次進入函數 static int i; 靜態(tài)變量自動初始化為0遞歸(Recursion) 函數直接或間接調用自己為遞歸 unsigned int func(unsigned
39、 int n) if (n = 0) return 1;else return n * func(n-1); 模塊模塊包含兩部分 源文件(xxx.c):一系列相關函數的定義 頭文件(xxx.h):這些函數的聲明等必要信息函數聲明、外部變量聲明、宏定義、類型定義可以將模塊編譯為.obj文件,同.h文件一起供別人使用,從而保護了源代碼使用模塊的過程1. 建立一個工程(project)2. 把各模塊都加入到工程中3. #include模塊的頭文件4. 開始使用此模塊編寫模塊的技術 模塊的信息隱藏 用static定義的函數和全局變量只在此模塊內有效(建議采用) 允許被其它模塊使用的全局變量 在源文件中
40、定義,不加static修飾 在頭文件中進行聲明,加extern修飾預編譯指令 編譯器在開始正式編譯之前處理的指令,叫預編譯指令 它們不會存在于最后生成的目標代碼中 文件包含:#include 用#include指定的文件內容替換#include所在的行 用或者括上文件名 表示在編譯器的include目錄內查找文件 表示在當前目錄查找文件 文件名中可以帶有路徑#define #define 宏名字 替換文本 在#define之后,所有獨立出現“宏名字”的地方(除了字符串內)都被“替換文本”替換 “替換文本”中可以有空格 宏可以有參數 #define max(A,B) (A) (B) ? (A)
41、: (B) 能想出帶參數的宏和函數的區(qū)別嗎? 定義宏的時候注意替換發(fā)生后產生的非預想結果 一般用括號可以避免,如上例與#define配套者 #undef,從現在開始取消#define的定義 #undef MAXLINE #if, #else,#elif,#endif #ifdef,#ifndef 這些預編譯指令通常用來處理多文件工程和程序多版本的問題。(程序多版本一般是不同平臺的版本,不同用戶等級的版本,不同開發(fā)階段的版本等)使用預編譯指令的目的 增強程序可讀性 但是調錯時宏可能帶來很多難題 精簡源代碼,提取變化 這一點更多時候用函數的效果更好,但宏也有其不可替代的優(yōu)勢 不編譯無用代碼,精煉目
42、標代碼C程序設計語言第5章 指針與數組 計算機內的存儲部件,活動中的所有指令和數據都保存在內存內 速度快,但是掉電即失 可以隨機訪問 只要指名要訪問的內存單元的地址,就可以立即訪問到該單元地址是一個無符號整數(通常用16進制數),其字長與主機相同 內存中的每個字節(jié)都有唯一的一個地址內存(Random Access Memory)地址(Address)指針的故事 “該程序執(zhí)行了非法操作,即將關閉” 這種錯誤幾乎全是由指針和數組導致的 黑客攻擊服務器利用的bug絕大部分都是指針和數組造成的 有些非計算機專業(yè)的人,盡量避免使用指針指針的故事 鐵桿C/C+程序員最摯愛的武器:指針 指針造就了C/C+的
43、高效和強大 很多不可能的任務由指針完成 main()char*a=main()char*a=%c%s%c;printf(a,34,a,34);printf(a,34,a,34);關于指針的原則 學習原則 一定要學會 其實通常的應用很簡單 就是一個變量 復雜的應用也不建議使用 使用原則 永遠要清楚每個指針指向了哪里 永遠要清楚指針指向的位置是什么數組(Array) 若干類型相同的相關數據湊到一起,就是數組 定義 類型 數組名整型常數1整型常數2 整型常數n; int a64; 使用 a00、a12、a53 每個元素都是一個普通變量 下標可以是任意整型表達式 數組的各個元素在內存中分布在一起,分布
44、規(guī)律是array.c 思考一下一維和三維數組怎么分布呢?從類型的角度理解數組 int a10; 定義了一個有10個int類型元素的數組 a的類型可以看作int10(只是看作,語法并不允許這么定義: int10 a) int a2010; 定義了一個有20個int10類型元素數組 a0、 a1a9的類型是int10,所以a00、 a01a199的類型是int int a302010; 這個呢? 這種特性決定了數組元素在內存的分布規(guī)律,也解釋了數組的很多語法現象數組初始化 數組定義后的初值仍然是隨機數,一般需要我們來初始化 int a5 = 12, 34, 56 ,78 ,9 ; int a5 =
45、 0 ; int a = 11, 22, 33, 44, 55 ; 數組大小最好用宏來定義,以適應未來可能的變化 #define SIZE 10int aSIZE;數組的使用 數組的下標都是從0開始 對數組每個元素的使用與普通變量無異 可以用任意表達式作為下標,動態(tài)決定訪問哪個元素 for (i=0; iSIZE; i+) ai = 2 * i; 下標越界是大忌! 使用大于最大下標的下標,將訪問數組以外的空間。那里的數據不是我們所想定的情況,可能帶來嚴重后果 有時,故意越界訪問數組會起到特別效果,但一定要對自己在做什么了如指掌 sizeof可以用來獲得數組所占字節(jié)數 sizeof(a) siz
46、eof(a0)數組的用處與特點 保存大量同類型的相關數據 快速地隨機訪問 一旦定義,不能再改變大小 在編譯階段就確定了數組的大小 數組名幾乎就是一個指針指針(Pointer) int *p; 定義了一個指針變量p,簡稱指針p p是變量,int*是類型 變量都占用內存空間,p的大小是sizeof(int*) p用來保存地址。此時這個地址是哪呢(p指向哪呢)? int i;p = &i; *p就像普通的變量一樣使用,其值是p指向的內存的內容,類型是int(在上例和i等價) p可以動態(tài)(任意)地指向不同內存,從而使*p代表不同的變量 p = 0; p = &a0;指針 指針也是數據類型。指向不同數據
47、類型的指針,分別為不同的數據類型 int*、float*、char*、int*、int* 指針指向非其定義時聲明的數據類型,將引起warning void*類型的指針可以指向任意類型的變量 指針在初始化時一般int *p=NULL; NULL表示空指針,即無效指針 但它只是邏輯上無效,并不是真正地無效 如果指針指向一個非你控制的內存空間,并對該空間進行訪問,將可能造成危險&與*運算符 &運算的結果指向該變量的指針 int i, *p;p = &i; int *p, a10;p = a; int *p, a10;p = &a0; int *p, a10;p = &a5; *和指針的組合是一個變量
48、,該變量的地址和類型分別是指針指向的地址和指針定義時指向的類型 int i, *p;p = &i;*p = 0; int *p, a10;p = a;*p = 0; int *p, a10;p = &a0;*p = 0; int *p, a10;p = &a5;*p = 0;指針與數組 數組名可以看作一個指針 只是不能修改這個指針的指向 常指針 int a10; a的類型是int10 a的類型也是int* 指針可當作數組名使用,反之亦然 int *p, a10;p = a;p1 = 0;*a = 0;指針運算 int* p=NULL;p+;/* p的值會是多少? */ 指針的加減運算是以其指向
49、的類型的字長為單位的 int *p, a10;p = a; *(p+3) 等價于 a3 p+; *p 等價于 a1指針運算 int *p, *q, a10;p = a;q = &a2; q - p = ? q = p + 3; 運算法則 只能進行加減和關系運算 只能同類型指針之間或指針與整數之間運算“類型”本不存在 存儲器在保存數據時并不關心數據的類型 完全以二進制方式工作 我們向計算機發(fā)出的指令說明了某塊內存里數據的類型 一塊內存內保存著(61 62 63 64)16 以char類型看待每個字節(jié): abcd 以float類型看待每個字節(jié): 16777999408082104000000.00
50、0000 以int類型看待每個字節(jié): 1684234849依天屠龍,強強聯手int main(void) int a = 0, 1, 2, 3, 4, 5, 6, 7, 8; int i; unsigned char *p; p = (unsigned char*)a; /* 類型強轉了 */ for (i=0; isizeof(a); i+) PrintHexChar(pi); /* 把指針當數組用 */ putchar( ); 指針強轉后,可以把一塊內存當作另一種類型來處理強強聯手,我們可以隨意控制任意內存指針與函數 指針既然是數據類型,自然可以做函數的參數和返回值的類型 指針做參數的經典
51、例子: main() int x, y; swap(x, y); void swap(int x, int y) int temp; temp = x; x = y; y = temp;指針做參數 main() int x, y; swap(&x, &y); void swap(int *px, int *py) int temp; temp = *px; *px = *py; *py = temp;指針做返回值 printf(%s, GetInput();.char* GetInput(void)char str100;scanf(%s, str);return str; char stri
52、ng30;printf(%s, GetInput(string); . char* GetInput(char* str)scanf(%s, str);return str;三個月使用scanf目睹之怪現狀 int i;scanf(%d, i); /* 這樣會如何?*/ int i;scanf(%f, &i); /* 這樣又會如何?*/ char c;scanf(%d, &c); /* 這樣呢?*/數組做參數 和指針一回事兒 void ProcessArray(int* a). void ProcessArray(int a).動態(tài)分配內存 在 和中均定義了下面的函數 void* malloc
53、(size_t size); size_t是在中定義的數據類型,就是一個unsigned int 向系統(tǒng)申請大小為size的內存塊,把指向首地址的指針返回。如果申請不成功,返回NULL void free(void* block); 釋放由malloc()申請的內存塊。block是指向此塊的指針 malloc申請的內存,在被free之前,程序的任何部分都可以使用 當然,要使用必須得到指向它的指針動態(tài)分配內存 如果malloc()申請的內存不被free()程序就退出,將產生內存泄露(Memory Leak) “內存泄露”一詞類似“原料泄露”。泄露出去的原料不能被利用,導致生產過程中原料不足 ma
54、lloc()時,系統(tǒng)找到一塊未占用的內存,將其標記為已占用,然后把地址返回,表明此程序占用此塊內存,其它程序不能再用它 free()時,系統(tǒng)標記此塊內存為未占用,本程序不能繼續(xù)使用,所有程序可以申請使用 如果malloc()之后不free(),此塊內存將永遠不會被任何程序使用,就好像這塊內存泄露出去一樣防止內存泄露之道 在需要的時候才malloc,并盡量減少malloc的次數 能用自動變量解決的問題,就不要用malloc來解決 malloc一般在大塊內存分配和動態(tài)內存分配時使用 malloc本身的執(zhí)行效率就不高,所以過多的malloc會使程序性能下降 可以重復利用malloc申請到的內存 盡量
55、讓malloc和與之配套的free在一個函數內 盡量把malloc集中在函數的入口處,free集中在函數的出口處 以上做法只能盡量降低產生泄露的概率。完全杜絕內存泄露,關鍵要靠程序員的細心與責任感字符串(String)與字符數組、字符指針 字符串 一串以0結尾的字符在C語言中被看作字符串 用雙引號括起的一串字符是字符串常量,C語言自動為其添加0終結符 Hello world! 把字符串常量作為表達式直接使用,得到的值是該常量的地址 C語言并沒有為字符串提供任何專門的表示法,完全使用字符數組和字符指針來處理 字符數組 每個元素都是字符類型的數組 char string100; 字符指針 指向字符
56、類型的指針 char* p; 數組和指針可以等同看待,上面三者本質上是一回事字符串處理函數 在中定義了若干專門的字符串處理函數 strcpy: string copy char *strcpy(char *dest, const char *src); strlen: string length size_t strlen(const char *s); strcat: string combination char *strcat(char *dest, const char *src); strcmp: string comparison int strcmp(const char *s1, const char *s2); stricmp: string comparison ignoring case int stricmp(const char *s1, const char *s2);指針、數組以及其它的類型混合 基本數據類型 int、long、char、short、float、double 指針是一種數據類型 是從其它類型派生的類型 XX類型的指針 數組也是一種數據類型 是從其它類型派生的類型 每個元素都有一個類型 任何類型都可以做指針或者數組的基礎類
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 企業(yè)辦公空間裝修合同
- 設備租賃與售后服務合同全新版
- 工程車輛采購合同樣本
- 有限合伙投資入股合同模板
- 服裝公司供應商合同管理范本
- 度安全生產目標責任合同范本
- 企業(yè)年會承辦合同范本(專業(yè)版)
- 美團押金合同范本
- 20《金字塔:金字塔夕照》教學設計-2023-2024學年五年級下冊語文統(tǒng)編版
- 15《真理誕生于一百個問號之后》教學設計-2023-2024學年六年級下冊語文統(tǒng)編版
- 山東省濟南市2024-2024學年高三上學期1月期末考試 地理 含答案
- 2025年湘教版二年級美術下冊計劃與教案
- 藥品注冊管理辦法課件
- 2024-2030年中國自動光學檢測儀(AOI)市場競爭格局與前景發(fā)展策略分析報告
- 2024-2025學年人教版數學八年級上冊期末模擬試卷
- 《智能制造單元集成應用》課件-數控機床參數備份與恢復
- 中學學校2024-2025學年工作計劃
- 四川省成都市2023年中考道德與法治真題試卷(含答案)
- 【初中生物】病毒課件2024-2025學年人教版生物七年級上冊
- 企業(yè)愿景和未來三年規(guī)劃
- 發(fā)酵饅頭課件教學課件
評論
0/150
提交評論