指標 林錦財.

Slides:



Advertisements
Similar presentations
第一單元 建立java 程式.
Advertisements

計算機程式語言實習課.
陳維魁 博士 儒林圖書公司 第九章 資料抽象化 陳維魁 博士 儒林圖書公司.
C語言中可變参數的用法——va_list、va_start、va_arg、va_end参數定義
Chapter 5 迴圈.
程序设计基础.
第十一章 結構.
Visual C++ introduction
2 C++ 程式概論 2.1 C++ 程式結構 程式註解 // 插入標題檔 #include 2-3
列舉(enum).
【變數與記憶體位址】 變數(Variable)提供一個有名稱的記憶體儲存空間。一個變數包含資料型態、變數本身的值及它的位址值。
Introduction to the C Programming Language
C 程式設計— 指標.
String C語言-字串.
C 程式設計— 指標 台大資訊工程學系 資訊系統訓練班.
101北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
Introduction to the C Programming Language
C語言簡介 日期 : 2018/12/2.
Function.
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
類別(class) 類別class與物件object.
SQL Stored Procedure SQL 預存程序.
CLASS 5 指標.
Chapter 7 指標.
Methods 靜宜大學資工系 蔡奇偉副教授 ©2011.
Pointers Data Structure 補充單元 2019/1/1.
Java 程式設計 講師:FrankLin.
Chap3 Linked List 鏈結串列.
Introduction to the C Programming Language
Introduction to the C Programming Language
|12 結構與列舉型態.
第一單元 建立java 程式.
第一章 直角坐標系 1-3 函數圖形.
|07 函數.
Speaker: Liu Yu-Jiun Date: 2009/4/29
輸入&輸出 函數 P20~P21.
第十章 指標.
Introduction to the C Programming Language
大綱:加減法的化簡 乘除法的化簡 去括號法則 蘇奕君 台灣數位學習科技股份有限公司
第7章 指標 7-1 指標的基礎 7-2 指標變數的使用 7-3 指標運算 7-4 指標與陣列 7-5 指向函數的指標.
习题课
指標
樣版.
习题课 编译原理与技术 计算机科学与技术学院 李诚.
C qsort.
流程控制:Switch-Case 94學年度第一學期‧資訊教育 東海大學物理系.
Pthread.
函數應用(二)與自定函數.
PROGRAM 7 SQUARE E. Angel.
陣列與結構.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
挑戰C++程式語言 ──第9章 函數.
指標 (pointer) 是一種特別的資料型態,用來儲存某一資料在記憶體內的位址。
北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
1-1 二元一次式運算.
實習八 函式指標.
Chap 6 函數 故用兵之法,十則圍之,五則攻之,倍則分之, 敵則能戰之,少則能逃之,不若則能避之。 故小敵之堅,大敵之擒也。
第一章 直角坐標系 1-3 函數及其圖形.
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
作業系統實習課(二) -Scheduler-Related System Calls-
Introduction to the C Programming Language
Programming & Language Telling the computer what to do
Chapter 6 函數.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
Array(陣列) Anny
C語言程式設計 老師:謝孟諺 助教:楊斯竣.
方法(Method) 函數.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
InputStreamReader Console Scanner
Presentation transcript:

指標 林錦財

大綱 何謂指標 參考(reference) 函數呼叫:傳值、傳址、傳參考 指標的指標 指標陣列 函數指標 複雜的指標宣告

何謂指標 很多程式員說:學C/C++而不會使用指標,相當於沒學過C/C++。 一般變數所存放的是「資料」 然而,指標變數則存放「記憶體位址」 依據指標變數所指的記憶體位址才能找到(dereference)「資料」

簡單的例子 如圖 p1指標變數所記載的值是變數a的記憶體 (memory) 位址,而p2則記載著b的記憶體位址, 稱p1是一個指向a的指標,p2是一個指向b的指標。 b 10 a 5 int *p1 = &a; int *p2 = &b; p1 p2

瞭解語法 int *p1 = &a; int *p2 = &b; 其中的&,稱為address of (取址)。即,p1 = address of a,p2 = address of b。 另一個符號*,代表的意義是指標。

瞭解語法 int *p1; 此宣告的意義是 p1是指向整數的指標

瞭解語法 int *p1 = &a; 這整行的意義:p1是一個指向整數的指標,指向整數變數a。

C++ 語法─參考(reference) 先暫停討論指標,而看看C++之「參考」 。 參考:可想像為一個變數或物件的別名 。 當函式的參數 (parameter) 在函式中會被修改,而且要將修改結果反映給呼叫函式,則會用參考來當函式的參數。

C++ 語法─參考(reference) 當其他程式呼叫此swap函式時,只要直接寫swap(x, y) 就能交換x與y的值。 void swap(int &a, int &b){ int tmp = a; a = b; b = tmp; } 當其他程式呼叫此swap函式時,只要直接寫swap(x, y) 就能交換x與y的值。 因為a就是x,b就是y。 a和b不是x和y的複製品,任何作用在a與b上的動作都會反映在x與y上面,反之亦然。

& & 既能用於「取址」又能用於「參考」,以及位元運算,容易造成初學者的混淆。 若&前面有資料型態 (例如 int &),則為參考,若&前面有等號 (例如 int* p = &a),則為取址。若&前後都是整數,則是位元運算 (例如 c = a & b)

* * 既能用於宣告指標變數(例如 int *p),也可用於找到(dereference)指標所指的資料 (例如 *p = q 或 r = *p),以及用於乘法運算 (例如 c = x * y) 將 int *p視為 int* p。 把int和*連在一起看,當作是一種型態叫做 “指向整數之指標”,要比int *p自然得多。 同樣的方式也可以套在char* p或void* p等。 但要注意的是下面的狀況: int* p, q;

int* p, q; 不要把這行誤解成p, q都是指向int之指標,事實上,q只是一個int變數。 上面這行相當於 int *p, q; 或 int *p; int q; 如果p, q都要宣告成指向int之指標,應寫成: int *p, *q 或者干脆分兩行寫: int* p; int* q;

call by value? call by address (或call by pointer)? call by reference? Call by value: swap(int a, int b) Call by address: swap(int* a, int* b) Call by reference: swap (int &a, int &b)

Call by value: swap(int a, int b) void swap(int a, int b){ int tmp = a; a = b; b = tmp; } 呼叫swap(x, y)後,x和y的值並不會有變化。

Call by address: swap(int* a, int* b) 利用指標來做參數傳遞,這種方法骨子裡仍是call by value,只不過call by value的value,其資料型態為指標罷了。 呼叫swap時,要寫成swap(&x, &y)。 void swap(int* a, int* b){ int tmp = *a; *a = *b; *b = tmp; }

Call by address: swap(int* a, int* b) 呼叫swap時,x的位址與y的位址會被複製一份到swap的指標變數a與b中。 x *a a &x 5 y *b b &y 10

Call by address: swap(int* a, int* b) swap結束後,&x (address of x) 和&y (address of y) 依然沒變,只是指標變數x所指的值與指標變數y所指的值交換了。 因為&x 和&y 其實是利用call by value在傳,因此,call by address其實骨子裡就是call by value。 x *a a &x 10 y *b b &y 5

Call by reference: swap (int &a, int &b) 這是C++才加進來的東西,C本身並沒有call by reference。 只要呼叫swap(x, y),就可以讓x和y的值交換。在這個例子中,a 就是 x, b 就是 y。 swap(int &a, int &b){ int tmp = a; a = b; b = tmp; }

測試一下您的理解 int g_int = 0; void changePtr(int* pInt){ pInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(localPInt); printf("%d\n", *localPInt); } 將印出?

int g_int = 0; void changePtr(int int g_int = 0; void changePtr(int* pInt){ pInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(localPInt); printf("%d\n", *localPInt); } 印出來的數字仍然會是localInt的1 因為changPtr中的pInt是由localPInt「複製」過去的,對pInt做改變並不會反映到localPInt身上。

指標的指標(pointer to pointer ) int g_int = 0; void changePtr(int** pInt){ *pInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(&localPInt); printf("%d\n", *localPInt); } 將印出?

pointer to pointer int g_int = 0; void changePtr(int** pInt){ *pInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(&localPInt); printf("%d\n", *localPInt); } g_int localInt localPInt 1

pointer to pointer int g_int = 0; void changePtr(int** pInt){ *pInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(&localPInt); printf("%d\n", *localPInt); } pInt g_int localInt localPInt 1

pointer to pointer int g_int = 0; void changePtr(int** pInt){ *pInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(&localPInt); printf("%d\n", *localPInt); } pInt g_int localInt localPInt *pInt 1

reference to pointer 同樣的功能也可以用「指標的參考」來做 int g_int = 0; void changePtr(int* &refPInt){ refPInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(localPInt); printf("%d\n", *localPInt); }

reference to pointer int g_int = 0; void changePtr(int* &refPInt){ refPInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(localPInt); printf("%d\n", *localPInt); } g_int localInt localPInt 1

reference to pointer int g_int = 0; void changePtr(int* &refPInt){ refPInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(localPInt); printf("%d\n", *localPInt); } g_int localInt refPInt即localPInt 1

reference to pointer int g_int = 0; void changePtr(int* &refPInt){ refPInt = &g_int; } void main(){ int localInt = 1; int* localPInt = &localInt; changePtr(localPInt); printf("%d\n", *localPInt); } g_int localInt refPInt即localPInt 1

指標陣列 一種常見的混淆是pointer array (指標陣列) 與pointer to pointers,因為兩種都可以寫成**的型式。 如,int**可能是pointer to pointer to integer,也可能是integer pointer array。 pointer array的常見例子:main(int argc, char** argv)其實應該是main(int argc, char* argv[])。 argv …

函式指標(function pointer) 指向函式的位址的指標。 假設有一個函式func1,如下: void func1(int int1, char char1); 想宣告一個能指向func1的指標,則寫成: void (*funcPtr1)(int, char); 理解成:funcPtr1是一個函數指標,它指向的函數接受int與char兩個參數並回傳void。

函式指標(function pointer) 指標指向函式的寫法: funcPtr1 = &func1; 取址符號省略亦可,效果相同: funcPtr1 = func1; 若欲在宣告時就直接給予初值,則寫成: void (*funcPtr1)(int, char) = &func1; 其中 & 亦可省略

函數指標的常見例子 stdlib.h中提供的qsort函式。此函式之原型如下: void qsort(void* base, size_t n, size_t size, int (*cmp)(const void*, const void*)); 其中的int (*cmp)(const void*, const void*) 就使用到函式指標。

函數指標的常見例子(續) 用於multithread時。函數指標負責把函數傳進建立執行緒的API中。 在event driven的環境中,使用的callback function。 所謂callback function即:發生某事件時,自動執行某些動作。

如何看懂複雜的指標宣告 常數與指標的讀法 const double *ptr; double *const ptr; double const* ptr; const double *const ptr; 以上幾個宣告,到底const修飾的對象是指標,還是指標所指向的變數呢? 關鍵在於:*與const的前後關係!

如何看懂複雜的指標宣告 當*在const之前,則是常數指標,反之則為常數變數。因此, const double *ptr; // ptr指向常數變數 double *const ptr; // ptr是常數指標 double const* ptr; // ptr指向常數變數 const double *const ptr; // 指向常數變數的常數指標 用中文講更是不清楚了@#$%!

如何看懂複雜的指標宣告 在The C++ Programming Language中有提到一個簡單的要訣:由右向左讀!!讓我們用這個要訣再來試一次。(用英文解說會比較清楚哦!) const double *ptr; // ptr is a pointer points to double, which is a constant double *const ptr; // ptr is a constant pointer points to double double const* ptr; // ptr is a pointer points to constant double const double *const ptr; // ptr is a constant pointer points to double, which is a constant

再來「英翻中」 const double *ptr; // ptr is a pointer points to double, which is a constant 中譯:ptr是一個指標,指向double的記憶體空間,此double值是常數(不可更改)

再來「英翻中」 double *const ptr; // ptr is a constant pointer points to double 中譯:ptr是一個常數指標(ptr值不可更改),指向儲存double的記憶體空間

再來「英翻中」 double const* ptr; // ptr is a pointer points to constant double 中譯:ptr是一個指標,指向固定double值的記憶體空間

再來「英翻中」 const double *const ptr; // ptr is a constant pointer points to double, which is a constant 中譯:ptr是一個常數指標,指向double的記憶體空間,此double值是常數(不可更改)

複雜宣告的讀法 void ** (*d) (int &, char **(*)(char *, char **)); 印度工程師Vikram的"The right-left rule": 從最內層的括號讀起,變數名稱,然後往右,遇到括號就往左。當括號內的東西都解讀完畢了,就跳出括號繼續未完成的部份,重覆上面的步驟直到解讀完畢。

複雜宣告的讀法 解讀 void ** (*d) (int &a, char*) : 1. 最內層括號的讀起,變數名稱: d 2. 往右直到碰到) : (空白) 3. 往左直到碰到( :是一個函數指標 4. 跳出括號,往右,碰到(int &, char*): 此函式接受兩個參數:第一個參數是reference to integer,第二個參數是character pointer。 5. 往左遇上void **: 此函式回傳的型態為pointer to pointer to void。

複雜宣告的讀法 解讀void ** (*d) (int &, char **(*)(char *, char **)) :