指標的應用

Download Report

Transcript 指標的應用

1
關於指標
2
配置動態記憶體 new
• 變數指標= new 資料型態(起始資料);
• 範例一
int num = 100;
int *numPtr = #
//*numPtr指向num變數
• 範例二
int *newPtr;
newPtr = new int;
*newPtr = 200;
//宣告指標變數
//配置動態指標變數
//起始指標變數值=200
• 範例三
int *newPtr = new int(200);
//*newPtr內值=200
3
new 建立的結果指定給指標變數
char *pc = new char;
int *pi = new int;
float *px = new float;
pc
(沒有名稱)
A008
A308
pi
A309
A30A
A30B
A008
(沒有名稱)
A000
A300
px
A301
A302
A303
A000
A001
A002
A003
(沒有名稱)
A004
A304
A305
A306
A307
A004
A005
A006
A007
4
存取指標變數與目的物
*pc = ‘y’;
*pi = 2518;
*px = 2.7182;
pc
A008
A308
pi
A309
A30A
‘y’ (沒有名稱)
A30B
A008
A000
A300
px
A301
A302
A303
A000
A004
A304
A305
A306
(沒有名稱)
2518
A001
A002
A003
2.7182
A307
A004
A005
A006
(沒有名稱)
A007
5
delete 敘述
delete pc;
delete pi;
delete px;
pc
A008
A308
pi
A309
A30A
‘y’
A30B
A008
A000
A300
px
A301
A302
2518
A303
A000
A004
A304
A305
A306
A001
A002
A003
2.7182
A307
A004
A005
A006
A007
6
觀念釐清 (1/3)
int
int
*pi
*pj
*pi = new int;
*pj = new int;
= 30;
= 50;
pi
30
pj
50
7
觀念釐清 (2/3)
*pj = *pi;
pi
30
pj
30
8
觀念釐清 (3/3)
pj = pi;
pi
30
pj
50
因為失去指標的指向,
這4個 bytes 的資料,
無法存取,也不能刪除
9
陣列的起始位址
• 陣列的起始位址也就是整個陣列的指標
• 陣列 x[]的起始位址,就是陣列第一個元素的
位址 &x[0]
• 在C/C++中,陣列名稱單獨出現時,也代表陣
列的起始位址,因此,x 也是陣列的起始位址
• x 和 &x[0] 的意義是相同的
10
指標 (位址) 的加法
• 如果 x 是陣列的起始位址(也就是整個陣列的
指標),那 x+1 的意義為何?
• 在C++中,陣列的指標加1,不是單純的只是
將 x 中所存的位址值加1,實際上是加上每一
個陣列元素所使用記憶體 byte 數
– 如果是整數或浮點數則加 4
– 如果是字元則加 1
• 若 x 是一陣列的起始位址
x
是
x+1 是
x+2 是
. . .
x+n 是
x[0]的位址 (即&x[0])
x[1]的位址 (即&x[1])
x[2]的位址 (即&x[2])
x[n]的位址 (即&x[n])
11
指標的目的物與陣列元素
• 如果 x 是一陣列的起始位址
*x
就是
*(x+1)就是
*(x+2)就是
. . .
*(x+n)就是
x[0]
x[1]
x[2]
x[n]
• 另例
short array[] = {30, 47, 26, 17, 22, 23}; //宣告字串變數
short *arrayPtr = array;
//指標=array起始位址
cout << "array 的第0個元素=" << *arrayPtr;
//輸出第0元素=30
cout << "array 的第1個元素=" << *(arrayPtr+=1);
//輸出第1元素=47
cout << "array 的第4個元素=" << *(arrayPtr+=3);
//輸出第4元素=22
12
字元陣列與字元指標參數
• 在函式的參數中,
– 字元陣列參數 char s[]
與
– 字元指標參數 char *s
– 都是接受傳入的陣列起始位址, 兩者意義相同
13
以字元陣列定義字串
• 但是在字串的定義與初值設定上,以字元陣列
和字元指標,兩者的意義略有不同
• 字元陣列的定義:
char s[] = “apple”;
位址 &S[0] &S[1] &S[2] &S[3] &S[4] &S[5]
S ‘a’ ‘p’ ‘p’ ‘l’ ‘e’ ‘\0’
S[0]
S[1]
S[2]
S[3]
S[4]
S[5]
14
以字元指標定義字串
• 字元指標不僅可以指向單一字元,也可以指向
字元陣列(字串)
• 字元指標的定義:
char *t = “apple”;
t
t+0
t+1
t+2
t+3
t+4
t+5
‘a’ ‘p’ ‘p’ ‘l’ ‘e’ ‘\0’
*(t+0)
*(t+2)
*(t+1)
*(t+4)
*(t+3)
*(t+5)
位址
15
兩者的相同點
• 以字元陣列的起始位址 s,或是以指標 t 都可
以代表字串
• 下列兩個敘述,都可以印出字串內容
cout << s;
cout << t;
16
兩者的差異
• 字元陣列可以直接儲存字串
char s[10];
cin >> s;
• 字元指標必須另有初值設定或是以 new 敘述配置記憶
體,才能儲存字串
char *t;
t = new char(10);
cin >> t;
• 字串陣列的名稱是一個常數
– s+3; 合法敘述
– s++; 不合法敘述
• 字元指標的名稱是一個變數
– t+3; 合法敘述
– t++; 合法敘述
17
字串指標特殊之處 (同學觀察到哪些獨特之處?)
18
指標與二維陣列
• 二維陣列定義範例:int x[3][2];
• x 是整個陣列的起始位址 (即&x[0][0])
• x[0], x[1], x[2] 分別是第一、二、三列
的起始位址 (即 &x[0][0], &x[1][0],
&x[2][0])
x[0]
x[1]
x[0][0]
x[1][0]
x[0][1]
x[1][1]
x[2]
x[2][0]
x[2][1]
19
長度運算符號
• sizeof 變數名稱
• sizeof array / sizeof array[0]
• 範例
cout << sizeof(bool);
//輸出bool型態的長度1
cout << sizeof(int);
//輸出int型態的長度4
cout << sizeof(float);
//輸出float型態的長度4
cout << sizeof(double);
//輸出double型態的長度8
char *array[] = {"床前明月光,", "疑似地上霜;",
"舉頭望明月,", "低頭思故鄉。" }; //宣告陣列指標
int count = (sizeof array)/(sizeof array[0]);
//計算元素個數
20
字串指標 (1/2)
• char* 字串名稱 = "字串資料";
char string[ ] = "ANSI/ISO C++";
char *pstring = "Visual C++";
cout << string;
cout << pstring;
cout << string[7];
cout << pstring + 7;
char string[] = "ANSI/ISO C++";
//string為字串變數
//pstring為字串指標
//顯示字串變數值
//顯示指標位址到字串結束
//顯示字串第7元素值
//顯示指標第7元素至結束
[0]
[1]
[2]
A
N
S
[3] [4]
I
/
[5]
l
[6]
[7] [8]
S O
[9] [10] [11] [12]
C
+
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10
char* pstring = "Visual C++";
V
i
指標pstring
s
u
a
l
C
+
+ \0
+ \0
21
字串指標 (2/2)
• 範例
char array[4][] = { "床前明月光",
"疑似地上霜",
"舉頭望明月",
"低頭思故鄉" };
char *parray [4] = { "床前明月光",
"疑似地上霜",
"舉頭望明月",
"低頭思故鄉" };
//宣告二維字串陣列
//宣告一維字串指標
22
傳遞常數指標 (1/2)
• 範例一
void power(const int *);
void main(void)
{
const int LEN = 5;
power(&LEN);
}
void power(const int *NUM)
{
cout << (*NUM) * (*NUM);
}
//計算平方函數原型
//宣告整常數符號
//傳遞常數指標
//計算平方函數
23
傳遞常數指標 (2/2)
• 範例二
void power(const int *);
//計算平方函數原型
void main(void)
{
int LEN = 5;
//宣告整整數變數
power(&LEN);
//傳指呼叫, 傳遞變數位址
}
void power(const int *NUM) //接收指標常數
{
cout << *NUM * *NUM;
}
24
傳回函數指標
• 範例
void main(void)
{
cout << *getNumber(); //取得getNumber()指標值
}
float *getNumber()
{
float *num;
cin >> *num;
return num;
}
//輸入浮點數函數
25
指標與結構綜合應用
以 linked List 為例
26
配置記憶體給結構指標
• 利用 new 敘述配置記憶體給一個結構指標
struct person *p;
p = new struct person;
p
name
age
sex
27
鍊結串列 (Linked List)
• 利用指標,將許多個結構串接在一起
• 每一個結構稱為一個 “節點”
• 建立鍊結串列是將節點逐一加入
p
null
28
使用鍊結串列的特點
• 優點 (使用鍊結串列較佳):
– 依照實際資料個數來動態配置記憶體
– 每個節點可以依照需求,加入任意位置
• 缺點 (陣列優於鍊結串列):
– 每個節點都需要有一個指標變數
– 存取速度較慢
29
鍊結串列節點的結構
• 節點的結構至少需要
包括兩個欄位
data
next
– 資料欄位,存放資料
– 指標欄位,用於指向下一個節點
struct node
//結構的名稱為 node
{
int data;
//存放資料
struct node *next; //存放下一節點的指標
};
30
鍊結串列應用 -- 堆疊 (Stack)
• 「堆疊」是一種資料結構,可以使用鍊結串列
來製作
• 後進先出 – 節點從頂端 top 加入,也從頂端刪
除
top
null
p
top
null
31
實作堆疊
• 宣告一個節點的結構 struct node
struct node
{
int data;
struct node *next;
};
data
next
• 定義一個 top 指標 (全域變數),用於指向堆疊
頂端
struct node *top;
top
32
堆疊初始化 -- InitStack()
void InitStack ()
{
top = NULL;
}
top
null
33
加入節點 -- PushStack ()
void PushStack (int value)
{
struct node *p;
p = new struct node;
p->data = value;//與(*p).data = value等意
p->next = top;
top = p;
}
top
null
p
top
p
null
34
移除節點 -- PopStack ()
int PopStack ()
{
struct node *p;
int value;
p = top;
top = top->next;
value = p->data; // p = p->data ??
delete p;
return (value);
}
null
top
p
top
null
p