https://blog.csdn.net/constantin_/article/details/79575638 html
就上面的博客做一下筆記:數組
關於【int (*p)[3]】與【int *p[3]】兩個的區別安全
https://blog.csdn.net/sayesan/article/details/39001609 數據結構
https://blog.csdn.net/ywb201314/article/details/52062059 app
技巧1:注意*與[與變量結合的優先順序,p有多是指針,也有多是數組,也有多是函數名。ide
技巧2:關於「指針類型」的斷定:函數
1)首先,要確保變量就是一個指針類型。
spa
2)去掉變量名,剩下的就是指針類型。
.net
技巧3:關於「指針所指向的類型」的斷定:指針
1)首先,要確保變量就是一個指針類型。
2)去掉變量名指針的聲明符*,剩下的就是指針指向的類型。
void若是來修飾指針運算符*,就表明是任意類型的指針。
int (*p)[3];
關於複雜指針類型,上面這個類型。注意(*p)這個括號,僅僅是用來約束運算符優先級的。不要和下面的指針類型混淆。
Int (*p)(int);
上面這個類型。注意(*p)這個括號,表明p指向的是一個函數。
因此在判斷(*p)指針的指向的內容類型時,能夠將(*p)同時去掉再行判斷 。
指針打印:採用%p
1)對於「例二」
若是ptr指針類型聲明爲char *,ptr++以後的打印結果爲b。
#include "stdafx.h" #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { char a[20]={'a','b','c','d','e','f'}; char *ptr= a; //強制類型轉換並不會改變a 的類型 ptr++; printf("%c",*ptr); system("pause"); return 0; }
若是ptr指針類型聲明爲int *,ptr++以後的打印結果爲e。
#include "stdafx.h" #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { char a[20]={'a','b','c','d','e','f'}; int *ptr=(int *)a; //強制類型轉換並不會改變a 的類型 ptr++; printf("%c",*ptr); system("pause"); return 0; }
因此當指針聲明成不一樣的類型,++的效果是不同的。++和指針的類型有關。
若是指針類型和指針所指向的類型不一致時,要注意++的使用。
2)對於「例三」
#include "stdafx.h" #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { int array[20]={0}; int *ptr=array; for(int i=0;i<20;i++) { (*ptr)++; ptr++; } for(int i=0;i<20;i++) { printf("[%d] = %d\n",i,array[i]); } system("pause"); return 0; }
3)對於「例四」
#include "stdafx.h" #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { char a[20]="You_are_a_girl"; int *ptr=(int *)a; ptr+=1; printf("%d\n",*ptr); system("pause"); return 0; }
對行%d,*ptr輸出的是1600483937
對行%c,*ptr輸出的是a
這是爲何,請高手解答?
4)對於「例五」
#include "stdafx.h" #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { char a[20]="You_are_a_girl"; char *p=a; char **ptr=&p; //printf("p=%d\n",p); //printf("ptr=%d\n",ptr); //printf("*ptr=%d\n",*ptr); printf("**ptr=%c\n",**ptr); ptr++; //printf("ptr=%d\n",ptr); //printf("*ptr=%d\n",*ptr); printf("**ptr=%c\n",**ptr); system("pause"); return 0; }
這個例子有點繞,須要注意,上面我來配個圖
**ptr:分解開就是*(*ptr)
*ptr取指ptr所指向的內容,ptr指向的地址是指針變量p所佔用的內存地址,ptr所指向的內容就是指針p變量。
*(*ptr) 就是*p,也就是取p所指向的a的首地址的值,因此第一次打印ptr的值是Y。
ptr++,就是得明白指針的++與普通的運算符是不同的(指針變量的++,表明它所指向的個體的內存地址的遞增,且增加單位爲指針類型所佔字節個數)。
ptr++,也就是 ptr所指向的地址+4(注意是p的地址+4,並不是a的地址+4).
ptr++ , 就是ptr所指向的內存地址是指針p的內存地址加4個字節的地址,至於這個地址裏存儲的對象是啥,誰也不知道。
*ptr,ptr新指向內存地址就是下面的這個藍牙框。 *(*ptr),就是把*ptr看成是一個指針,而*ptr並不是必定是一個指針。這樣程序可能就會報錯。
5)對於「例9」
假如我像下面這麼寫,會報一個錯誤:
#include "stdafx.h" #include <stdlib.h> int _tmain(int argc, _TCHAR* argv[]) { int array[10]={0,1,2,3,4,5,6,7,8,9},value; array++; value=*array; printf("%d\n",value); system("pause"); return 0; }
error C2105: 「++」須要左值
上面的錯誤百度了一個解釋:https://blog.csdn.net/hou09tian/article/details/75332576
就是數組名是一個指針,可是不是一個變量。不可能對它進行++運算。++不可以使用在常量上
改一下代碼:
int _tmain(int argc, _TCHAR* argv[]) { int array[10]={0,1,2,3,4,5,6,7,8,9},value; int *ptr = array; ptr++; value=*ptr; printf("%d\n",value); system("pause"); return 0; }
結果輸出1
其實,說到數組,我還一個 須要補充的:數組元素的內存地址是連續的
經過下面的代碼打印:
for(int i = 0; i < 10; i++){ printf("array[%d] address = %d\n",i,&array[i]); }
6)對於「例十」
strcpy函數,會將char *指針所指向的字符串複製,而不單單是一個字符。
printf("%s",array); %s是從起始位置輸出字符直到遇到\0爲止,因此%s輸出char[]數組,會輸出整個串。
關於strcpy函數的詳解:
https://blog.csdn.net/okawari_richi/article/details/57411796
7)對於「例十一」 (數組和指針)
sizeof 函數:http://www.javashuo.com/article/p-nuanstqp-kb.html
http://blog.sina.com.cn/s/blog_4badbe8e0100qb0s.html (詳細說明數組名與指針的關係)
8)對於「例十二」 (結構體和指針)
https://www.cnblogs.com/winifred-tang94/p/5843440.html
成員調用的方法(->左邊必須是指針,"."左邊必須是實體)
特別注意結構體與數組,和指針的關係是不同的。
對於*(ptr +1)打印的不是結構體的第2個元素,很奇怪。難道數組名與結構體名不同?
printf("%s\n","----------結構體名取結構體正常數據------------------"); printf("%d\n",*ss); printf("%d\n",*(ss+1));
增長上述代碼,工程一編譯就報錯:
錯誤1error C2100: 非法的間接尋址
錯誤2error C2676: 二進制「+」: 「wmain::MyStruct」不定義該運算符或到預約義運算符可接收的類型的轉換
因此我得出一個結論,數組名與結構體名有徹底不同的特性:結構體名不能當成指針使用,結構體名不是指針常量。
注意這行代碼:
struct MyStruct *ptr=&ss;
假如ss是數組,上面的代碼就不用加&號了。
struct MyStruct *ptr=ss;
可是結構體會報錯:
錯誤1error C2440: 「初始化」: 沒法從「wmain::MyStruct」轉換爲「wmain::MyStruct *」
這就更加證實了結構體名不是指針常量這個結論 。
繼續修改代碼:
注意上面的打印結果,經過pstr取的結構體元素地址是正確的,可是ptr取的結構體元素地址是錯誤的。
注意代碼中ptr與pstr的定義:
struct MyStruct *ptr=&ss; int *pstr=(int*)&ss;
ptr指向的類型是 MyStruct,指向的對象爲結構體實體ss。
pstr指向的類型是int,指向的對象爲結構體的實體ss的首元素。
ptr+1,就是&ss這個地址+sizeof(MyStruct),就是&ss+16。
pstr+1,就是&ss這個地址+sizeof(int),就是&ss+4。
--------------------------------------------------------------------------------------------
| 結構體與數組的共性:
| 1)結構體實體的地址和結構體第一個元素的地址同樣, 各元素的地址也是連續的。(特殊狀況也有不連續的)
| 數組實體的地址和數組第一個元素的地址同樣, 各元素的地址也是連續的。
| 2)數組和結構體自身的實體(變量)並不佔據獨立的內存(和首元素地址同樣),只有元素才佔用真正的內存地址,
| 它只是標明自身的元素是一組特殊的數據結構, 經過實體封裝,便於元素的訪問。
|
| 結構體與數組的區別:
| 1)數組名是指針常量,可是結構體名和指針沒有任何的關係。
--------------------------------------------------------------------------------------------
9)對於「例十三」
注意做者對結構體的特殊之處的解釋
10)指針類型的轉換
能夠把指針的值看成一個整數取出來,也能夠把一個整數值看成地址賦給一個指針
11) 指針安全問題
這個很重要
使用指針必需要清楚指針指向了哪裏