260 likes | 457 Vues
CLASS 5 指標. int my_abs(int); int rect(int,int); int main(){ int x,y,r; printf(“ 請輸入長方型的長 :”); scanf(“%d”,&x); printf(“ 請輸入長方型的寬 :”); scanf(“%d”,&y); printf(“ 長方型的面積 :%d<br>”,rect(my_abs(x), my_abs(y))); return 0; } int rect(int x,int y){ return x*y; }
E N D
int my_abs(int); int rect(int,int); int main(){ int x,y,r; printf(“請輸入長方型的長:”); scanf(“%d”,&x); printf(“請輸入長方型的寬:”); scanf(“%d”,&y); printf(“長方型的面積:%d\n”,rect(my_abs(x), my_abs(y))); return 0; } int rect(int x,int y){ return x*y; } int my_abs(int num){ if(num<0)num*=-1; return num; }
複習 srand(time(NULL)); int rand_num=(rand()%901)+100;//100~1000 printf(“亂數:%d, 平方根%lf\n”,rand_num,sqrt(rand_num));
想一想 • 下面這個函式作什麼事情? • 應該是交換num1和num2,但其實並沒有,why? • 因為上面的函式只是把變數的值傳進去,函式更改的是變數的複製品,而不是真正變數在記憶體存放的值
何謂指標? • 一般正常的變數 • 儲存的是程式當中用來記錄或是做計算用的數值 • 指標變數 • 變數的內容儲存的是另一個變數的記憶體位址值
兩個運算子 • 取址運算子(&) • 取得一個變數的記憶體位址 • 提領運算子(*) • 間接讀取指標所指向的記憶體位址資料
指標變數的宣告 • 語法 • 資料型態 *指標變數名稱; • 資料型態代表這個指標變數所存放的位址要以什麼樣的資料型態(記憶體大小)來解讀 • int *countPtr; • 指定初始值的宣告 • Int count; • int *countPtr=&count;
0022FF70 0022FF74 countPtr 0022FF74 8 count 範例練習 • 實地操作變數、指標變數以及*、&運算子,並觀察結果
為什麼要用指標? • 當我們希望傳入的引數在函式中修改其值時,我們必須利用指標變數來取得修改的權利 • 如果只有一個需要改變,也可利用return • 指標變數代表一個位址,假如我們有一塊很大的連續記憶體(如陣列)要傳入函式,使用指標變數是有效率的 • 因為在參數初始化時,只需複製一個位址,而不必將整個連續記憶體的內容都複製一份 • 交換兩個複雜資料型態的變數時,只需交換指向它們位址的指標即可,增加程式運算的速度
範例練習 • 撰寫一個真正可以交換兩數的函式,並在主函式呼叫它
const常數修飾子 • int *ptr; • ptr可變動,*ptr也可變動 • int *const ptr; • ptr不可變動,*ptr可變動 • const int *ptr; • ptr可變動,*ptr不可變動 • const int *const ptr; • ptr不可變動,*ptr也不可變動
指標與陣列名稱 • 宣告陣列時,陣列的名稱本身就可以看作是一個指標 • 常數指標 • 不能更改這個常數指標的值 • 存放的位址 • 陣列第一個元素在記憶體的位址 • 利用索引和這個記憶體位址,我們可以取得陣列中各元素的值 • int array[5]; • array是一個位址//printf(“%d”,array); • //array[0]放在array+0*sizeof(int)的位址 • //array[2]放在array+2*sizeof(int)的位址
指標的運算 • 指標的加減運算,只有對陣列執行時才有意義 • 因為我們不能假設相同型態的兩個變數一定會連續地存放在記憶體中,除非它們是同一陣列內相鄰的兩個元素 • int arr[6], *ptr=arr; printf(“%d”,*ptr); //印出100 ptr++; printf(“%d”,*ptr); //印出200 ptr+=2; printf(“%d”,*ptr); //印出400 printf(“%d”,ptr-arr); //印出3
陣列與指標的交換性 • int arr[10],*ptr; • ptr=arr; /*這兩行 • ptr=&arr[0]; 做的是一樣的事情*/ • int arr[10],*ptr=arr; //ptr為一指向arr的指標 • arr[2]、*(arr+2)、ptr[2]、*(ptr+2)是相同的東西 • 注意 • 陣列與指標不同在於陣列名稱是常數指標 • arr++; • 不合法,因為arr是常數指標,不可更改指向位址 • ptr++; • 合法,ptr是指標變數
存取陣列裡的元素 • 使用[ ]陣列運算子 • array[i],i值決定要取用從array位址起算要位移幾個元素長度,單位元素長度(記憶體大小)取決於陣列的資料型態 • 使用*提領運算子 • array+i,表示從array這個位址,位移i個單位元素的位址,單位同樣取決於陣列的資料型態 • 給定位址後,配合提領運算子,取用第i個元素即是用*(array+i)
array 指標與一維陣列 • 宣告一維陣列,程式執行時,系統會保留一塊連續的記憶體 • int array[8]; • 陣列array • 代表這一段連續記憶體的起始位址,亦即此陣列第一個元素的記憶體位址(&array[0])
array+1 array+1[2] 存取陣列裡的元素2 • (array+1)[2]表示的是*(array+1+2)也就是array[3]的位置 • 注意 • 因為*運算子的優先權大於+,所以*array+i表示的是這個位址的元素値加上i • *(array+2)是18 • *array+2是 25+2=27 • *(array+2)是可接受數值的變數(可以放在指定運算子=的左邊),但*array+2只是一個數值而已
練習 • 將長度為5的一維陣列傳入函式 • (用rand()產生5~105的值) • 在函式內將陣列裡面的值-5 • 在主程式印出新的值 • void sub_five(int*); • int main(){ • int i,num[5]; • srand(time(NULL)); • //亂數產生5個值,並印出 • sub_five(num); • //印出陣列裡新的值 • } • void sub_five(int* num){ • //將陣列裡的值減5 • }
指標與多維陣列 • 多維陣列的記憶體配置 • 每一個元素在記憶體裡順序,是以最低的維度排起,由小到大 • int num[3][2]; num[0] num[1] num[2] • num所指的單位元素是一個擁有2個整數的一維陣列
指標與多維陣列2 • 在陣列宣告時,指定了較低的維度擁有2個元素,編譯器 (compiler)看見num[1]才知道往後移動的一個單位是一個長度為2個整數的一維陣列 • 存取num[1][0]的寫法 • num[1][0] • (*(num+1))[0] • *(*(num+1)+0) • *(num[1]+0) • 使用提領運算子後,*(num+1)仍然是一個指標
以多維陣列為函式的參數 • 假設要傳給函式的是一個二維陣列,其宣告是 int num[3][2]; • 函式的參數列:void test(int num2[3][2]) { } • 參數num2所指的是一個擁有兩個整數的一維陣列,總共有三個這樣的一維陣列 • 相同寫法 • void test(int num2[ ][2]) { } • void test(int (* num2)[2]) { } • 不合法的寫法 • void test(int *num2[2]) { } • 宣告了一個陣列放了兩個指標變數
指標的指定與轉換 • int num[3][2], *num2; • num2=num; • 不合法的指定敘述 • 因為num2所指的元素是一個整數,而num所指的元素是一個一維陣列 • 仍然可以透過強制型態轉換,把num2成功的指向num所指的位址。 • num2=(int *)num; • num2跟num分享同樣的位址 • num2 num2[1] num2[2] num2[3] num2[4] num2[5]
補充 (malloc and free) • int main(){ • int *pt; • int size,i; • printf("請輸入陣列的大小: "); • scanf("%d",&size); • pt=(int*)malloc(sizeof(int)*size); • for(i=0;i<size;i++) • pt[i]=rand()%10+1; • for(i=0;i<size;i++) • printf("%d ",pt[i]); • free(pt); • system("pause"); • }
補充 (malloc and free) • (指標的型態)malloc (sizeof(陣列的資料型態)*陣列大小); • 範例 • float* pt=(float*)malloc(sizeof(float)*size); • char* pt=(char*)malloc(sizeof(char)*size);
作業六 • 參見hw6.doc • (到www.csie.ntu.edu.tw/~r93041/C下載)
作業六(也可以試著做這一個) • 讓使用者輸入陣列的大小,並產生int陣列 • 提示:用malloc • 讓使用者輸入值到陣列裡 • 將陣列傳到一個自訂的函式裡,做排序 • 在主函式輸出排序結果