1 /*----------------------------------------
2 指針練習(精華)
3
4 1)首先,要理解變量或數組的首地址,指的就是存放數據的RAM或ROM中地址號最小的那個字節地址。
5 2)指針前面的類型說明符,具有2重意義(既決定了對一級指針進行解引用時,將會操作的字節數,以及對一級指針進行算術運算時,會跳轉的地址個數)。
6 ①決定了指針加一時,指針會跳轉多少個地址,
7 例如:
8 如果指針是
9 char類型的,(指針+n) 指針會跳轉n*1個地址。
10 int 類型的,(指針+n) 指針會跳轉n*2個地址。
11 long類型的,(指針+n) 指針會跳轉n*4個地址。
12
13 ②並且還決定了通過指針操作地址值時,實際上會返回多少個字節的值,且地址號大的字節先返回。
14 例如:
15 假設要操作指針的一次地址返回值,那麼如果指針是
16 char類型的,返回1個字節。
17 int 類型的,返回2個字節。
18 long類型的, 返回4個字節。
19
20 數組前面的類型說明符,同樣具有2重意義,且跟上面的很相似。
21 例如:
22 #include"stdio.h"
23 int c[]={0x1234,0x5678};
24 void main()
25 {
26 printf("%p %d\n",c,*c); //數組是int類型意味著返回2個字節
27 printf("%p %d\n",(c+1),*(c+1)); //實際上(c+1)與c是夾著一個地址,因為數組類型符號是int,如果數組類型是long,則夾著3地址
28 }
29
30 也就是要注意類型所占的字節數,還有就是什麼時候該看數組類型符號或者指針類型符號。
31 3)&叫取首地址符號,*叫解引用符號。
32 4)數組名是指一個首地址,所以,point=a(point是一個指針,a是一個數組名), a的前面不需要加&符號。
33 變量名指的是一個值,a[1]指的也是一個值,這些值包含著一個或多個字節,在想要讓指針指向這些值的字節的地址時,
34 需要在變量名以及a的前面加上&符號,即意思是要讓指針賦值符號(=)右邊的東西是地址。
35 5)數組或變量的數據是一個一個字節的存放的,而且字節的地址是呈現連續的,賦值的時候,從左到右看,
36 越往右,字節的地址號越大。因此,對於多字節數據類型的數組而言,看起來有種“首尾相連”的效果,
37 因為一個元素的最低位字節其地址的加一地址對應的字節,就是下一個元素的最高位字節。
38
39 簡單點來說就是低地址存放高字節,這種現象稱為大端排列(常用單片機)。注意:有些時候則是低地址存放低字節,這種現象稱為小端排列(ARM)。
40
41 6)指針可分為:函數指針,數組指針(多維指針),變量指針,結構體指針。 又可分為:多級指針,多維指針。 地址可分為:多級地址,多維地址。
42 7)只有字符數組的最後一個元素會緊接一個隱藏元素,該元素值為0,映射的字符為“\0”。
43 8)數據指針型函數,也叫指針函數(即返回值是一個地址)。
44 9)char (*p)[2]; //聲明一個二維指針(也叫二維數組指針)
45 分析方括號([])對多維指針的操作時,要遵循一個原則:先明確指針的維數,再分析有多少組方括號,方括號裡面的數字是多少,由此得到地址是如何跳轉的;
46 然後根據方括號的組數得知地址最終會發生多少次的解引用,如果解引用的次數少於地址的維數,
47 那麼最終得到的還是一個地址,也如果解引用的次數等於地址的維數,那麼得到是一個數據值。
48 每次對多維地址進行一次解引用後,地址的維數將會變小。
49 一維數組名就是一個一級一維地址,二維數組名就是一個一級二維地址,多維數組名就是一個一級多維地址。每一個數組名都是一個地址。這些地址是固定的。
50 一級多維指針的特點是:解引用的寫法很特殊;運算時地址的跳轉很特殊。
51 探究代碼如下:
52 int Array[2][3][2]={{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}};
53
54 printf("%d\n", Array);
55 printf("%d\n", Array[1]); //與上一行代碼相比,發生了 3*2*4=24個地址 的跳轉
56 printf("%d\n", Array[1][1]); //與上一行代碼相比,發生了 2*4=8個地址 的跳轉
57
58 printf("%d\n",*(Array[1][1]));//對1維地址進行1次解引用,得到一個數據值,為9
59
60 printf("%d\n",*(*(Array[1]))); //對2維地址進行2次解引用,得到一個數據值,為7
61 printf("%d\n",*(Array[1])); //對2維地址進行1次解引用,得到的是一個1維地址,且與Array[1]值一樣,但Array[1]是一個2維地址
62 10) #include<stdio.h>
63 #include<stdlib.h>
64 int main()
65 {
66
67 //下面是存在著非法讀寫的演示,雖然非法讀寫是可以實現,但是這只能存在於同一個進程裡面,而且這種情況沒有什麼有利的實際意義
68
69 int *p; //int類型指針,操作4個字節
70 p=(int *)malloc(2); //向堆區域存儲空間申請了2個字節,但不進行初始化,calloc方式的申請會進行初始化
71 if(p)
72 printf("Memory Allocated at: %p\n",p);
73 else
74 printf("Not Enough Memory!\n");
75 printf("%x\n",*p); //由於只申請了2個字節,所以非法讀取了2個字節
76 *p=0x12345678; //由於只申請了2個字節,所以非法寫入了2個字節
77 printf("%x\n",*p); //由於只申請了2個字節,所以非法讀取了2個字節
78 free(p); //釋放堆中申請過的2個字節,並且有可能把內存中的值也清0,這要取決於運行的內核
79 //下面是非法讀寫了4個字節
80 printf("%x\n",*p);
81 *p=0x87654321;
82 printf("%x\n",*p);
83 return 0;
84 }
85 11)經探究發現,不同類型的指針指向的地址跟指針類型不一致時,有可能會報錯,也有可能只是警告而已
86 12)unsigned char (*q)(); //聲明一個函數指針
87 指針形式調用函數時不給定傳遞參數值的話,默認是傳遞-1 , 指針調用函數的格式為:"(*指針名)(形參列表)" 或 "指針名(形參列表)"
88 13)一級和多級指針的使用:
89 int val=0x1122;
90 char *p3=&val;
91 char **p2=&p3;
92
93 printf("%x\n", p3);
94 printf("%x\n", p3+1); //跳轉1個地址(因為p3是個一級指針而且類型修飾符為char)
95
96 printf("%x\n", *(p3)); //操作1個字節(因為p3是個一級指針而且類型修飾符為char)
97 printf("%x\n", *(p3+1));//操作1個字節(因為p3是個一級指針而且類型修飾符為char)
98
99 printf("%x\n", (p2));
100 printf("%x\n", (p2+1)); //跳轉4個地址(因為內存中字節所使用的地址長度為32位且指針p2是一個二級指針)
101
102 printf("%x\n", *(p2)); //操作4個字節(因為內存中字節所使用的地址長度為32位且指針p2是一個二級指針)
103 14)對多級多維指針的探究:
104 //假設已經掌握對多級一維指針,和一級多維指針的使用
105
106 unsigned char (**p)[3];
107 int Array3[10]={0x804a0e0,0x55667788,2,3,4,5,6,7,8,9}; //之所以第一個元素為0x804a0e0,是因為該值取的不當,下面對(*(*p))進行解引用的時候,有可能在程序執行時導致內核塌陷,看起來好像是程序語法錯誤,也就是說要保證解引用的指針是在正確范圍內的
108 p=Array3;
109
110 printf("%x\n", p); //p是一個二級二維指針,指向一個二級二維地址
111 printf("%x\n", p+1); //發生4個地址的跳轉(因為地址長度為4個字節),因為(p+1)是一個二級二維地址,也就是此行語句輸出值比上一行語句大4
112
113 printf("%x\n", *p); //解引用得到4個字節的值,因為p是一個二級二維指針。*p 為一級二維指針
114 printf("%x\n", (*p+1)); //跳轉3個字節,因為 *p 屬於一級二維指針,也就是此行語句輸出值比上一行語句大3。因為一級指針地址的跳轉,是取決於維數,*p是一個一級二維指針,那麼跳轉數為:sizeof(unsigned char)*[3]=3
115
116 printf("%x\n", *(*p)); //對一級二維指針(*p)進行解引用,得到一級一維指針*(*p),該行語句打印值等效於一級二維指針*p
117
118 printf("%d\n", *(*(*p))); //對一級一維指針*(*p)進行解引用,得到1個字節的值,值為0xe0也就是224,因為指針 p 的類型修飾符為char,而sizeof(unsigned char)=1
119
120 printf("%d\n", *(*(*p))+1); //該行打印值比上一行大1,為225
121
122 //總結:對多級多維指針進行解引用的時,每次解引用都會遵循先降級再降維,當級數沒降到1,那麼維數不起作用,也就是把指針當做多級一維指針來處理。
123 // 當已經是一級指針了後,維數起作用,當做一級多維指針或一級一維指針處理
124
125
126
127 ------------------------------------------*/
這是我對指針學習的歸納記載,如有疑問歡迎聯系作者本人一起探討~
尊重作者的勞動,轉載請記得注明來源:http://www.cnblogs.com/weifeng727/p/5584151.html