●🧑個人主頁:你帥你先說.
●📃歡迎點贊👍關注💡收藏💖
●📖既選擇了遠方,便只顧風雨兼程,
●🤟歡迎大家有問題隨時私信我!
●🧐著作權:本文由[你帥你先說.]原創,CSDN首發,侵權必究,
文章目錄
- 1.指標是什么?
- 2.指標
- 3.指標型別
- 4.野指標
- 4.1野指標成因
- 4.2如何規避野指標
- 5.指標運算
- 5.1指標+ -整數
- 5.2指標-指標
- 5.3指標的關系運算
- 6.指標和陣列
- 7.二級指標
- 8.指標陣列
1.指標是什么?
在計算機科學中,指標(Pointer)是編程語言中的一個物件,利用地址,它的值直接指向(points to)存在電腦存盤器中另一個地方的值,由于通過地址能找到所需的變數單元,可以說,地址指向該變數單元,因此,將地址形象化的稱為“指標”,意思是通過它能找到以它為地址的記憶體單元,
2.指標
指標是個變數,是用來存放記憶體單元的地址,
#include <stdio.h>
int main()
{
int a = 10;//在記憶體中開辟一塊空間
int *p = &a;//這里我們對變數a,取出它的地址,可以使用&運算子,
//將a的地址存放在p變數中,p就是一個之指標變數,
return 0;
}
總結:指標就是變數,用來存放地址的變數,(存放在指標中的值都被當成地址處理),
那這里的問題是:
一個小的單元到底是多大?
如何編址?
在記憶體中每一個小單元的大小是1個位元組
在計算機中:
32位-32根地址線
地址線-1/0 要么是0要么是1
那一共多少種可能?
00000000000000000000000000000000
00000000000000000000000000000001
…
111111111111111111111111111111111111
一共 2 32 2^{32} 232種可能
轉換成10進制就是4294967296
除1024算出來是4,194,304Kb
除1024算出來是4096Mb
再除1024算來是4GB
這里我們就明白:
1.在32位的機器上,地址是32個0或者1組成二進制序列,那地址就得用4個位元組的空間來存盤,所以一個指標變數的大小就應該是4個位元組,
2.那如果在64位機器上,如果有64個地址線,那一個指標變數的大小是8個位元組,才能存放一個地址,
3.指標型別
我們都知道,變數有不同的型別,整形,浮點型等,那指標有沒有型別呢?
準確的說:有的
int* num = 10;
p = #
這里就是個int型的指標,除了這些,變數有的型別指標都有,
char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double*pd = NULL;
我們知道,指標是用來存放地址的,在32位平臺下地址是4個位元組,那為什么還要創建出那么多指標型別呢?
int a = 0x11223344;
int*pa = &a;
*pa = 0;
剛開始a的記憶體是這樣的

當執行到*pa = 0后

我們把這段代碼改一改
int a = 0x11223344;
char* pc = &a;
*pc = 0;
剛開始依舊是這樣的

當執行到*pc = 0后

這次與上次不同 只有1個位元組的大小發生了改變
所以我們就知道指標型別決定了指標解參考操作的時候,一次訪問幾個位元組,char*指標解參考訪問1個位元組,int*指標解參考訪問4個位元組,

通過觀察,可以發現不管存在int型別還是char型別,a的地址都是一樣的,但當+2時跳過的位元組就不一樣了,int型別的跳過了8個位元組,而char型別的只跳過了兩個型別,
所以指標型別還決定了指標+ -整數的時候的步長(指標±整數的時候,跳過幾個位元組),int* 指標 +1 跳過4個位元組,char* 指標+1 跳過1個位元組,
4.野指標
概念: 野指標就是指標指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
4.1野指標成因
- 指標未初始化
#include <stdio.h>
int main()
{
int *p;//區域變數指標未初始化,默認為隨機值
*p = 20;
return 0;
}
2.指標越界訪問
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//當指標指向的范圍超出陣列arr的范圍時,p就是野指標
*(p++) = i;
}
return 0;
}
- 指標指向的空間釋放
int* test()
{
int a = 10;
return &a;//函式只要呼叫就會申請空間,出了這個函式申請的空間就會被釋放
}
int main()
{
int* p = test();
printf("%d\n", *p);//此時空間被釋放,這塊空間已經不屬于你了,此時再去訪問就是非法訪問
return 0;
}
4.2如何規避野指標
1. 指標初始化
2. 小心指標越界
3. 指標指向空間釋放即使置NULL
4. 避免回傳區域變數的地址
5. 指標使用之前檢查有效性
int main()
{
int a = 10;
int* p = &a;//明確地初始化,確定指向
int* p2 = NULL;//不知道一個指標當前應該指向哪里時,可以初始化為NULL
//*p2 = 100;//err 空指標不能解參考
//這樣寫代碼就可以避免訪問到空指標了
if (p2 != NULL)
{
*p2 = 100;
}
return 0;
}
5.指標運算
5.1指標+ -整數
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指標+-整數;指標的關系運算
for (vp = &values[0]; vp < &values[N_VALUES]; )
{
*vp++ = 0; //將陣列中的內容都改成0
}
5.2指標-指標
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
char ch[5] = { 0 };
printf("%d\n", &arr[9] - &arr[0]);
指標-指標 得到的數字的絕對值是指標和指標之間元素的個數
printf("%d\n", &arr[9] - &ch[0]);//err這種寫法就是錯誤的
指標-指標的前提是兩個指標指向同一塊區域
//
圖解

學完這些我們就可以用指標寫一個my_strlen函式了
int my_strlen(char* s)
{
int count = 0;
while (*s != '\0')
{
count++;
s++;
}
return count;
}
也可以利用剛剛所學的指標-指標
int my_strlen(char* s)
{
char* start = s;
while (*s != '\0')
{
s++;
}
return s-start;
}
5.3指標的關系運算
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
這段代碼和剛剛上面那段代碼類似,只是這次是從后往前
我們可以對這段代碼進行簡化
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
圖解

這段代碼最侄訓造成這種情況,實際在絕大部分的編譯器上是可以順利完成任務的,然而我們還是應該避免這樣寫,因為標準并不保證它可行,
C語言標準規定
允許指向陣列元素的指標與
指向陣列最后一個元素后面的那個記憶體位置的指標比較,但是不允許與指向第一個元素之前的那個記憶體位置的指標進行比較,
6.指標和陣列
陣列名是什么?我們看一個例子:
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}

你會發現這兩個列印的內容是一樣的,
所以陣列名是首元素的地址,但有兩個例外
1. sizeof(陣列名) - 這里的陣列名不是首元素的地址,是表示整個陣列的,這里計算的是整個陣列的大小,單位還是位元組
2. &陣列名 - 這里的陣列名不是首元素的地址,是表示整個陣列的,拿到的是整個陣列的地址
7.二級指標
指標變數也是變數,是變數就有地址,二級指標就是用來存放一級指標的地址,

那要怎么理解int** ppa呢?
我們可以把int** ppa拆成int* * pa,第二個 *告訴我們pa是指標變數,int* 告訴我們pa所指向a的型別是int*,
再舉個例子
int a = 10;
int* pa = &a;
int** ppa = &pa;
int*** pppa = &ppa;
同樣地,我們可以把int*** pppa拆成int** * pppa,第三個*告訴我們pppa是個指標變數,int**告訴我們pppa所指向的ppa的型別是int**,
我們知道,*pa是對a進行解參考可以找到a的內容,同理,*ppa可以找到pa的內容,那么**pa就可以找到a的內容,通過這些,對于指標的理解又進一步提升了,
雖然指標有二級、三級、四級、五級等,但實際應用中經常使用的
還是二級指標
8.指標陣列
指標陣列是指標還是陣列?
答案:是陣列,是存放指標的陣列,
int arr[10];//整型陣列---存放整型的陣列
char ch[5];//字符陣列---存放字符的陣列
//指標陣列---存放指標的陣列
//int* 整型指標陣列
//char* 字符指標陣列
int* pa[5];//整型指標陣列
char* pc[5];//字符指標陣列
通過之前的學習,我們可以知道存放指標的陣列相當于是存放地址的陣列,
看完這些

所以你也應該意識到

離開之前

這樣的文章你還不趕緊 點贊收藏+關注作者!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/294987.html
標籤:其他
