文章目錄
- 指標是什么?
- 指標的定義
- 指標的大小
- 指標型別
- 指標有哪些型別?
- 指標型別有什么意義?
- 野指標
- 野指標的成因
- 如何避免野指標
- 指標運算
- 指標+-整數
- 指標-指標
- 指標的關系運算
- 二級指標
指標是什么?
指標的定義
在計算機科學中,指標(Pointer)是編程語言中的一個物件,利用地址,它的值直接指向(points to)存在電腦存盤器中另一個地方的值,由于通過地址能找到所需的記憶體單元,可以說地址指向該記憶體單元,因此,將地址形象化的稱為“指標”,意思是通過它能找到以它為地址的記憶體單元,
這是官方對指標的定義,其實我們可以理解為:在記憶體中,記憶體被細分為一個個大小為一個位元組的記憶體單元,每一個記憶體單元都有自己對應的地址,

我們可以將這些記憶體單元形象地看成一個個的房間,將記憶體單元(房間)對應的地址形象地看成房間的門牌號,而我們通過門牌號(地址)就可以唯一的找到其對應的房間(記憶體單元),即地址指向對應記憶體單元,所以說,可以將地址形象化的稱為“指標”,
指標變數是用于存放地址的變數,(存放在指標中的值都將被當作地址處理)
#include<stdio.h>
int main()
{
int a = 10;//在記憶體中開辟一塊空間
int* p = &a;//將a的地址取出,放到指標變數p中
return 0;
}
總結:
- 指標變數是用于存放地址的變數,(存放在指標中的值都將被當作地址處理)
指標的大小
對于32位的機器,即有32根地址線,因為每根地址線能產生正電(1)或負電(0),所以在32位的機器上能夠產生的地址信號就是32個0/1組成的二進制序列:

一共 232 個地址,
同樣的演算法,在64位的機器上一共能產生 264 個不同的地址,
232 可以用32個bit位進行存盤,而8個bit位等價于1個位元組,所以在32位的平臺下指標的大小為4個位元組,
264 可以用64個bit位進行存盤,所以在64位的平臺下指標的大小為8個位元組,
總結:
- 在32位平臺下指標的大小為4個位元組,在64位平臺下指標的大小為8個位元組,
指標型別
指標有哪些型別?
我們知道,變數的型別有int,float,char等,那么指標有沒有型別呢?回答是肯定的,
指標的定義方式是type+ *
char * 型別的指標存放的是char型別的變數地址;
int * 型別的指標存放的是int型別的變數地址;
float * 型別的指標存放的是float型別的變數地址等,
指標型別有什么意義?
1.指標±整數
若指標型別為int * 的指標+1,那么它將跳過4個位元組的大小指向4個位元組以后的內容:

若指標型別為char * 的指標+1,那么它只會跳過1個位元組的大小指向下一個位元組的內容,以此類推,
2.指標解參考
指標的型別決定了指標解參考的時候能夠訪問幾個位元組的內容,
若指標型別為int *,那么將它進行解參考操作,它將可以訪問從指向位置開始向后4個位元組的內容:

若指標型別為char *,那么將它進行解參考操作,它將可以訪問從指向位置開始向后1個位元組的內容,以此類推,
總結:
- 指標的型別決定了指標向前或向后走一步有多大距離,
- 指標的型別決定了指標在進行解參考操作時,能向后訪問的空間大小,
野指標
概念:野指標就是指向位置是不可知的(隨機的、不正確的、沒有明確限制的)指標,
野指標的成因
1.指標未初始化
#include<stdio.h>
int main()
{
int* p;
*p = 10;
return 0;
}
區域指標變數p未初始化,默認為隨機值,所以這個時候的p就是野指標,
2.指標越界訪問
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = &arr[0];
int i = 0;
for (i = 0; i < 11; i++)
{
*p++ = i;
}
return 0;
}
當指標指向的范圍超出arr陣列時,p就是野指標,
3.指標指向的空間被釋放
#include<stdio.h>
int* test()
{
int a = 10;
return &a;
}
int main()
{
int* p = test();
return 0;
}
指標變數p得到地址后,地址指向的空間已經釋放了,所以這個時候的p就是野指標,(區域變數出了自己的作用域就被釋放了)
如何避免野指標
1.指標初始化
當指標明確知道要存放某一變數地址時,在創建指標變數時就存放該變數地址,
當不知道指標將要用于存放哪一變數地址時,在創建指標變數時應置為空指標(NULL),
#include<stdio.h>
int main()
{
int a = 10;
int* p1 = &a;//明確知道存放某一地址
int* p2 = NULL;//不知道存放哪一地址時置為空指標
return 0;
}
2.小心指標越界
3.指標指向的空間被釋放后及時置為NULL
3.使用指標之前檢查有效性
在使用指標之前需確保其不是空指標,因為空指標指向的空間是無法訪問的,
指標運算
指標±整數
#include<stdio.h>
int main()
{
int arr[5] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 5; i++)
{
*(p + i) = i;
}
return 0;
}
指標-指標
指標-指標的絕對值是是兩個指標之間的元素個數,
int my_strlen(char* p)
{
char* pc = p;
while (*p != '\0')
p++;
return p - pc;
}
strlen函式的模擬實作就可以運用指標-指標的代碼實作,
指標的關系運算
指標的關系運算,即指標之間的大小比較,
我們如果要將一個陣列中的元素全部置0,可以有兩種方法,
第一種:從前向后置0
#include<stdio.h>
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int* p = &arr[0];
for (p = &arr[0]; p <= &arr[4]; p++)
{
*p = 0;
}
return 0;
}
最終指向陣列最后一個元素后面的那個記憶體位置的指標將與&arr[4]比較,不滿足條件,于是結束回圈,
第二種:從后向前置0
#include<stdio.h>
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int* p = &arr[4];
for (p = &arr[4]; p >= &arr[0]; p--)
{
*p = 0;
}
return 0;
}
最終指向第一個元素之前的那個記憶體位置的指標將與&arr[0]比較,不滿足條件,于是結束回圈,
這兩種方法在絕大部分編譯器下均能將arr陣列中的元素置0,但是我們要盡量使用第一種方法,因為標準并不保證第二種方法可行,
標準規定:
允許陣列元素的指標與指向陣列最后一個元素后面的那個記憶體位置的指標比較,但是不允許與指向第一個元素之前的那個記憶體位置的指標進行比較,
二級指標
我們知道,指標變數是用于存放地址的變數,但是指標變數也是變數,是變數就有地址,那么存放指標變數的地址的變數是什么呢?
其實,存放普通變數的地址的指標叫一級指標,存放一級指標變數的地址的指標叫二級指標,存放二級指標變數地址的指標叫三級指標,以此類推,
#include<stdio.h>
int main()
{
int a = 10;
int* p1 = &a;
int** p2 = &p1;
return 0;
}
在這里,我們用一級指標p1存放了普通常量a的地址,用二級指標p2存放了一級指標p1的地址,
這時如果我們要得到a的值,就有兩種方法:
方法一:對一級指標p1進行一次解參考操作即可得到a的值,即*p1,
方法二:對二級指標p2進行一次解參考操作即可得到p1的值,而p1的值就是a的地址,所以再對p2進行一次解參考操作即可得到a的值,也就是對二級指標p2進行兩次解參考操作即可得到a的值,即**p2,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/259726.html
標籤:其他
上一篇:【VideoQA最新文獻閱讀】Open-Ended Multi-Modal Relational Reason for Video Question Answering
