指標 (pointer) 是一種特別的資料型態,用來儲存某一資料在記憶體內的位址。

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

第一單元 建立java 程式.
計算機程式語言實習課.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。
Visual C++ introduction
簡易C++除錯技巧 長庚大學機械系
資料大樓 --談指標與陣列 綠園.
函數(一) 自訂函數、遞迴函數 綠園.
資料結構設計與C++程式應用 Fundamentals of Data Structures and Their Applications Using C++ 第3章 佇列 資料結構設計與C++程式應用.
【變數與記憶體位址】 變數(Variable)提供一個有名稱的記憶體儲存空間。一個變數包含資料型態、變數本身的值及它的位址值。
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
101北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第一章 程序的基本结构. 第一章 程序的基本结构 教材及授课结构 本章目标 基本内容 扩展阅读 上机指导 应用举例 习题.
Object-Oriented Programming in C++ 第一章 C++的初步知识
前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
類別(class) 類別class與物件object.
SQL Stored Procedure SQL 預存程序.
CLASS 5 指標.
Chapter 7 指標.
指標 林錦財.
Methods 靜宜大學資工系 蔡奇偉副教授 ©2011.
第3讲 C++程序控制结构 3.1 顺序结构 3.2 分支结构 3.3 循环结构 3.4 转向控制 3.5 综合案例分析.
C++程序设计 string(字符串类) vector(容器类).
第3章 指標與字串 (Pointers and Strings)
Java 程式設計 講師:FrankLin.
JAVA 程式設計與資料結構 第四章 陣列、字串與數學物件.
Chap3 Linked List 鏈結串列.
C++语言程序设计 第十一章 流类库与输入/输出.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
程式設計實習課(四) ----C 函數運用----
第一單元 建立java 程式.
陣列(Array).
六、函数 教学目标: 函数的概念、定义、调用和返回 带自定义函数的程序设计 递推算法 递归思想及算法实现 函数的参数传递方式 C语言程序设计.
第一章 直角坐標系 1-3 函數圖形.
開始使用Visual C++.
C++大学基础教程 第11章 多态性 北京科技大学 信息基础科学系 2019/4/8 北京科技大学.
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
第十章 指標.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
第7章 指標 7-1 指標的基礎 7-2 指標變數的使用 7-3 指標運算 7-4 指標與陣列 7-5 指向函數的指標.
物件導向程式設計 CH2.
向量 (vector) 就是典型的一維陣列,而更高維的矩陣,例如矩陣 (matrix) 和張量 (tensor) 則分別是二維和三維的陣列。
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
C qsort.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++程式設計入門 變數與運算子 作者:黃建庭.
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
陣列與結構.
北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
C++语言程序设计 第十章 C++标准模板库 成都信息工程学院计算机系.
實習八 函式指標.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
Chap 6 函數 故用兵之法,十則圍之,五則攻之,倍則分之, 敵則能戰之,少則能逃之,不若則能避之。 故小敵之堅,大敵之擒也。
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
String類別 在C語言中提供兩種支援字串的方式 可以使用傳統以null結尾的字元陣列 使用string類別
變數與資料型態  綠園.
Array(陣列) Anny
資料!你家住哪裏? --談指標 綠園.
C語言程式設計 老師:謝孟諺 助教:楊斯竣.
方法(Method) 函數.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

指標 (pointer) 是一種特別的資料型態,用來儲存某一資料在記憶體內的位址。 8 指標 清明時節雨紛紛 路上行人欲斷魂 借問酒家何處有 牧童遙指杏花村 《清明﹒杜牧(803~852)》 指標 (pointer) 是一種特別的資料型態,用來儲存某一資料在記憶體內的位址。

指標 8.1 記憶體位址與指標 8.2 指標與參照 8.3 陣列與指標的代數計算 8.4 指標參數 8.5 函數指標 8.6 動態記憶體配置

在記憶體內資料的四個相關特性 1. 資料名稱。 2. 資料型態。 3. 資料內容。 4. 該資料在記憶體內的位址。

變數 A 的內容和位址 double A = 2.5 // 定義 double變數A並存入 2.5

範例程式 Variable.cpp // Variable.cpp #include <iostream> using namespace std; // ----- 主程式 ------------------------ int main() { double A = 2.5; cout << "A 的值為:" << A << endl; cout << "A 所佔用的記憶體大小為:" << sizeof(A) << " bytes 或是 " << sizeof(double) << " bytes" << endl; cout << "A 所在位址為:" << “0x” << &A << endl; return 0; }

操作結果 A 的值為:2.5 A 所佔用的記憶體大小為: 8 bytes 或是 8 bytes A 所在位址為: 0x0012FF84

指標 double A = 2.5; 指標是用來儲存其他資料的位址的特殊代號。例如,我們可以使用以下敘述來定義一個名叫 pF的指標: double* pF; // 定義指標 pF pF = &A; // 將資料 A 的位址存入指標 pF 具體表示如下:

指標的四個特性 對於指標 pF而言,它的 名稱: pF 資料型態: double * 資料內容: 0x0065FE00 記憶體位址: 0x0065FDFC

宣告時所指定的目標資料的資料型態無法改變 譬如,pF 已宣告為 double* pF;  // 定義指標 pF 假如 int X = 12; 則敘述 pF = &X; // 錯誤! 指標 pF 必需存放 double 資料的位址 必需配合目標資料的資料型態改成 int* pF;

指標 pF 指向變數 A 指標pF和變數A之間的關係

指標的定義 指標的定義敘述有兩種寫法: 同時定義兩個指標: 在定義pF的同時給予初值: double* pF; // 定義指標 pF (較常用) double *pF; // 定義指標 pF (較少用) 同時定義兩個指標: double *p1, *p2; // 同時定義p1, p2兩個指標 在定義pF的同時給予初值: double* pF = &A; // 定義指標pF,同時存入資料 A 的位址

取值運算子 (value-of operator) double x; // 定義 double 變數 x x = *pF; // 將指標 pF所指處的資料存到變數 x 表示的是「將存在指標pF所指之處的內容儲存到x裹面」。

變數指標 double* pF; // 定義指標pF double X, Y; pF = &X; // pF 指向 X pF = &Y; // pF 改指向 Y 允許好幾個指標指向同一個資料。例如:

陣列名稱也是指標 double V[5]; // 定義陣列 V V是一個常數指標 (constant pointer),資料型態為double * const。

指標與取址運算子 (address-of operator) 「&」 double X = 3.8; // 宣告和初始化 X double* p = &X; // 宣告和初始化 p 其關係相當於 *p 是 X 的內容 (亦即上圖中的 3.8) &X 是 p 的內容 (亦即 X 的位址 0x0065FE00)。

參照 double &x = y; // 宣告x 是 y 的參照 double &x; // 錯誤! 必需給 x 參照的對象 double y, z;// 定義 y 和 z 兩個 double 變數 double &x = z; // 錯誤! 不能更改參照的對象

範例程式 Ref.cpp 使用參照和指標 // Ref.cpp #include <iostream> using namespace std; // ------ 主程式 ----------------------- int main() { double x = 1.0; double &y = x; // 定義x的參照y double *p = &x; // 定義和初始化指標 p cout << "x 原來的值是 " << x << endl; *p = 5.0; cout << "執行 *p = 5.0; 後\n"; cout << "x 的值是 " << x << endl; y = 7.3; cout << "執行 y = 7.3; 後\n"; return 0; }

操作結果 x 原來的值是 1 執行 *p = 5.0; 後 x 的值是 5 執行 y = 7.3; 後 x 的值是 7.3

使用下標來計算陣列元素的位址 const int m = 5; double A[m]; 則第k+1個元素,也就是A[k] 的位址為 &A[0] + k × sizeof(double)

使用下標來計算陣列元素的位址 const int m = 20; const int n = 60; double B[m][n]; 元素B[i][j] 的位址為 &B[0][0] + (i × n + j) × sizeof(double)

使用下標來計算陣列元素的位址 const int m = 20; const int n = 60; const int p = 80; double C[m][n][p]; 元素C[i][j][k]的位址為 &C[0][0][0] + (i × n × p + j × p + k) × sizeof(double)

使用指標來存取 A[0] 的位址 double *pV; 則下面兩式都可以將A[0] 的位址存到pV裏面: pV = &A[0];

使用指標來存取陣列元素: 指標代數 (pointer algebra) *pV 相當於 A[0] *(pV+i)   相當於 A[i] 我們可以寫成通式: A[i] ≡ *(pV+i) 這裹i的範圍為 0 ~ (m-1)。

範例程式 Apointer.cpp (指標代數) 使用*pV++ 逐一獲得向量的各個元素,以求得向量的總合 // Apointer.cpp #include <iostream> using namespace std; // ----- 主程式 --------------------------------- int main() { const int Size = 5; double V[Size] = {48.4, 39.8, 40.5, 42.6, 41.2}; double Sum = 0.0, Average; double *pV = V; int i; for (i=0; i<Size; i++) Sum += *pV++; cout << "陣列 V 各元素的總合是 : " << Sum << endl; cout << "陣列 V 各元素的平均值是: " << Sum / double(Size) << endl; return 0; }

操作結果 陣列 V 各元素的總合是 :212.5 陣列 V 各元素的平均值是:42.5

二維陣列的指標 const int m = 2; const int n = 3; double B[m][n];

二維陣列的元素表示法 通式: B[i][j] ≡ *(B[i] + j) ≡ *(*(B+i) + j) 下標表示法 指標表示法 (1) 指標表示法 (2) B[0][0] *B[0] *(*B) B[0][1] *(B[0]+1) *(*B+1) B[0][2] *(B[0]+2) *(*B+2) B[1][0] *B[1] *(*(B+1)) B[1][1] *(B[1]+1) *(*(B+1)+1) B[1][2] *(B[1]+2) *(*(B+1)+2) 通式: B[i][j] ≡ *(B[i] + j) ≡ *(*(B+i) + j)

範例程式 ShowMatrix.cpp (指標表示法) #include <iomanip> #include <iostream> using namespace std; // ----------------------------------- int main() { const int Row = 2; const int Col = 3; double B[Row][Col]={ 1.8, 4.9, 6.8, 6.2, 2.1, 3.4}; int i, j; cout << "(1)陣列 B 是: " << endl; for (int i=0; i< Row; i++) { for (int j=0; j< Col; j++) cout << setw(5) << B[i][j]; cout << endl; }

cout << endl; cout << "(2)陣列 B 是: " << endl; for (int i=0; i< Row; i++) { for (int j=0; j< Col; j++) cout << setw(5) << *(B[i] + j); } cout << "(3)陣列 B 是: " << endl; cout << setw(5) << *(*(B+i) + j); return 0;

操作結果 (1)陣列 B 是: 1.8 4.9 6.8 6.2 2.1 3.4 (2)陣列 B 是: (3)陣列 B 是:

指標參數 (Pointers as Parameters) 使用參照時,從呼叫端無從辨別參數有沒有使用參照 例如,如果在呼叫這一側的敘述寫成 X = Fnc(a, b); // 呼叫函數Fnc() 被呼叫側的函數其原型可能是下列兩者中的任一個: double Fnc(double, double); double Fnc(double&, double&);

傳址(Passing Addresses) 在呼叫端可以直接將位址當成參數: X = Fnc(&a, &b); // 呼叫函數Fnc(), // 參數用a 和 b 的位址 而在接收端就可以使用指標來接受這個位址: double Fnc(double*, double*); //參數列是指標

範例程式 Swap2F.cpp 使用傳址的方式來交換變數的值 // Swap2F.cpp #include <iostream> using namespace std; // --- 函數 SwapF () 的宣告 ---------------- void SwapF(double* x, double* y); // --- 主程式 ----------------------------- int main() { double a = 2, b = 5; cout << "執行 SwapF() 前, \n"; cout << " a 是: " << a << " b 是: " << b << endl; SwapF(&a, &b); cout << "執行 SwapF() 後, \n"; cout << " a 是: " << a << " b 是: " << b; return 0; }

// --- 函數 SwapF () 的定義 ---------------- void SwapF(double* x, double* y) { double Temp; Temp = *x; *x = *y; *y = Temp; return; }

操作結果 執行 SwapF() 前, a 是:2 b 是:5 執行 SwapF() 後, a 是:5 b 是:2

傳遞指標以存取陣列 將陣列當成函數的參數傳遞 double VecAvg, P[5]; // P是長度為5 的一維陣列 VecAvg = Average(P); // 呼叫函數 Average() 而被呼叫函數的原型可寫成: double Average(double []); double Average(double *);

範例程式 檔案 ArrayPFnc.cpp // ArrayPFnc.cpp #include <iostream> using namespace std; // ---函數 Average()和MaxElem()的宣告 double Average(double *); double MaxElem(double *); const int Size = 5; // ---主程式------------------------ int main() { double P[Size] = {48.4, 39.8, 40.5, 42.6, 41.2}; cout << "陣列 P 的平均值是: " << Average(P) << endl; cout << "陣列 P 的最大值是: " << MaxElem(P) << endl; return 0; }

// ---函數 Average() 的定義---------- double Average(double* V) { double Sum = 0; for (int i = 0; i < Size; i++) Sum += V[i]; return Sum/double(Size); } // ---函數 MaxElem() 的定義---------- double MaxElem(double* V) double MaxE; MaxE = V[0]; for (int i = 1; i < Size; i++ ) if (MaxE < V[i]) MaxE = V[i]; return MaxE;

操作結果 陣列 P 的平均值是:42.5 陣列 P 的最大值是:48.4

函數指標 (Function Pointers) 函數名稱本身就是一種常數指標 (constant pointer)。 double Func(int); // 函數 Func( )的原型 可以使用下列的語法定義函數指標pF並指向函數 Func(): double(*pF)(int); // 定義函數指標pF pF = Func; // 將函數指標pF指向函數 Func( ) 上面兩式可以合併成一個具初始化功能的定義敘述: double(*pF)(int) = Func;

函數指標的使用方式 cont << pF(6) << endl;

函數指標的使用 例如,把數值積分的演算法寫成函數 Integ(): 對於不同的數學函數,譬如 這兩個數學函數的積分值: double Integ(double (*Fnc)(double)); 對於不同的數學函數,譬如 double Fnc1(double); // 數學函數Fnc1() 的原型 double Fnc2(double); // 數學函數Fnc2() 的原型 這兩個數學函數的積分值: double x1, x2; // 宣告實數 x1 和 x2 x1 = Integ(Fnc1); // 計算Fnc1() 的積分值 x2 = Integ(Fnc2); // 計算Fnc2() 的積分值

範例程式 FncPoint.cpp 函數指標的使用 #include <iostream> using namespace std; // --- 函數 F1(), F2()和Twice() 的宣告 -- double F1(int); double F2(int); double Twice(double (*)(int), int); // --- 主程式 --------------------------- int main() { int A = 3; int B = 5; cout << "Twice(F1, A)的值是: " << Twice(F1, A) << endl; cout << "Twice(F2, B)的值是: " << Twice(F2, B) << endl; return 0; }

// ---- 函數F1()的定義 --------------------- double F1(int N) { return double (N*N);} // ---- 函數F2()的定義 --------------------- double F2(int N) { return double (N*N*N);} // --- 函數Twice()的定義 ------------------ double Twice(double (*pF)(int), int N) {return 2.0 * double( pF(N) );}

操作結果 Twice(F1, A)的值是:18 Twice(F2, B)的值是:250

一維陣列的動態記憶體配置及回收 int Size = 100; double *pV = new double[Size]; delete [] pV;

使用動態記憶體配置以避免大量資料的搬移

範例程式 SwapV.cpp 交換指標內容以交換陣列 #include <iostream> #include <iomanip> using namespace std; // ---函數的宣告-------------------- void DisplayV1(double*, int); void DisplayV2(double*, int); void Swap(double** x, double** y); // ---主程式------------------------ int main() { const int SizeA = 5; const int SizeB = 7; double* A = new double [SizeA]; double* B = new double [SizeB]; for (int i=0; i<SizeA; i++) A[i]= 1.0*i; for (int i=0; i<SizeB; i++) B[i]= 3.0*i; cout << "執行 Swap() 前, \n"; cout << "A 是 :\n";

DisplayV1(A, SizeA); cout << "B 是 :\n"; DisplayV2(B, SizeB); Swap(&A,&B); cout << "執行 Swap() 後, \n"; cout << "A 是 :\n"; DisplayV1(A, SizeB); DisplayV2(B, SizeA); delete [] A; delete [] B; return 0; } // ------ 函數DisplayV1()的定義 ------------- void DisplayV1(double* V, int N) { cout << endl; for(int i = 0; i < N; i++) cout << setw(5) << V[i] << " "; cout << endl; return;

// ------- 函數DisplayV2()的定義 ------------- void DisplayV2(double* V, int N) { cout << endl; for(int i = 0; i < N; i++) cout << setw(5) << *(V+i) << " "; cout << endl; return; } // -------- 函數Swap()的定義 ----------------- void Swap(double** x, double** y) { double* Temp; Temp = *x; *x = *y; *y = Temp;

操作結果 執行 Swap() 前, A 是 : 0 1 2 3 4 B 是 : 0 3 6 9 12 15 18 執行 Swap() 後,   0 1 2 3 4 B 是 :   0 3 6 9 12 15 18 執行 Swap() 後, 0 1 2 3 4

以逐列的方式建構二維陣列 int m = 20, n = 50; // 動態配置長度為 m 的一維指標陣列 double **pM = new double *[m]; for (int i=0; i<m; i++) pM[i] = new double[n]; // 回收二維陣列的記憶體 delete pM[i]; delete pM;

二維陣列的動態記憶體配置 (以逐列的方式建構二維陣列)

以連續記憶空間的方式建構二維陣列

以連續記憶空間的方式建構二維陣列 int m = 20, n = 50; // 動態配置長度為 m 的一維指標陣列 double **pM = new double *[m]; pM[0] = new double [m*n]; // pM[0]指向新向量的開頭處 for (int i=1; i<m; i++) pM[i] = pM[i-1]+n; // 每個pM[i]指向陣列的特殊 delete pM[0]; // 釋放指標pM[0]所指的向量 delete pM; // 釋放pM所指的指標向量

範例程式 DynMatrix.cpp 向量和矩陣用在檢查亂數的平均值 #include <iomanip> #include <iostream> #include <new> using namespace std; const int m = 2; const int n = 3; // --- 各函數的宣告 ------------------------ void ShowMatrix(double **); double MatrixAvg (double **); void Sum(double **, double **, double **); void LackMemory() { cerr << "記憶體不足!\n"; abort(); }

// --- 主程式 ----------------------------- int main() { // 動態記憶體配置 pMa set_new_handler(LackMemory); double **pMa = new double *[m]; for (int i=0; i<m; i++) pMa[i] = new double[n]; for (int i=0; i< m; i++) for (int j=0; j< n; j++) pMa[i][j]= (i*i+2.0*j)/2.0; // 動態記憶體配置 pMb double **pMb = new double *[m]; pMb[0] = new double [m*n]; for (int i=1; i<m; i++) pMb[i] = pMb[i-1]+n; pMb[i][j] = double(i+j)/2.0;

// 動態記憶體配置 pMc double **pMc = new double *[m]; pMc[0] = new double [m*n]; for (int i=1; i<m; i++) pMc[i] = pMc[i-1]+n; // 顯示 pMa 和 pMb cout << "陣列 pMa 是: " << endl; ShowMatrix(pMa); cout << "陣列 pMb 是: " << endl; ShowMatrix(pMb); // 求 pMc Sum(pMa, pMb, pMc); cout << "陣列 pMa + pMb 是: " << endl; ShowMatrix(pMc); // 求 pMa 的平均值 cout << "陣列 pMa 的平均值是: " << MatrixAvg(pMa) << endl; // 回收 pMa for (int i=0; i<m; i++) delete [] pMa[i]; delete [] pMa;

// 回收 pMb delete [] pMb[0]; delete [] pMb; // 回收 pMc delete [] pMc[0]; delete [] pMc; return 0; } // --- 函數 ShowMatrix() 的定義 ----------- void ShowMatrix(double **M) { for (int i=0; i< m; i++) for (int j=0; j< n; j++) cout << setw(5) << M[i][j]; cout << endl; return;

// --- 函數 MatrixAvg() 的定義 ------------ double MatrixAvg(double **M) { double Sum = 0; for (int i=0; i< m; i++) for (int j=0; j< n; j++) Sum+= M[i][j]; return Sum / double(m*n); } // --- 函數 Sum() 的定義 ------------------- void Sum(double **X, double **Y, double **Z) Z[i][j]= X[i][j]+Y[i][j]; return;

程式 DynMatrix.cpp 操作結果 陣列pMa是: 0 1 2 0.5 1.5 2.5 陣列pMb是: 0 0.5 1 0 1 2 0.5 1.5 2.5 陣列pMb是: 0 0.5 1 0.5 1 1.5 陣列pMa + pMb是: 0 1.5 3 1 2.5 4 陣列pMa的平均值是:1.25