今日目標
1. 複習進度
2. 小考及作業
3. 題目練習
一個美好的編輯器
個人化你的 Dev-C++
舒服最重要~微調 Dev-C++
一般設定
顯示設定
語法配色
–
右鍵貼上測資 快速編輯模式
簡易漂亮縮排法
同一區塊的程式敘述對齊
若 B 區塊包含於 A 區塊,則 B 區塊往後縮 排一單位
EX
for(i=0;i<n;i++){
a[i]=i;
if(a[i]==i){
a[i]=0;
} }
當區域變數與全域變數 糾結在一起
了解程式區段、區域變數與全域變數
程式區塊
C 以 {
statement;
}
來表示一塊塊的程式區塊,在許多語法中會也與其串 接
Ex
if(true) do sth. // 只做這件事 if(true){
do sth1. // 做了這些事 do sth2.
}
區域變數的作用範圍
C 是區塊式結構的程式語言,每個由大括 弧所組成的區塊都是一個獨立的結構。
在每一個區塊, C 會建立一個獨立的命 名空間,使用者可以在這個命名空間內對 變數任意取名字(但不能與保留字衝突,
也不能取相同的名字),但到區塊外就無 法存取了。
區塊內的變數又稱為區域變數,所能作用 的範圍只有該區塊內。
區域變數的作用範圍
{
int x,y;
x=1;
y=2;
}
int x;
x=?;
y=2;
Question 1 :
第一個 x 與第二個 x 一樣嗎 Question 2 :
第二個 y 存在嗎 ?
區域變數的好處
1. 只存活於自己作用的區段,不會在不 需要的區段出現,也不會有誤用的情況。
2. 區段結束後記憶體會自動釋放。
3. 除錯容易
全域變數
在函數之外宣告的變數被稱為全域變數。
全域變數自宣告後,
一直存在,直到程式結束為止。
在整個程式中,
一個全域變數的名稱只能被宣告一次。
全域變數的作用範圍從宣告處開始,直到 檔案的結束。
全域變數的作用範圍
void Function(){
x=2;
}
int x;
int main(){
x=1;
return 0;
}
Question :
這樣的程式會通過編譯嗎 ?
全域變數的好處
1. 減少函數輸入的引數
2. 能使用較大的記憶體
變數常犯的錯誤
當區域變數與全域變數有相同的名稱時,
編譯器並不會出現編譯錯誤,但常常會因 此而出問題。
int n;
int main(){
int n;
scanf(“%d”,n);
}
1+1+1+….+1=N*1
各類迴圈
while
while( 判斷式 ){
程式敘述 ; ...
}
執行迴圈之後的敘述 檢察判斷式
是否為真
迴圈內程式敘述
否
是
do…while
do {
程式敘述 ; ...
}while( 判斷式 );
執行迴圈之後的敘述 檢察判斷式
是否為真
迴圈內程式敘述
否
是 迴圈內程式敘述
for
for( 起始式 ; 判斷式 ; 運算式 ){
程式敘述 ;
… }
執行迴圈之後的敘述 檢查判斷式
是否為真
迴圈內程式敘述
否
是 起始式
運算式
break; 與 continue;
在迴圈敘述中, break; 會直接跳出迴圈
,執行迴圈之後的程式敘述。
而 continue; 則是會直接跳到該次迴圈的 最尾端 (PS. 若為 for 迴圈仍會執行運算 式 )
陣列
型態 陣列名稱 [ 元素個數 ];
宣告時元素個數要為常數,盡量不要以變 數當作元素個數。
陣列占用的是連續的記憶體。
EX:
int array[1000];
array[0] array[1] array[2] … … … Array[n-1]
多維陣列
型態 陣列名稱 [ 元素個數 1] [ 元素個數 2]…[ 元素個 數 n];
多維陣列占用的依然是連續的記憶體
EX:
int A[100][100];
A[0] A[1] … A [n- 1]
A[0][0] … A [0][m-
1] A[1][0] … A [1][m-
1]
指標
指向變數的型態 * 指標名稱 ;
一種指向記憶體位置的變數
取位置的 &
要對一般變數找到其在記憶體上的位置,
只需在變數的前加上 & 即可。
& 不能加在指標的前面, & 指標,代表 指標在記憶體上的位置。
EX:
int a=2;
int *ptr;
ptr=&a;
取值的 *
要對一個指標找到其在記憶體上變數的值
,只需在指標的前加上 * 即可。
* 不能加在一般變數的前面,否則會編譯 錯誤。
EX:
int a;
int *ptr;
ptr=&a;
*ptr=2;
指標的型態
指標只是指向記憶體的一個變數,型態對 其來說並不重要
會影響到的只有取值以及運算的時候。
指標 NULL 不可以取值
NULL 不指向任何地方,故不會有值,所 以對 NULL 取值的話會記憶體存取錯誤
。
陣列與指標
陣列所用的是一段連續的記憶體,而陣列 的另外一個含意就是指向記憶體的指標。
例如有一個陣列 A[m] ,則 A 指向變數 A [0] 的位置 ,A+i 指向 A[i] 的位置,又如有 一個陣列 A[m][n] ,則 A 指向 A[0][0] 的 位置, A+i*n+j 指向 A[i][j] 的位置。
但不可以將陣列像一般指標一樣指向其他 的記憶體。
函數
回傳值型態 函數名稱 ( 型態 1 引數 1, 型態 2 引數 2,…){
…
return 回傳值 ; }
為依據每次的引數進行相同操作,並回傳 結果的一個程式區塊。
若回傳值型態為 void 時不須回傳任何東 西。
遞迴函數
遞迴函數是呼叫自己的函數
通常會將問題切割成許多小問題在交由函 數繼續遞回下去解決
EX
int FAB(int x){
if(x==1) return 1;
else if(x==2) return 2;
return FAB(x-1)+FAB(x-2);
}
遞迴常見的問題
1. 函數沒有回傳值
2. 遞迴沒有結束條件
3. 遞迴的引數出錯
4. 遞迴使用了不同函式的變數
5. 變數名稱與全域函數相同
6. 邊界回傳值不正確
( 以上感謝 silentvow 學長整理 )
qsort()
qsort(
第一個元素的指標 , 元素的個數 ,
每個元素所占用的 byte 數 , 比較函式 );
qsort()
int cmp(
const void* a 元素的指標 , const void* b 元素的指標 ){
int *A=(int*)a;
int *B=(int*)b;
若 a 的順位在 b 前面回傳負值 ; 若 a 的順位在 b 後面回傳正值 ; 若 a 的順位跟 b 一樣回傳 0;
}
字串
C 的字串以字元 (char 型態 ) 陣列表示
’
並以字元 \0’ 表示字串結束
需要注意開 char 陣列時要多留一個位置
’
給 \0’
gets 與 puts
char *gets( char *str );
讀入字元直到換行或 EOF( 讀完一整行 )
會回傳讀入字串的位置
若讀到 EOF 會回傳 NULL
int puts( char *str );
印出一字串並換行
若印出成功回傳一非負整數
若印出失敗回傳 EOF
strcmp 與 strncmp
int strcmp( const char *str1, const char *str2 );
比較兩字串
若兩字串相同則回傳 0
若 str1 的字典順序較小回傳一 負整數
若 str1 的字串順序較大回傳一 正整數
int strncmp( const char *str1, const char *str2, size_t count );
與 strcmp 相同,不過只比較前 count 個字 元
strcpy 與 strncpy
char *strcpy( char *dest, const char *src );
char *strncpy( char *to, const char *from, size_t count );
strcpy 是將一個字串複製到另外一個字串
而 strncpy 是將一個字串的前 count 個字元複 製到另一個字串,但需要注意的是,複製過
’
去後並不會補上 \0’
strtol
long strtol( const char *start, char **end, int base );
strtol 可以用來分割字串裡面的多個數字
start 為字串的指標
end 為第一個數字之後的部分
當 end 變成 NULL 時,代表已經取完了
strlen
size_t strlen( char *str );
strlen 會回傳字串的長度
需要特別注意放入的指標不可以是 NULL
EX
char str[]=“hello”;
len=strlen(str);
memset
void* memset( void* buffer, int ch, size_t count );
memset 將會將記憶體的某一個區段都填 上某一個值,可用來幫助初始化
注意:只能用來初始化 0 或 -1 ( 想想計概的表示法 )
EX
memset(array,0,sizeof(array));
作業
題目練習
UVa Online Judge
http://uva.onlinejudge.org/
Q272,Q458,Q494
Q10062,Q10222
翻譯