2013年5月27日 星期一

C++ 指標 pointer

指標用來指向記憶體的位址
int *p:設定一個變數 p ,p 可用來儲存 int型態變數的記憶體位址
&x: 取得 x 的記憶體位址
測試範例(環境 VS2012):
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    int *p;
    int x = 5;

    /* 指標測試 */
    p = &x; // 將 p 指標,指到 x 的記憶體位址
    cout << "x=" << x << endl; // x=5
    cout << "p=" << p << endl; // p=0038FBB0
    cout << "*p=" << *p << endl; // *p=5
    cout << "*p+1=" << *p+1 << endl; // *p+1=6
    cout << "x=" << x << endl; // x=5

    /* 陣列 */
    int arr[3];
    cout << "sizeof(arr)=" << sizeof(arr) << endl; // sizeof(arr)=12  #int大小 4bytes x 3 = 12
    cout << "arr=" << arr << endl;   //  arr=0038FB9C #陣列的變數值就是位址?
    cout << "&arr=" << &arr << endl; // &arr=0038FB9C #陣列有無用 & 取值都沒差?
    ZeroMemory(arr, sizeof(arr)); // 清除記憶體內容,將陣列初始值設為 0

    p = arr; // 將 p 指標,指到 arr 的記憶體位址
    cout << "p=" << p << endl;             //       p=0038FB9C
    cout << "&arr[0]=" << &arr[0] << endl; // &arr[0]=0038FB9C

    cout << "arr[1]=" << arr[1] << endl; // arr[1]=0
    *p = 3;      // 使用指標設定陣列第0個元素的值
    *(p+1) = 10; // 使用指標設定陣列第1個元素的值
    *(p+2) = 20; // 使用指標設定陣列第2個元素的值
    cout << "arr[0]=" << arr[0] << endl; // arr[0]=3
    cout << "arr[1]=" << arr[1] << endl; // arr[1]=10
    cout << "arr[2]=" << arr[2] << endl; // arr[2]=20


    /* 指標的指標 */
    p = &x; // 將 p 指標,指到 x 的記憶體位址
    int y = 100;

    int **pp; // 指標的指標
    pp = &p;  // 指標也能指到另一個指標的記憶體位址
    cout << "pp=" << pp << endl; // pp=0038FBBC
    cout << "&p=" << &p << endl; // &p=0038FBBC
    cout << "*p=" << *p << endl; // *p=5
    cout << "*pp=" << *pp << endl; // *pp=0038FBB0 # *pp = p的值 = x的記憶體位址
    cout << "**pp=" << **pp << endl; // **pp=5
    *pp = &y; //將 p 改指到 y 的記憶體位址
    cout << "*p=" << *p << endl; // *p=100

    /* 一維陣列,變數名稱當指標用 */
    int arr2[5];
    cout << "arr2=" << arr2 << endl; // arr2=0038FB68
    *arr2 = 11; // 把陣列變數名稱當指標用? 設定第0個元素的值
    cout << "arr2[0]=" << arr2[0] << endl; // arr2[0]=11
    *(arr2+1) = 22; // 把陣列變數名稱當指標用? 設定第1個元素的值
    cout << "arr2[1]=" << arr2[1] << endl; // arr2[1]=22

    /* 二維陣列 */
    int arr3[2][3];
    cout << "arr3[1][2]=" << arr3[1][2] << endl; // arr3[1][2]=-858993460
    cout << "sizeof(arr3)=" << sizeof(arr3) << endl; // sizeof(arr3)=24 #int大小 4bytes x 2 x 3 = 24
    ZeroMemory(arr3, sizeof(arr3)); // 清除記憶體內容,將陣列初始值設為 0
    cout << "arr3[1][2]=" << arr3[1][2] << endl; // arr3[1][2]=0
    int* m = &arr3[0][0]; // 設定 m 指標,指到 arr3 第0個元素位址,即指到 arr3 位址
    *(m+1*3+2) = 50; // 使用指標設定 arr3[1][2] 的值為50 (第 1*3+2 = 5 個元素)
    cout << "arr3[1][2]=" << arr3[1][2] << endl; // arr3[1][2]=50
    cout << "&arr3[0][0] - &arr3[0][0]=" << (&arr3[0][0] - &arr3[0][0]) << endl; // &arr3[0][0] - &arr3[0][0]=0 #兩陣列元素位址相減,得到兩元素相距幾個元素
    cout << "&arr3[0][1] - &arr3[0][0]=" << (&arr3[0][1] - &arr3[0][0]) << endl; // &arr3[0][1] - &arr3[0][0]=1 #兩陣列元素位址相減,得到兩元素相距幾個元素
    cout << "&arr3[0][2] - &arr3[0][0]=" << (&arr3[0][2] - &arr3[0][0]) << endl; // &arr3[0][2] - &arr3[0][0]=2 #兩陣列元素位址相減,得到兩元素相距幾個元素
    cout << "&arr3[1][0] - &arr3[0][0]=" << (&arr3[1][0] - &arr3[0][0]) << endl; // &arr3[1][0] - &arr3[0][0]=3 #兩陣列元素位址相減,得到兩元素相距幾個元素
    cout << "&arr3[1][1] - &arr3[0][0]=" << (&arr3[1][1] - &arr3[0][0]) << endl; // &arr3[1][1] - &arr3[0][0]=4 #兩陣列元素位址相減,得到兩元素相距幾個元素
    cout << "&arr3[1][2] - &arr3[0][0]=" << (&arr3[1][2] - &arr3[0][0]) << endl; // &arr3[1][2] - &arr3[0][0]=5 #兩陣列元素位址相減,得到兩元素相距幾個元素

    /* int 型態指標加減 */
    int z = 10;
    int *g = &z;
    cout << "z=" << z << endl;   //  z=10
    cout << "*g=" << *g << endl; // *g=10
    cout << "g=" << g << endl;   //   g=0038FB30
    g++; // 指標改指到下一個元素的記憶體位址
    cout << "g++=" << g << endl; // g++=0038FB34 #比原本 0038FB30 多了一個int元素大小 4bytes
    cout << "*(g++)=" << *g << endl; // *(g++)=-858993460

    getchar();
    return 0;
}

struct 與指標
/* 結構 */
struct cc{
    int aa;
    char bb;
    int *pp; // 結構裡面也能存放指標
};

struct cc mm;
mm.aa = 123;
mm.bb = 'h';
int x = 5;
mm.pp = &x; // 將 mm.pp 指標,指到 x 的記憶體位址

cout << "mm.aa=" << mm.aa << endl; // mm.aa=123
cout << "mm.bb=" << mm.bb << endl; // mm.bb=h
cout << "mm.pp=" << mm.pp << endl; // mm.pp=0038FBB0
cout << "*mm.pp=" << *mm.pp << endl; // *mm.pp=5

struct cc *pm =&mm; // 將 pm 指標,指到 mm 的記憶體位址
// 由 pm 指標存取內部元素的方法
// 方法1
cout << "(*pm).aa=" << (*pm).aa << endl; // (*pm).aa=123
cout << "(*pm).bb=" << (*pm).bb << endl; // (*pm).bb=h
cout << "(*pm).pp=" << (*pm).pp << endl; // (*pm).pp=0038FBB0
// 方法2:使用"->",可由指標存取 struct 內部元素的值
cout << "pm->aa=" << pm->aa << endl; // pm->aa=123
cout << "pm->bb=" << pm->bb << endl; // pm->bb=h
cout << "pm->pp=" << pm->pp << endl; // pm->pp=0038FBB0
cout << "*pm->pp=" << *pm->pp << endl; // *pm->pp=5
cout << "*(pm->pp)=" << *(pm->pp) << endl; // *(pm->pp)=5,結果同*pm->pp,因 -> 優先權比 * 大


char 型態指標
char c = 's';
char *d = &c; // char 型態的指標
cout << "c=" << c << endl; // c=s
cout << "d=" << d << endl; // d=s昍昍昍昍`? # 用cout出現亂碼
printf_s("printf_s %%p d=%p \n", d); // printf_s %p d=002DF947 # 改用 printf_s %p
cout << "(void *)d=" << (void *)d << endl; // (void *)d=002DF947 # 轉成 (void *)
cout << "(int *)d=" << (int *)d << endl; // (int *)d=002DF947 # 轉成 (int *)
cout << "*d=" << *d << endl; // *d=s

string 與指標
char *pstr = "sxtcv"; // 將字串常數"直接指定"給字元指標
printf_s("printf_s %%p pstr=%p \n", pstr); // printf_s %p pstr=00B6EE7C
cout << "pstr=" << pstr << endl; // pstr=sxtcv
cout << "pstr+1=" << pstr+1 << endl; // pstr+1=xtcv
cout << "pstr+2=" << pstr+2 << endl; // pstr+2=tcv
cout << "*pstr=" << *pstr << endl; // *pstr=s
cout << "*(pstr+1)=" << *(pstr+1) << endl; // *(pstr+1)=x
cout << "*(pstr+2)=" << *(pstr+2) << endl; // *(pstr+2)=t
cout << "(void *)pstr=" << (void *)pstr << endl; // (void *)pstr=00B6EE7C
cout << "(int *)pstr=" << (int *)pstr << endl;   //  (int *)pstr=00B6EE7C

void *pv;
pv = pstr;
cout << "pv=" << pv << endl; // pv=00B6EE7C
cout << "*((char *)pv)=" << *((char *)pv) << endl; // *((char *)pv)=s

宣告一個陣列,陣列的元素可用來存放記憶體位址
int x=1, y=2, z=3;
int* a[3]; // a是一個陣列,裡面的元素,用來儲存記憶體位址
a[0] = &x;
a[1] = &y;
a[2] = &z;
cout << "a[0]=" << a[0] << endl; // a[0]=0018FACC
cout << "a[1]=" << a[1] << endl; // a[1]=0018FAC0
cout << "a[2]=" << a[2] << endl; // a[2]=0018FAB4
cout << "*a[0]=" << *a[0] << endl; // *a[0]=1
cout << "*a[1]=" << *a[1] << endl; // *a[1]=2
cout << "*a[2]=" << *a[2] << endl; // *a[2]=3

cout << "*a=" << *a << endl; //         *a=0018FACC
cout << "*(a+1)=" << *(a+1) << endl; // *(a+1)=0018FAC0
cout << "*(a+2)=" << *(a+2) << endl; // *(a+2)=0018FAB4
cout << "**a=" << **a << endl; //         **a=1
cout << "**(a+1)=" << **(a+1) << endl; // **(a+1)=2
cout << "**(a+2)=" << **(a+2) << endl; // **(a+2)=3


用 new 配置記憶體位址給指標
int* p;
p = new int; // 配置一個 int 位址給指標 p
cout << "p=" << p << endl; // p=0031E078
*p=50;
cout << "p=" << p << endl; // p=0031E078
cout << "*p=" << *p << endl; // *p=50
delete p; // 刪除配置的記憶體 new int,但 p 依舊存在
cout << "p=" << p << endl; // 在VS2012中p=00008123,在Netbeans(MinGW)中 p 依舊為 0031E078
cout << "*p=" << *p << endl; // 在VS2012會出錯,在Netbeans(MinGW)中 *p 值無法預期

動態陣列(Dynamic Array):系統在 heap 配置記憶體,大小不固定,須使用者自行釋放記憶體
(靜態陣列Static Array,系統在 stack 配置記憶體,大小固定,系統會自己回收記憶體)
參考:
http://stackoverflow.com/questions/2672085/c-static-array-vs-dynamic-array
http://hatsukiakio.blogspot.tw/2009/04/c-static.html
http://www.functionx.com/cpp/Lesson14.htm
http://www.cplusplus.com/doc/tutorial/dynamic/
int* p;
p = new int[3]; // p是一個指標,p 指到一個 int 動態陣列(有3個元素) 
p[0] = 10;
p[1] = 20;
p[2] = 30;

cout << "p[0]=" << p[0] << endl; // p[0]=10
cout << "p[1]=" << p[1] << endl; // p[1]=20
cout << "p[2]=" << p[2] << endl; // p[2]=30

cout << "p=" << p << endl; // p=004D3090
cout << "p+1=" << p+1 << endl; // p+1=004D3094
cout << "p+2=" << p+2 << endl; // p+2=004D3098

cout << "*p=" << *p << endl; // *p=10
cout << "*(p+1)=" << *(p+1) << endl; // *(p+1)=20
cout << "*(p+2)=" << *(p+2) << endl; // *(p+2)=30
delete []p; //刪除配置的動態陣列,一定要delete,否則會Memory Leak


其他參考資料:
C 語言常見誤解/指標/表示法與轉型
C 語言常見誤解/指標/空指標與NULL
C 語言常見誤解/指標/指標運算
C和C++運算子

沒有留言:

張貼留言