• 文章
  • 三種不同的指標使用方法
釋出者:
2012年10月22日 (最後更新:2012年10月22日)

三種不同的指標使用方法

評分:3.2/5 (157票)
*****
在這篇短文中,我將透過三種不同的方法使用指標來完成相同的任務,向您展示指標的用法。我認為對於 C++ 初學者來說,這是一個非常好的方法,因為您可以從不同的角度看待指標,從而更好地理解它們以及如何使用它們。

程式碼使用三種不同的指標方法來建立一個字串陣列。您可以將其視為稀疏的字元矩陣,或者僅僅是一個字串陣列,例如:
Aa01234
Bb012
Cc0123456
等等。

這三種方法分別是:偏移量、索引和遞增。
程式碼使用 #define 指令,以便能夠
輕鬆編譯每種方法。因此,只需註釋掉這三行
您就可以看到每種方法是如何工作的。

例如,現在設定為使用遞增方法執行。

1
2
3
//#define _use_offset_
//#define _use_array_
#define _use_increments_ 


我使用的資料結構是 char**。
這是一個指向字元的指標的指標,
就像 -> (-> 字元)。
我將其初始化為
 
char** array_of_strings = new char*[26];


所以基本上它是一個字串陣列,就像
-> ->sssssssssssss
->sssssssssssss
->sssssssssssss

array_of_strings 是主指標 ->,我們透過任一方法來移動它
垂直移動(這樣想更好)。目前,
當我們解引用 *array_of_strings 時,我們就得到了另一個指標,即那個
指向實際字串的指標,即上面的第二個 ->。
所以 array_of_strings++ 會移動到下一個字串(垂直),而
(*array_of_strings)++ 會指向字串中的下一個字元(水平)。


第一種方法是使用偏移量。在這種方法中,我們不修改
指標,而是使用某個偏移量來指向資料,
就像 *(pointer+5) = something。因為指標儲存的是地址,所以我們可以這樣做,
pointer+5 指向距離 pointer 偏移 5 個位元組的位元組地址。
在陣列術語中,這相當於陣列方法中的 pointer[5]。在遞增術語中,這相當於
++pointer;++pointer;++pointer;++pointer;++pointer,將指標遞增 5
次。

第二種方法是最好、最簡單的,使用陣列索引:
array[i][j]。

第三種方法是遞增。在這裡,我們需要修改指標,
因為我們使用 ++ 和 -- 運算子來向前或向後移動指標。

所以 p[1]、*(p+1) 和 *++p 是執行相同操作的三種方式:
將指標指向指標後一個位元組的位置。

在遞增方法中,我使用了兩個指標:
array_of_strings 和 new_string。它們都是指標,但它們的
行為不同。array_of_strings 是一個指向指標的指標,
它指向一個指向位元組(字元)的指標,而 new_string
指向實際資料,即字串。當我們執行 array_of_strings++ 時,
我們將 array_of_strings 移動到指向下一個字串。

Aa01234
*array_of_strings++ -> Bb01234567

當我們執行 *++new_string 時,我們指向字串中的下一個字元:
Aa01234
^
|
*++new_pointer

請注意,我使用遞增運算子放在 *++p 前面,而不是 *p++,因為我想
先遞增 p,然後再解引用。如果我執行 *p++,它會處理
Aa012345 或者任何字串兩次。

下面是程式碼,裡面有註釋,我認為不難理解。
只需註釋掉兩個 #define 指令,保留您想嘗試的那個
未註釋,然後設定斷點,看看它是如何工作的。

要執行程式碼,如果您使用的是
Microsoft Visual Studio,只需建立一個新的 Windows 控制檯應用程式。如果您使用的是其他工具,只需將
程式碼複製貼上到您的 Main 函式中即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
	/************************************************************************/
	/*
	    this example shows the equivalence in pointer math between
	    array     p[i]
	    offset    *(p+i)
	    increment p++ p++ ..... i number of times

	    example p[3] = *(p+3) = p++ p++ p++
	*/
//#define _use_offset_
//#define _use_array_
#define _use_increments_

	#ifdef _use_offset_
		cout << "using offset\n";
	#endif
	#ifdef _use_array_
		cout << "using array\n";
	#endif
	#ifdef _use_increments_
		cout << "using increments\n";
	#endif

	int j;
	
	/*
	    declare and initialize the sparse matrix of characters
	    or the array of string, whichever fits.
	*/
	char** array_of_strings = new char*[26];

	for (int i = 0; i < 26 ; i++) 
	{
#ifdef _use_offset_		
		/*
		  using offsets
		  instead of changing the pointer, just use
		  and offset from it all the time. the i is the
	           vertical offset into the table of strings
		  while the j is the horizontal. j = x and y = i
		  in vector terminology.
		*/
		*(array_of_strings+i)      = new char(toascii(65+i));
		*(*(array_of_strings+i)+1) = char(toascii(97+i));
		for (j = 2; j < rand() % 16 + 2; j++)
			*(*(array_of_strings+i)+j) = char(toascii(48+j-2));
		*(*(array_of_strings+i)+j) = '\0';
#endif
#ifdef _use_array_
		/*
		   using arrays
		   the simplest and prefered way because is more
	            readable and cleaner. just use array indexes
		    [y][x] or [i][j]
		*/
		array_of_strings[i]    = new char(toascii(65+i));
		array_of_strings[i][1] = char(toascii(97+i));
		for (j = 2; j < rand() % 16 + 2; j++)
			array_of_strings[i][j] = char(toascii(48+j-2));
		array_of_strings[i][j] = '\0';
#endif
#ifdef _use_increments_
		/*
		   use increments
		   here we change the pointers instead of using offsets
		   like p+i we actuaqlly increment the pointers p++
		   two things we need a two pointers the vertical pointer
		   and the horizontal pointer which actually points to
		   each string. array_of_strings is the verticaal and
	            new_string is the horizontal and the one which
		   points to the string and we use to modify the strings.

		   before printing out the strings we need to reset 
	            the vertical pointer array_of_strings back to the
		   to the beginning so we simply subtract 26 from it
	            because we incremented it 26 times.
		*/ 
		char* new_string  = *array_of_strings++ = new char(toascii(65+i));
		*++new_string = char(toascii(97+i));
		for (j = 2; j < rand() % 16 + 2; j++)
			*++new_string = char(toascii(48+j-2));
		*++new_string = '\0';
#endif
	}

		#ifdef _use_increments_
			array_of_strings = array_of_strings - 26;
		#endif

	for (int i = 0; i < 26 ; i++) 
	{
		#ifdef _use_offset_
			cout << *(array_of_strings+i) << endl;
		#endif
		#ifdef _use_array_
			cout << array_of_strings[i] << endl;
		#endif
		#ifdef _use_increments_
			cout << *array_of_strings++ << endl;
		#endif
	}
	/************************************************************************/