目錄
一、什么是pointer
1.指標理解的兩個要點:
2.指標變數
二、指標型別
三、野指標
1.野指標成因
2.如何避免野指標
四、指標運算
1.指標+-整數
2.指標-指標
3.指標的關系運算
五、二級指標
六、指標陣列
【前言】
指標可以說是C/C++中最難學透的部分了,沒有之一!為了更好地闡述指標的一些重要內容,筆者也是把錄播反復看了好幾遍,才把指標初階整理出來,所以,下面的都是重點哦,還來康康吧,
一、什么是pointer
1.指標理解的兩個要點:
- 指標是記憶體中的一個最小記憶體單元的編號,也就是地址(指標就是地址);
- 平時我們口語說的指標,通常指的是指標變數,是用來存放記憶體地址的變數,
【注意】:記憶體單元 == 編號 == 地址 == 指標
再強調一遍,指標就是地址,通常口語中所說的指標大多指的是指標變數,
在記憶體中:

記憶體被劃分成一個個小的記憶體單元,一個基本的記憶體單元的大小是一個位元組,
2.指標變數
我們可以通過&變數,取出變數的記憶體起始地址,把地址存放到一個變數當中,這個變數就是指標變數,
#include<stdio.h>
int main()
{
int a = 10;//定義整型變數a,會在記憶體中開辟一塊空間
int* p = &a;//*告訴我們p是一個指標變數,int表示p指向的物件的資料型別是int
return 0;
return 0;
}
指標變數,用來存放地址的變數(注意:存放在指標變數中的值都被當作了地址來處理)
那這里的問題是:
- 一個小的記憶體單元到底是多大?-->答案是一個位元組
- 如何編址呢?
這里就主要探討如何編制:
對于32位機器來說,假設有32根地址線,每根地址線在尋址的時候會產生高電平和低電平,也就是電信號1/0,那么32根地址線產生的地址就會是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
... ... ... ...
01111111 11111111 11111111 11111111
10000000 00000000 00000000 00000000
10000000 00000000 00000000 00000001
... ... ... ...
11111111 11111111 11111111 11111101
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111111
這里就會有2^32個地址編號,因為一個記憶體編號管理一個位元組大小的空間(注意這里不要將指標大小和指標管理一塊空間的大小混淆!指標大小在32位平臺是4個位元組,在64位平臺是8個位元組,而指標也就是一塊記憶體單元編號,可以管理一個位元組的空間)所以32位機器可以管理2^32個位元組的記憶體空間,換算成GB也就是:2^32Byte == 2^32 / 1024KB == 2^32 / 1024 / 1024MB == 2^32 / 1024 / 1024 / 1024GB == 4GB,同樣的方法算出,對于64位機器,可以管理8GB大小的記憶體空間,
【總結】
- 指標是用來存放地址的,指標是唯一表示一塊記憶體空間的;
- 指標的大小在32位平臺是4個位元組,在64位平臺是8個位元組,
二、指標型別
問題引入:指標型別都是4/8個位元組,那還分不同指標型別干什么?
回答這個問題,那這里就要好好說道說道指標型別的意義了(注意哦,非常重要!!!)
意義一:
指標型別決定了指標在解參考的時候一次能訪問幾個位元組(也叫指標的權限),
int* —— 4個位元組
char* —— 1個位元組
double* —— 8個位元組
【注意】:需要注意的是,不要和指標型別的大小混淆咯!
意義二:
指標型別決定了指標向前或向后走一步的步長(+-整數),單位是位元組!
三、野指標
野指標就是指標指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
1.野指標成因
- 指標未初始化;
- 指標越界訪問;
- 指標指向的空間已經釋放(特別易錯),
具體講解:
<1>指標未初始化
比如:int* p;//區域變數指標未初始化,默認是隨機值,這是不可取的,
<2>指標越界訪問
//最常見的就是陣列越界訪問
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
int i = 0;
for (i = 0; i < 12; i++)//陣列越界
{
arr[i] = 1;
}
return 0;
}
<3>指標指向的空間已經釋放
#include<stdio.h>
int* test()
{
//區域變數a是具有生命周期的,一旦出了這個范圍就會被銷毀,記憶體空間的使用權限被識訓了
int a = 100;
return &a;//回傳a的地址
}
int main()
{
int* p = test();
//指標p用來接收a的地址,但是test函式呼叫完畢后,分配給a的記憶體空間也就被識訓了
//此時p接受的地址是不正確的,導致p成為了野指標
printf("%d\n", *p);
return 0;
}
2.如何避免野指標
- 指標初始化;
- 小心指標越界;
- 指標指向的空間釋放需要即時置為NULL(也就是說,指標不想用了就將它置為NULL);
- 避免回傳區域變數的地址(野指標的成因3);
- 指標使用之前需要檢查其有效性,
具體講解:
<1>指標初始化
比如:int* p = NULL;//指標的使用需要初始化,如果不知道指標指向誰,可以先初始化成NULL
<2>小心指標越界
主要是在陣列中,注意陣列下標很容易導致越界訪問
<3>指標指向的空間釋放需要即時置為NULL(也就是說指標不想用了就將它置為空)
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
//通過指標pa將a的值改為20
*pa = 20;
printf("%d\n", a);//輸出20
//pa完成它的任務之后,在整個工程中都不想用它了,需要即時將它置為NULL
pa = NULL;//可能在學校教學中很少這樣寫,但是在企業級的代碼規范中是這樣要求的喲
return 0;
}
<4>避免回傳區域變數的地址
#include<stdio.h>
int* test()
{
//區域變數a是有生命周期的,所以a一旦出了test()函式范圍就會被銷毀
//也就是說定義a時分配給a的記憶體空間的使用權限不再是a的了,已經被系統識訓
int a = 100;
return &a;//回傳a的地址(出test函式之后這塊地址不再是a的了)
}
int main()
{
//原本是定義指標變數p,用來接收a的地址
//但是a呼叫test函式結束后,a的地址被系統識訓了
//所以指標p指向的位置是不可知的、不正確的
//這是最容易出錯的典型!一定要小心哦
int* p = test();
printf("%d\n", *p);
return 0;
}
<5>指標使用之前要檢查其有效性
//還用上面的那道題目,通過指標pa將a的值改為20
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;//此時pa指向的是a的地址,對pa進行解參考操作等同于對a進行操作
//需要通過對指標pa進行解參考操作,將a的值更改為20
//但是在使用pa之前,最好要判斷其有效性
//可能你會覺得下面這個步驟有點畫蛇添足了,但是請相信筆者,這種習慣在上千行的程式中會很受用
//更不要說在之后進入企業中面對上十萬行的專案了,所以請鐵汁現在就養成良好的編程習慣!
if (pa != NULL)
{
*pa = 20;
}
printf("%d\n", a);
return 0;
}
四、指標運算
1.指標+-整數
這里就要重提指標型別的意義了,前面說過指標型別的意義二:指標型別決定了指標向前或向后走一步的步長(+-整數),單位是位元組,具體看在記憶體中的操作:
#include<stdio.h>
int main()
{
//定義一個整型陣列
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
return 0;
}

#include<stdio.h>
int main()
{
//定義一個字符陣列
char arr[] = {'a','b','c','\0'};
return 0;
}

好,指標+-整數就講到這里咯,大家下去自己動手看看short型、double型指標+-整數是什么樣的效果,
2.指標-指標
注意哦,使用指標-指標運算的時候,前提是兩個指標指向的是同一塊記憶體空間,那何為指向同一塊記憶體空間呢?最典型的例子就是陣列,
指標-指標其實表示的是兩個指標中間的元素個數,注意哦,不是中間有幾個位元組,
指標-指標的實踐:自定義函式實作strlen函式的功能
#include<stdio.h>
#include<assert.h>
int my_strlen(char* arr)
{
assert(arr);
char* end = arr;
while (*end != '\0')
{
end++;
}
return end - arr;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
3.指標的關系運算
指標的關系運算,也就是指標比較大小,指標怎么比較大小呢,前面我們說過,指標就是地址,所以指標比較大小比較的是地址的大小,也就是說比較的是地址的高低,
這個很簡單,在這里就不說了,
五、二級指標
指標變數也是變數,是變數就需要在記憶體中開辟空間,故而也就會有地址,所以指標變數的地址存放到二級指標中,
六、指標陣列
指標陣列是陣列,是用來存放指標變數的陣列! 說簡單點,它和整型陣列、字符陣列等別無二致,只不過陣列型別不同而已,
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int c = 0;
int* pa = &a;
int* pb = &b;
int* pc = &c;
//定義一個指標陣列
int* arr[] = { pa,pb,pc };
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/385889.html
標籤:其他
