1 / 55

第 八 章

第 八 章. 指標 (Pointer). 大綱. 8.7 指標與函數 8.8 指標與結構 8.9 指標中之指標 8.10 指標指向函數 8.11 指標陣列 8.12 指標常犯之錯誤. 8.1 位 址運算子 & 8.2 指標之宣告 8.3 指標之使用 8.4 記憶體配置 8.5 指標與陣列 8.6 指標與字串. 8.1 位 址運算子 &. 一般變數皆為靜態的資料,若欲取得該變數之位址,只能使用 位址運算子 ( Address Operator ) 「 & 」 ( Ampersand ) int a=10;

regis
Télécharger la présentation

第 八 章

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第八章 指標(Pointer)

  2. 大綱 • 8.7 指標與函數 • 8.8 指標與結構 • 8.9 指標中之指標 • 8.10 指標指向函數 • 8.11 指標陣列 • 8.12 指標常犯之錯誤 • 8.1 位址運算子& • 8.2 指標之宣告 • 8.3 指標之使用 • 8.4 記憶體配置 • 8.5 指標與陣列 • 8.6 指標與字串

  3. 8.1 位址運算子 & • 一般變數皆為靜態的資料,若欲取得該變數之位址,只能使用位址運算子(Address Operator) 「&」(Ampersand) • int a=10; • cout << &a; //輸出位址 00A5 • cout << a; //輸出內容 10

  4. 例題: 列印一般變數之位址。 #include <iostream> //cout using namespace std; int main( ){ short a=10, b; //短整數佔2bytes int c=23, d; //整數佔4 bytes float p=1.1, q; //浮點數佔4bytes cout << “&a=” << &a << endl; cout << “&b=” << &b << endl; cout << ”&c=” << &c << endl; cout << “&d=” << &d << endl; cout << ”&p=” << &p <<endl; cout << “&q=” << &q << endl; return 0; } 位址會因電腦不同而異

  5. 8.2 指標之宣告 • 指標是一種間接指向,在宣告上與一般變數不同。 • 資料型態 *變數名稱; //星號在變數之左上方 如 int *a, *b, *c; • 資料型態* 變數名稱; //星號在資料型態之右上 如 int* a, * b, * c; • 宣告 int *ptr 後變數ptr稱為指標變數,它是儲存『位址的值』, *ptr為內容,其意義如下: • *ptr: 表ptr位址內所指示之內容 • ptr: 表儲存位址

  6. 8.3 指標之使用 • 指標變數在使用時,不可指向不存在(void)之位置,否則會造成不可預料的結果,使用指標應遵循下述兩種狀況: • 1. 指向已存在之位址。 • 2. 要求分配記憶體。 • 讓指標指向已存在位址就是將一般變數之位址設定給指標變數,讓一般變數與指標共用同一塊記憶體,只要一般變數內容改變,指標變數之內容也會改變,反之亦然。 • int a=10,*p; • p=&a; a 10 *ptr

  7. 8-3-1指標與位址運算子 • *與&兩者皆為指標之參考符號 • 兩者之關係如: • int *ptr, a=10; //宣告ptr為指標變數 • ptr = &a; //ptr存變數a的位址 • 將a之位址設定給ptr,接著兩變數皆指向同一塊記憶體,變數利用「&」取得位址 。 a 10 *ptr

  8. 8-3-2 指標型態之一致性 • 指標型態之一致性: 指向已存在之指標變數應與其資料型態一致,因不同型態之指標是無法轉換的。 • 列印數值(內容): • 一般變數 cout << a; • 指標變數 cout << *ptr; • 列印位址: • 位址運算子 cout << &a; • 指標變數 cout << ptr;

  9. 8-3-3 指標之設定 • 同樣指標型態可以互相設定,亦即可使許多指標指向同一位址,如下例,p1與p2同樣指向x,即三者指向同一地點。 *p1 10 x *p2

  10. 例題: 指標間之設定。 #include <iostream> //cout using namespace std; int main( ){ int x=10; int *p1, *p2; p1 = &x; p2 = p1; //指標間之設定 cout << "p2=" << p2 << endl; cout << “*p2=”<<*p2<<endl cout <<”*p1=”<<*p1<<endl; cout <<”x=”<<x<<endl return 0; } 執行結果: p2=0064FE00 *p2=10 *p1=10 x=10

  11. 8-3-4 指標位址之運算 • 指標位址之遞增或遞減,如宣告*ptr;後之ptr++, ++ptr或ptr--, --ptr等係針對所存在之位址作該資料型態大小作加減,而非加一或減一之運算。 • 如:int *ptr, a[3]={10,20,30}; • ptr = &a; • 若&a之位址為「0064FE00」,則ptr之內容亦為「0064FE00」。 • ptr++; // ptr之內容就變為「0064FE04」

  12. 宣告 運算 增減量 char *ch; ch++; ch--; 1 int *ptr; ptr++; ptr--; 4 float *f; f++; f--; 4 double *d; d++; d--; 8 資料型態遞增減之增減量 • 單位為bytes

  13. 例題: 利用指標作運算。 #include <iostream> //cout using namespace std; int main( ){ int *ptr, a=10; ptr = &a; cout << ptr << ","<< &a << endl; cout << *ptr << a << endl; (*ptr)++; cout << "a="<< a << endl; return 0; }

  14. 例題:字串利用指標作運算。 #include <iostream> //cout using namespace std; int main( ){ char *ch, s[6]="abcde"; //字串 ch = s; cout << ch << ","<< ++ch << endl; cout << s << ","<< s+1<< ","<<s[4]<<endl; return 0; }

  15. 例題:整數陣列利用指標作運算。 #include <iostream> //cout using namespace std; int main( ){ int s[5]={10,20,30,40,50}; int *ptr = s; for (int i=0; i<5; i++) cout << "s["<<i<<"]="<< &s[i] <<endl; cout << "*ptr內容="<< *ptr << endl; cout << "ptr位址="<< ptr << endl; ptr = ptr + 1; cout << "ptr+1內容="<< *ptr << endl; cout << "ptr+1位址="<< ptr << endl; return 0; }

  16. 8.4 記憶體配置 • 對於陣列大小設定需給定一常數值,且大小設定後更改困難, 用完後記憶體無法歸還。 • 下列方式是錯誤的: cin >> size; int a[size]; • 指標要求分配記憶體時,指令敘述為new, 當記憶體使用完要歸還或釋放時指令敘述為delete, 兩者必須相互的出現。

  17. 8.4.1 new與delete之使用 • 分配或釋放記憶體之敘述格式: • 指標變數 = new 資料型態[大小](初值); //配置 • delete [ ] 指標變數; //釋放 • 配置記憶體 • 配置單一記憶體 • 配置單一記憶體並給予初值 • 配置多個記憶體: 以指標當陣列使用,有固定大小及彈性大小。

  18. 8.4.2 配置單一記憶體 • 指標變數 = new 資料型態; • delete 指標型態; • 如: • double *f; • f = new double;//配置一個浮點數空間 • delete f; //釋放一個空間,在delete 後不必加入[ ]

  19. 例題: 配置記憶體空間,輸入資料及顯示指標變數位址 #include <iostream> //cout using namespace std; int main( ){ int *a, *b, c; a= new int; b= new int; //分配空間 cout << "a之位址="<< a << endl; cout << "b之位址="<< b << endl; cout << "c之位址="<< &c << endl; cout << "輸入a, b="; cin >> *a >> *b; c = *a + *b; cout <<"c=" << c << endl; delete a; //交回分配之記憶體 delete b; return 0; } a之位址=0x00672d54 b之位址=0x00672d64 c之位址=0x0064fe00 輸入a,b=10 20 c=30

  20. 8.4.3 配置單一記憶體並給初值 • 指標型態 = new 資料型態(初值); • delete 指標型態; • 如: int *a; a = new int(10);//則*a之值為10,而非設定10個int空間 或 int *a=new int(10); //宣告,配置與初值合併

  21. 例題: 指標初值之設定(來自計算值) #include <iostream> //cout using namespace std; const doublePI=3.14159; const doubleradius = 10.0; int main( ){ float *area=new float(PI*radius*radius); cout << "Area="<<*area<<endl; cout << area << endl; delete area; cout << *area << endl; cout << area << endl; return 0; }

  22. 8.4.4 配置多個記憶體 • 指標變數 = new資料型態[大小]; • delete[ ]指標變數; • 如: • int *a; • a=new int[5]; //配置5 * 4=20 Bytes給a,固定大小。 • delete [ ] a; //釋放a之空間

  23. 例題:以指標輸入10個浮點數資料,求平均。(固定大小)例題:以指標輸入10個浮點數資料,求平均。(固定大小) #include <iostream> //cout using namespace std; int main( ){ float *f, sum=0, ave; f = newfloat[10]; cout << "Enter 10 data:\n"; for (int i=0;i<10;i++){ cin >> *(f+i); sum+= *(f+i); } ave=sum/10.0; cout << “10個數平均=" << ave << endl; delete[ ] f; return 0; }

  24. 例題: 指標資料之排序,輸入三指標變數資料後由小到大輸出。 cout << "排序後:"<<*a<<" "<<*b <<" "<<*c<<endl; delete c; //釋放記憶體 delete b; delete a; return 0; } void swap(int *a, int *b){ if (*a>*b) { int t = *a;   *a = *b; *b = t; } } #include <iostream> //cout using namespace std; void swap(int *a ,int *b); int main( ){ int *a,*b,*c; a = new int; //配置記憶體 b = new int; c = new int; cout << "輸入a,b,c="; cin >> *a >> *b >> *c; swap(a,b); //交換 swap(b,c); swap(a,b);

  25. 例題: 以指標來設定彈性陣列。 #include <iostream> //cout using namespace std; int main( ){ int *a, size, i; cout <<"輸入陣列大小:"; cin >> size; a = new int[size]; //分配記憶體 for (i=0; i<size; i++){ cout <<i<<“:”<< (a+i) <<“="; //輸出位址 cin >> *(a+i); } cout <<”輸出資料:”; for (i=0; i<size; i++) cout << *(a++) <<" "; delete[ ] a; //釋放記憶體 return 0;}

  26. 8.5 指標與陣列 • 指標與陣列兩者具有相當的密切關係,如: • int str[30], *ptr; • ptr = str; 或 ptr = &str[0]; • 表ptr已被設定到str陣列第一個元素,因此要存取第五個元素可以如下寫法: • str[4]; • *(str+4); • *(ptr+4);

  27. 陣列存取資料之方法 • 設宣告int a[5], *ptr; • 以標準陣列方式存取, 如a[n]。 • 以陣列名稱加上索引值來存取,如*(a+n)。 • 以指標變數加上索引值來存取,如*(ptr+n), 需事先執行ptr=a或ptr=&a[0]。 • 以指標來存取陣列之元素比以索引來存取陣列之元素之速度較快。

  28. 8.5.1 陣列名稱之指標用法。 #include <iostream> //cout using namespace std; int main( ){ int *ptr, a[5]={5,10,15,20,25}, i; cout <<” 標準存取: ”; for (i=0; i<5; i++) cout << a[i] << “ “; cout << endl; cout <<” 陣列名稱存取: ”; for (i=0; i<5; i++) cout << *(a+i) << “ “; cout << endl; cout <<” 指標存取: ” ; ptr = a; for (i=0; i<5; i++) cout << *(ptr+i) << “ “; cout << endl; return 0; }

  29. 指標變數 陣列名稱 位址 內容 存取方式 ptr+0 a+0 0066FF00 5 a[0], *(a+0), *(ptr+0) ptr+1 a+1 0066FF04 10 a[1], *(a+1), *(ptr+1) ptr+2 a+2 0066FF08 15 a[2], *(a+2), *(ptr+2) ptr+3 a+3 0066FF0C 20 a[3], *(a+3), *(ptr+3) ptr+4 a+4 0066FFF0 25 a[4], *(a+4), *(ptr+4) ptr 0066FF00 指標與陣列

  30. 8.5.2 以指標變數取代陣列 #include <iostream> //cout using namespace std; const N = 5; int main( ){ int a[N], *ptr,i; ptr = a;//或ptr=&a[0] cout << "輸入”<<N<<”筆資料:"; for (i=0; i<N; i++) cin >> *(ptr+i);//以指標輸入 cout << "以陣列名稱輸出:"; for (i=0; i<N; i++) cout << *(a+i) << " ";cout << "\n"; return 0; }

  31. 8.5.3 陣列各元素位址之取得 #include <iostream> //cout using namespace std; const N = 5; int main( ){ int a[N], i, *ptr; cout << "以陣列元素:\n"; for (i=0; i<N; i++) cout <<"a["<<i<<"]="<< &a[i] <<endl; cout << "以指標:\n"; ptr = a; //或 ptr = &a[0]; for (i=0; i<N; i++) cout <<“ptr+”<<i<<“=”<< ptr+i <<endl; cout << "以陣列名稱:\n"; for (i=0; i<N; i++) cout <<"a+"<<i<<"="<< (a+i) <<endl; return 0;}

  32. 8.5.4 指標變數與二維陣列 #include <iostream> //cout using namespace std; const int N=4,M=3; int main( ){ int a[N][M], i, j, *ptr; ptr = &a[0][0]; for ( i=0; i<N*M; i++) cin >> *(ptr+i); cout <<” 陣列資料如下:\n”; for (i=0; i<N; i++){ for ( j=0; j<M; j++){ cout.width(3); cout << *(*(a+i)+j) << " "; } cout << "\n";} return 0; }

  33. 8.6 指標與字串 在C++內字串本身就是指標,因字串是屬於字元陣列, 如: #include <iostream> //cout using namespace std; int main( ){ char *ptr; char s[ ]="This is a string."; cout << "s= " << s << endl; ptr =s; cout <<”輸入字串:” ; cin >> ptr; cout << "輸入後: s=" << s << endl; return 0; } s=This is a string, 輸入字串:Clinton 輸入後:s=Clinton

  34. 例題: 將指標內字串搬移到另一字串內及ptr++之使用。 #include <iostream> //cout using namespace std; int main( ){ char *ptr="This is pointer string."; char s[25]; int i; cout << "ptr= " << ptr << endl; for (i=0; i<strlen(ptr)+1; i++) s[i]=*(ptr+i); cout << "搬移後 : s=" << s << endl; ptr++; //ptr=ptr+1;指向第二位置 cout << “ptr++=”<<ptr<<endl; ptr=ptr+4;//跳過4個位置到第6個位置 cout << “ptr+4=”<<ptr<<endl; return 0; } ptr=This is pointer string. 搬移後:s=This is pointer string. ptr++=his is pointer string. ptr+4=is pointer string.

  35. 8.7 指標與函數 • 函數之傳回值若以函數名稱傳回只有一個值, 這是以return傳回數值。 • 函數除了可傳回值外, 還可以利用參數傳回參考位址與指標位址, 解除只能傳回一個之限制。 • 若要傳回一個以上之資料就需利用參數之傳遞以傳回多個值, 使用方式有傳址(參考)呼叫(Call by Reference)及指標呼叫(Call by Pointer), 而函數名稱除了傳數值外亦可以傳址呼叫及指標呼叫傳回。

  36. 宣告 呼叫 函數定義 說明 int a; sum(&a,...); void sum(int *a,...) 指標參數傳回 int a; sum(a,...); void sum(int &a,...) 參考參數傳回 int *a; sum(a,...); void sum(int *a,...) 指標參數傳回 int *a; a=sum(…); int *sum(…) 函數名傳回 int *a, *b; a=sum(b,...); int *sum(int *b,...) 函數名,指標參數傳回 函數與指標之可能的組合

  37. 8.7.1 一般變數傳給指標 • 一般變數傳遞參數給函數, 若需再傳回, 在函數之參數需宣告為指標變數, 而呼叫者需以位址運算子「&」告訴函數 • 資料型態 函數名稱(資料型態*, …); //函數原型 • void call_fun( int*, int*); • 呼叫函數(&一般變數, …); //呼叫函數 • 如: { int a, b; • call_fun(&a, &b); …} • 資料型態 函數名稱(資料型態 *變數, …) //函數定義本體 • void call_fun( int *p, int *q) {….}

  38. 例題: 寫一函數傳回兩輸入資料給主程式後,在主程式內求和後輸出。 #include <iostream> //cout using namespace std; void get_data(int*, int*); int main( ){ int a,b,sum; get_data(&a,&b); sum = a + b; cout << "sum=" << sum << endl; return 0;} void get_data(int *a, int *b) { cout << "輸入a,b="; cin >> *a >> *b; } 輸入a, b=10 20 sum=30

  39. 主程式 函數get_data 內容 位址 位址 a 10 0066FF00 → 0066FF00 a b 20 0066FF04 → 0066FF04 b 共用同一塊記憶體

  40. 例題: 寫一函數將兩數互換後在主程式輸出(指標接收)。 #include <iostream> //cout using namespace std; void swap_data(int*, int*); int main( ){ int a=10, b=15; cout << "交換前:" << a <<" "<< b << endl; swap_data(&a, &b); cout << "交換後:" << a <<" "<< b << endl; return 0;} void swap_data( int *a, int *b ){ int t; t = *a; *a = *b; *b = t; } 交換前: 10 15 交換後: 15 10

  41. 8.7.2 傳址方式傳參數 #include <iostream> //cout using namespace std; void swap_data(int*, int*); int main( ){ int a=10, b=15; cout << "交換前:" << a <<" "<< b << endl; swap_data(a, b); cout << "交換後:" << a <<" "<< b << endl; return 0;} void swap_data( int &a, int &b ){ int t; t = a; a = b; b = t; }

  42. 8.7.3 指標傳給指標 #include <iostream> //cout using namespace std; void add_one(int*); int main( ){ int a=10, *b; b = &a; add_one(b); cout << "*b=" << *b << endl; cout << " a=" << a << endl; return 0; } void add_one(int *a){ (*a)++; }

  43. 8.7.4 函數名稱以指標傳回 #include <iostream> //cout using namespace std; int *get_sum(int,int); int main( ){ int a=10, b=20, *p; p = get_sum(a,b); cout << "sum=" << *p; delete p; return 0; } int *get_sum(int a, int b) { int *p=new int (a+b); return p; }

  44. 8.7.5 傳回一個以上資料 #include <iostream> //cout using namespace std; int *get_sum(int,int); int main( ){ int *a,*b,*p; a = new int(10); b = new int(20); p = get_sum(a,b); cout <<"*a="<<*a<<endl <<"*b="<<*b<<endl <<"*p="<<*p<<endl; delete p; delete b; delete a; return 0; } int *get_sum(int *a,int *b){ int *p=new int(*a+*b);   (*a)++;   --(*b);    return p; }

  45. 8.9 指標中之指標(雙指標) • 設定一指標指向另一指標, 第二指標指向內容值之用法, 此種情形稱為多重間接指向(multiple indirection)或指標中之指標(pointers to pointers)。在此種情況下, • 第一指標儲存第二指標之位址, 而第二指標系指向儲存數值之位址。 • 雙重指標可用來設定二維陣列, 先要求列(Row)之指標, 再以列之指標來設定行(Column)之指標, 使列為第一指標, 行為第二指標, 形成陣列中陣列, 其存取方式可用一般之陣列存取方法。

  46. 指標 變數 位址 內容 單一指標 指標2 變數 指標1 位址 內容 位址 雙指標

  47. 例題: 指標中之指標。 #include <iostream> //cout using namespace std; int *get_sum(int,int); int main( ){ int x, *p, **m; x = 100; p = &x; //p指向x m = &p; //m指向p cout << "**m="<<**m<<endl; cout << "*p=" << *p << endl; cout << "x=" << x << endl; return 0; }

  48. 8.10 指標指向函數 • 指標也可指向已經存在之函數, 雖然函數不是變數但它仍然在記憶體內有一實體位址, 有實體位址就可將指標指向該位址, 就稱為函數指標(function pointer), 函數之位址是函數被呼叫時之進入點, 一旦函數被指標指到相當於可以呼叫該函數; 函數指標也可當引數(Argument)或參數(Parameter)傳給其他函數。

  49. 例題: 指標指向pow函數 。 #include <iostream> //cout #include <math.h> //pow(x,y) using namespace std; int main( ){ double x, y; double (*p)(double, double); p = pow; //求x之y次方 cout << "x, y="; cin >> x >> y; cout << x <<"之" << y <<"次方="<< (*p)(x,y); return 0; }

More Related