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