指標,一直都是c語言中的難點,剛開始大一剛學c的時候就感覺懵逼,一直都是簡簡單單去理解,簡簡單單的使用,從沒有說去深刻研究一下,尤其是現在決定搞**開發了,以後估計更少用到,所以趁現在有點時間趕緊好好看一看。好好的搞懂它。
一、什麼是指標?
這裡就有個很多人容易搞混的概念,什麼是指標,什麼是指標變數,不懂嗎?那就仔細聽我說明吧,指標實際上就是位址,例如我們平常所說的某個函式返回乙個指標,其實返回的是乙個位址,而指標變數則是儲存位址的變數。正常來說,我們使用c語言定義乙個型別的變數時,就給這個變數名賦予了乙個記憶體空間,如果單純只定義變數而不給其賦值,那麼它的值是不確定,在不同的編譯器不同的計算機都可能會有不同的值,因為作業系統**記憶體單元後並不會清除其內容,當程式執行時需要為變數分配空間時就從這些**的單元中進行分配,例如:
#include#includeint main()
列印出來的結果並不是沒有值,而是:
當你為其賦值時才會重寫該位址的內容。我們經常會聽到書上說,如果你定義乙個指標變數而不給予賦值,是件很恐怖的事情,那是為什麼呢?其實這是為了避免野指標的出現。
什麼是野指標?
指標。與空指標不同,野指標無法通過簡單地判斷是否為
null
避免,而只能通過養成良好的程式設計習慣來盡力減少。對野指標進行操作很容易造成程式錯誤。
野指標有什麼危害呢?
我在這裡引用知乎的一句話:設想,你家裡有個物體,不知什麼時候突然出現,也不知什麼時候突然消失。會把你的東西亂挪位置,還時不時打碎個瓶子。這個物體,在計算機的世界叫野指標。在現實世界,叫貓。
所以為了避免野指標的出現,我們需要有良好的程式設計習慣,例如:
1.指標變數一定要初始化為null,因為任何指標變數(除了static修飾的指標變數)剛被建立時不會自動成為null指標,它的預設值是隨機的。
2.釋放時置 null,當指標p指向的記憶體空間釋放時,沒有設定指標p的值為null。delete和free只是把記憶體空間釋放了,但是並沒有將指標p的值賦為null。通常判斷乙個指標是否合法,都是使用if語句測試該指標是否為null。
指標變數與其位址
我們知道,定義乙個指標變數通常都是type *變數名的格式。type是資料型別,例如int,char等等。我們前面有說,指標變數實際上是儲存位址的變數,而這個位址往往是另乙個變數的位址。例如:
// 指標變數與其位址,普通變數與其位址的區別
int main()
列印的結果是:
我們對其大致分析一下,首先我們定義的乙個變數a,a的值為2,所以列印的a為2,&a是a的記憶體位址,我這裡位址統一用%p(指標)來輸出,然後又定義了乙個整型指標b,把a的值賦予了它,這種寫法是有的,雖然我們前面說了指標變數是用來存指標(位址)的變數,但是給值不給位址這樣也是可以的,這樣的話b就指向了a的內容。列印b實際上就是列印a,實際上這個不等於一種引用,因為b也是有自己的記憶體空間的,類似於一種副本,所以我在後面又將a的值改為3,嘗試列印a,b的值是否還相同,從結果可看出,其實b的值並不會隨著a的變化而變化,說明這種用法並不是一種引用。
然後我們看真正的用法,為定義的指標賦予位址的值,在上面的**中,我將a的位址賦值給了指標變數c,所以c記憶體位址的內容應為a的記憶體位址,我們可以看上面的輸出,可以看出,c的值剛好是a的位址,&c的值的c自己的位址,而*c則為a的值,關於*c,我們可以這麼理解。int *c=&a,那麼a就是c的乙個物件,則*c就是指標變數c指向的那個物件的值。
現在你應該十分了解指標了,那我們在來看看,
二、陣列作為引數和指標有什麼關係?
首先我們先來了解一下什麼叫陣列指標,什麼又是指標陣列。
我們常會聽到說這裡有個整型陣列,是用來放整型的元素的。其實指標陣列跟它是一樣的,不過它是用來放指標(位址)的而已,而陣列指標又是什麼呢?其實陣列指標就是乙個指向了陣列的指標變數。在這裡引用一下大佬的解析:
陣列指標(也稱行指標)
定義 int (*p)[n];
()優先順序高,首先說明p是乙個指標,指向乙個整型的一維陣列,這個一維陣列的長度是n,也可以說是p的步長。也就是說執行p+1時,p要跨過n個整型資料的長度。
如要將二維陣列賦給一指標,應這樣賦值:
int a[3][4];
int (*p)[4]; //該語句是定義乙個陣列指標,指向含4個元素的一維陣列。
p=a; //將該二維陣列的首位址賦給p,也就是a[0]或&a[0][0]
p++; //該語句執行過後,也就是p=p+1;p跨過行a[0]指向了行a[1]
所以陣列指標也稱指向一維陣列的指標,亦稱行指標。
指標陣列
定義 int *p[n];
優先順序高,先與p結合成為乙個陣列,再由int*說明這是乙個整型指標陣列,它有n個指標型別的陣列元素。這裡執行p+1是錯誤的,這樣賦值也是錯誤的:p=a;因為p是個不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它們分別是指標變數可以用來存放變數位址。但可以這樣 *p=a; 這裡*p表示指標陣列第乙個元素的值,a的首位址的值。
如要將二維陣列賦給一指標陣列:
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
這裡int *p[3] 表示乙個一維陣列內存放著三個指標變數,分別是p[0]、p[1]、p[2]
所以要分別賦值。
這樣兩者的區別就豁然開朗了,陣列指標只是乙個指標變數,似乎是c語言裡專門用來指向二維陣列的,它占有記憶體中乙個指標的儲存空間。指標陣列是多個指標變數,以陣列形式存在記憶體當中,占有多個指標的儲存空間。
這是引用網上大神的解釋,重點我都加粗了,應該不難理解。
知道了這個我們再來看乙個例子,陣列作為引數到底是怎麼回事。
上**:
//區別陣列引數,陣列指標,陣列間的區別
int getsize(int data)
int main()
; int size1=getsize(data);
int size2=sizeof(data);
int *da=data;
int size3=sizeof(da);
printf("%d,%d,%d\n",size1,size2,size3);
printf("%p,%p,%p",data,da,&data[0]);
return 0;
}
列印結果是這樣的:
簡答解釋一下**,sizeof()是用來計算位元組數的。我定義了乙個getsize()來獲取傳入的陣列的位元組數,然後來區分不同情況下陣列的位元組數情況。我們都知道整型是4個位元組的。先來看第乙個size1,這裡我將乙個含有四個元素作為引數傳給了自定義的getsize函式,讓它返回引數的位元組數,這裡我們可以知道列印出的結果是4,而第乙個直接獲取定義的陣列的結果卻是16,這是為什麼呢?實際上,當乙個陣列作為引數傳遞給函式時,它是以陣列首元素的指標(位址)的形式傳過去的,即是陣列data[0]的位址,所以它的位元組長度結果為4,接下來我們看下size3,我使用乙個指標變數da來將data直接賦值給他,實際上賦的值也是陣列data的首元素,所以使用sizeof()獲得的也是4個位元組。
接下來我們來看看位址。從列印結果可以知道,陣列作為引數傳進函式後列印出的位址和data,da,&data[0]的首位元組位址都是一樣的。這裡我為什麼說是首位元組呢。因為在32位以上的系統,int是4個位元組,乙個位元組又是8位元,因為記憶體單位是位元組,所以我說這個指標實際上是首位元組的位址。
我講了那麼多,相信你對指標有一定了解了吧。不要問我為啥要寫這篇文章,我閒的蛋疼。
超易懂mysql索引
建立乙個名為user的表,其包括id,name,age,等字段資訊。此外,id為主鍵聚簇索引,idx name為非聚簇索引。create table user id varchar 10 not null default name varchar 10 default null,age int 11...
超簡單易懂的編譯原理詞法分析 python
詞法分析是電腦科學中將字串行轉換為單詞序列的過程,進行詞法分析的程式或者函式叫作詞法分析器,也叫掃瞄器。在本程式中,我通過python實現了乙個簡單的詞法分析器,該程式並不包含完整的詞法分析,因為給的例子並不是很難,所以就沒有新增很多,但是道理就是這樣的道理。example b 1 00101 a ...
樂觀鎖的簡單使用 通俗易懂 超詳細
樂觀鎖機制採取了更加寬鬆的加鎖機制。樂觀鎖是相對悲觀鎖而言,也是為了避免資料庫幻讀 業務處理時間過長等原因引起資料處理錯誤的一種機制,但樂觀鎖不會刻意使用資料庫本身的鎖機制,而是依據資料本身來保證資料的正確性 cas 樂觀鎖技術,當多個執行緒嘗試使用cas同時更新同乙個變數時,只有其中乙個執行緒能更...