第二章 C 語言基本概述 C 語言的基本語法 關鍵字 vs. 識別字 各種程式錯誤 提高程式的可讀性 簡單的 C 程式 下面的程式碼可印出兩行字串 :. 簡單的例子 含括指令與標頭檔 (/) #include 是前置處理器的指令 #include 稱為含括指令 語法為 #include < 標頭檔 > 含括指令與標頭檔 (/) 含括動作前後的比較 : 前置處理器以標頭檔 (header file) 的內容取代 #include < > 因為是在編譯前執行, 所以稱為 " 前置 " 處理器 #include <stdio.h> #include <stdlib.h>
含括指令與標頭檔 (/) 不含括 stdio.h 或 stdlib.h 標頭檔也可以編譯? 含括指令與標頭檔 (/) 標頭檔的內容 : 標頭檔內是工具函式的宣告, 例如 printf() 在 stdio.h 中, system() 在 stdlib.h 中, 程式裡有使用到的工具函式才需要含括對應的標頭檔案 某些編譯器會將常用的標頭檔自動含括 有些編譯器會出現警告訊息, 並自動含括一些標頭檔 早期的 C 編譯器沒有適當宣告時有一些預設的法則 ; ANSI C 的編譯器如果沒有含括所使用函數的標頭檔, 所用到的工具函數沒有適當的宣告時即無法編譯 函數 (function) main() main() 函數是你的程式執行的起點 程式區塊及本體 程式區塊與本體的範圍 : 每個 C 程式必須有一個 main() 函數, 而且只能有一個 函式
變數的使用 宣告方式 : 變數是 CPU 執行演算法過程中存放資料的地方 int num; /* 宣告名稱為 num 的整數變數 */ int a,b,c; /* 宣告 a,b 與 c 為整數變數 */ 同一敘述宣告三個變數 float sum=0.0; /* 宣告浮點數變數 sum, 並設值為 0.0 */ 變數裡存放的資料型態 : char 字元, 如 'A' '' 與 '&' 等 int 整數 long 長整數 如 - 等 short 短整數 float 單精度浮點數 如. -. 等 double 倍精度浮點數 變數的初始化 變數的使用 Integer Type short unsigned short int unsigned int long unsigned long Floating-Point Type float double long double Range in Typical Microprocessor Implementation - ~ 0 ~ - ~ 0 ~ - ~ Approximate Range 0 - ~0 0-0 ~0 0 0 - ~0 0 ~ Significant Digits : machine, operating system, and compiler dependent : not all numbers in the range can be represented precisely : The mass of one electron is approximately 0 - grams. Diameter of the Milky Way galaxy in kilometers is approximately 0 kms. : long double is the same as double for VC and VC00 0 ASCII 字元內碼表 變數的命名規則 0 0 0 NUL LF DC RS ( < F P Z d n x SOH VT NAK US ) = G Q [ e o y STX FF SYN SP * > H R \ f p z ETX CR ETB! +? I S ] g q { EOT SO CAN ", @ J T ^ h r ENQ SI EM # - A K U _ i s } ACK DLE SUB $. B L V ` j t ~ BEL DCL ESC % / C M W a k u DEL BS DC FS & 0 : D N X b l v HT DC GS ' ; E O Y c m w 變數名稱可以是英文字母 數字或底線 名稱中不能有空白字元 第一個字元不能是數字 不能使用到關鍵字 intel_x /* 正確 */ _AMD /* 正確, 變數的第一個字母可以是底線 */ dos /* 錯誤, 變數的第一個字母不能是數字 */ my dogs /* 錯誤, 變數不能有空格 */ goto /* 錯誤, 變數不能是 C 語言的關鍵字 */
變數的設值方式 宣告的時候設值 ( 初始化 ) int num = ; /* 宣告變數, 並直接設值 */ 宣告後再設值 int num,num; /* 宣告變數 */ char ch; num = ; /* 將整數變數 num 的值設為 */ num = 0; /* 將整數變數 num 的值設為 0 */ ch = m ; /* 將字元變數 ch 的值設為 'm' */ Strong type Language Weak-type Language: 變數使用前不需要宣告, 同一個變數裡可以放不同型態的資料 Strong-type Language: 變數在使用之前一定要宣告, 並且只能存放指定型態的資料, 限制嚴格的好處如下 : 避免變數名稱打錯 ( 如數字 0 與英文字母 O) 增加程式的可讀性 便於程式碼的維護 除錯容易. 識別字及關鍵字 格式化的輸出函數 printf() 利用 printf() 函數在螢幕上印出字串 : 識別字 (identifier) 識別字是用來命名變數或函數的文字 識別字
關鍵字 (keyword)(/) 關鍵字是 C 語法的基本元素. 識別字及關鍵字 關鍵字 (keyword) (/) 下表為 C 語言的關鍵字. 識別字及關鍵字 關鍵字 (keyword) 或稱為保留字 (reserved word) 程式錯誤的分類. 除錯 語法錯誤. 除錯 語法錯誤 (syntax error) 程式含有不合語法的敘述, 它無法被編譯程式翻譯 下面是有語法錯誤的程式 : 語意錯誤 (semantic error) 語意錯誤 ( 又稱邏輯錯誤 ), 就是程式的執行結果與寫程式者的預期不同 0
語意錯誤 下面是語意錯誤的程式 : /* prog_a, 語意錯誤的程式 */ #include <stdio.h> #include <stdlib.h>. 除錯 語意錯誤通常是你以為電腦會做的, 和電腦實際做的之間有落差. 誤會一場 提高程式的可讀性 (/) 列印程式碼時請用固定字距. 提高程式的可讀性 int main(void) { int num = ''; /* 宣告整數變數 num, 並設值為 '' */ printf("i have %d dogs.\n", num); system("pause"); return 0; } /* prog_a OUTPUT --- I have 0 dogs. ---------------------------------*/ 提高程式的可讀性 (/). 提高程式的可讀性 列印程式碼時使用非固定字距, 且斜體字的程式碼, 較難閱讀 提高程式的可讀性 (/) 程式碼縮排與對齊, 分隔不同的細節層次. 提高程式的可讀性
提高程式的可讀性 (/) 註解有助於程式的閱讀與偵錯. 提高程式的可讀性 C 是 Free Format 的語言 #include<stdio.h> #include<stdlib.h> int main(void){ printf("helloworld!\n"); system("pause"); return 0; } #include<stdio.h> #include<stdlib.h> int main(void){printf("helloworld!\n");system("pause");return 0;} int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++ Hell\ oworld!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);} The International Obfuscated C Code Contest http://www.ioccc.org/years.html Winner of the international C obfuscation contest in 00 #include <unistd.h> #include <curses.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <sys/time.h> #define o0(m,w) mvprintw(w,m?m-:m,"%s%s ",M?" ":"",_) #define O0(M,W) M##M=(M+=W##M)-W##M #define l(m,w) M.tv_##W##sec #define L(m,M,l,L,o,O) for(l=l;l--;)((char*)(m))[o]=((char*)(m))[o] #define I ll,(struct sockaddr*)&il #define i COLS #define j LINES #define L_ ((j%)?j:j-) fd_set I;struct socka\ ddr_in il;struct host\ ent*li; struct timeval IL,l;char L[],_[<<] ;void (int ){_[ --]=+0;if( ++ ) (-- );_ [ ]='=';}double o,oo=+0,oo=+0.; long O,OO=0,oO=,ii,iI,Ii,Ll,lL, II=sizeof(il),Il,ll,LL=0,i=0,li, li;int main(int\ il,char *Li[]){\ initscr();cbreak ();noecho();nonl (); (li=i/); _[0]='[';_[lI-] =']';L(&il,&_,\ II,O,+O,+lI);il. sin_port=htons(( unsigned long)(\ PORT&0xffff));lL =l_;if(il=!--il) {il. sin_addr.\ s_addr=0;bind(i,ii);listen(ll, );ll=accept(i,& II);}else{oO-=; LI=gethostbyname (Li[]);L(&(il. sin_addr),(*li). h_addr_list[0],\ LI->h_length,iI, ii,ii);(*(&il)). sin_family=(&(*\ LI))->h_addrtype ;connect(i,ii); }ii=ii=(o=i*0. )- li/;ii=l_-;o =li=l_*0.;while (_){mvaddch(+oo, oo,' ');o0(ii,ii );o0(ii,il-=il); mvprintw(li-,il,"%d\n\n%d",i,ll );mvhline(li,+0, '- ',i);mvaddch( O,o,'*');move(li,Il);refresh();\ timeout(+speed); gettimeofday(&il,+0);ll=getch(); timeout(0);while (getch()!=err);\ if(ll=='q'&&il)\ write(ll,_+,); if(ii>(ll=0)&&ll ==','){write(ll, _,-(--Il));}else if(ll=='.'&&ii+\ li<i){write(ll, _+li,++il);}else if(il!il)write (ll,_+li-,-); gettimeofday(&l, 0);II=((II=l(IL,)+(l(l,u)-=l( IL,u))-l(l,)+(\ l(l,)-=l(il,)) )<0)?+II-l(l,) +e+(--l(l,)): II;usleep((II+=\ l(l,)*e-speed *e)<0?-ii:+0); if(ll=='q'&&!il) break;fd_zero(&i );FD_SET(lL,&I); memset(&*&il,ll, sizeof(l));if((\ Ll=select(lL+,& I,0,0,&IL)));{if (read(ll,&l,ll+ )){if(!*l){ll++; }else if(*l==ll[ _]){ll--; }else\ if(*(&(*l))==[_ ]){break;}}else{ break;}}o0(o,o); O0(O,o);if(o<0){ o*=-;oo*=-;}if (o>i){o=i+i-o ;Oo*=-;}if(o>=( Ii+=ll)&&O<&&oO <0&&o<Ii+lI){O= ;oo=~-- oo;oo+=ll *e-;}if(o<0){o =ii;ll++;}if(o>= (ii+=il)&&o>ii- &&oo>0&&o<ii+li){o=ii- ;oo=~--oo;oo+=il*e- ;}if(+o>+ii){o- =O;i++; }}endwin();return(0);} Network based Pong game