文章目錄
- *首先,我們來看看指標的定義,*
- ***下面,我們就來看看指標和指標型別***
- ***我們先來看看野指標的概念***
- ***我們講一下指標運算***
- ***我們再來看看指標和陣列***
- ***二級指標***
- ***接下來我們了解一下指標陣列***
hello,今天我們來分享一些關于指標的內容,我們都知道,指標可謂是博大精深,讓一眾小白望塵莫及,那么指標真的那么可怕嗎?莫慌,讓我們一起來征服它,

首先,我們來看看指標的定義,

那么什么是記憶體呢?
我們知道,計算機是有32位和64位之分的,所謂32位就是有32位地址線,64位就是有64位地址線,每根地址線有正負電之分,我們可以對應為0和1來表示,也就是二進制來表示,
我們以32位的計算機為例,它的表示范圍為00000000000000000000000000000000到11111111111111111111111111111111
這之中的每一個編號都可以作為一個地址,也是一個位元組,

明確了這個問題之后,我們再來往下看一段代碼:

這就是指標變數儲存地址的最直觀案例了,那么也許你會有一個疑問,a是int型的,我們知道它占四個位元組,那么指標變數指向的是其中的一個位元組還是全部位元組呢?答案在下圖揭曉:

沒錯**,指標指向的就是首地址,**那么既然p指向的是首地址,我們又怎么能一次性地取到a的全部地址呢?我們要借用一個符號——*,對,就是星號,星號是解參考運算子,我們通過一個例子來看一下:

那么講到這里你是否有一個疑問,我們上面有說道,**32位計算機指標變數大小為四個位元組,64位計算機指標變數大小為八個位元組,**那為什么還要給指標變數定義型別呢?這個問題我們繼續往下看:
下面,我們就來看看指標和指標型別
:
我們先來看一個例子:



看完以上三張圖,注意找不同哦!有沒有什么發現?

謎底揭曉:

好的,通過以上的演示我們就可以明白,定義指標的型別,目的是決定指標訪問幾個位元組,我們再來看一個例子;

通過這個例子我們還可以看出,指標型別不僅可以決定指標訪問幾個位元組,也可以決定指標加一后,跳過幾個位元組,
根據這個規律,我們就可以這樣寫程式了:

好的,我們繼續看下一個程式:
#include<stdio.h>
int *test()
{
int a =10;
return &a;
}
int main()
{
int *p = test();
printf("hh\n");
printf("%d ", *p);
return 0;
}
猜猜螢屏上會輸出什么?
答案揭曉:

我們發現輸出的竟然是一個隨機值,那么這是為什么呢?聰明的小伙伴們想必已經猜到了,當test函式執行完成,a的空間就已經被釋放了,所以后出現隨機值,(有的同學可能會發現,如果我們不列印hh,輸出的值就是10,這個問題比較復雜,我們在之后的文章中再講,)列印出隨機值,這里的p就成為了傳說中的——野指標,
我們先來看看野指標的概念
:野指標是指指標指向的位置是不可知的,包括隨機的,不正確的或者沒有明確限制的,
也許你曾經在網上刷到過野生大爺的段子,但野指標從破壞力上來說完勝野生大爺,

那么都有什么原因會造成野指標呢?
1.指標未初始化

2.指標越界訪問


通過以上兩張圖對比,我們可以發現,第一張圖報錯的原因是陣列大小僅為10,而我們放了11個元素,這就是指標越界,但有人可能會發現,為什么自己的程式明明越界了,但編譯器為什么沒有報錯呢?難道厲害的你成功騙過了編譯器?

這個問題呢,顯然,雖然編譯器沒有報錯,但你畢竟是錯了,就好比小偷偷了東西,雖然沒有被警察發現,但畢竟也是偷了,雖然讀書人的事怎么能叫偷呢?所以,小伙伴們一定要注意,還是不要越界的好!!!
3.指標指向的空間被釋放
比如這個例子:

野指標破壞力如此之強,那么我們又該如何避免野指標呢?
在下給出如下建議:
1、指標初始化
2、小心指標越界
3、指標指向空間釋放即時置NULL(空指標)
4、指標使用之前檢查有效性
好的,接下來,簡單說完野指標,我們繼續往下來:
我們講一下指標運算
那么指標都有哪些運算呢?我們來看一下:
- 指標+/-整數
- 指標-指標
- 指標的關系運算
好的,下面我們分別來看看這三種指標運算:
1.指標+/-整數
先來看這個例子:


通過這個例子我們可以發現,指標加減整數運算的一些規律,我們發現上面的程式兩種寫法輸出的結果是一樣的,那么這兩種寫法有什么不同呢?我們來逐一分析一下:

我們發現第一種寫法,指標p其實是沒有變的,一直指向起始地址,只是p加了整數之后,產生的新的p+i,指向新的數字,

我們發現這種寫法和第一種的輸出是一樣的,我們來分析一下這個程式,在這個程式里,p的指向發生了變化,p指向的地址被賦予了i的值,當我們需要輸出時,我們需要重新把p賦成arr,這樣再利用for回圈,就可以列印出0~9,
通過以上兩個例子,我們可以發現,指標與整數的加減法,有時候可以產生新的地址,有時候可以改變指標指向的地址,
2.指標-指標
我們先來看一個例子:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", &arr[9] - &arr[0]);
return 0;
}
猜一猜這個小巧的程式輸出的結果是什么?
10?40?隨機值?————答案揭曉:

想不到吧,答案竟然是9!!!這就告訴我們——指標-指標得到的值的絕對值是指標之間的元素個數,有小伙伴可能會問了,為什么要加一個絕對值的限定呢?我們將上述程式做一點小改動,再來看看結果:

這下明白為什么要限定絕對值了吧,

那么有的小伙伴可能會突發奇想,寫出下面這樣的程式:
#include<stdio.h>
int main()
{
int a[5] = { 0 };
char b[5] = { 0 };
printf("%d \n", &a[5] - &b[0]);
return 0;
}
這個結果又會輸出什么呢?讓我們來看一下:

結果是9,有什么規律嗎?現在我們還無法確定,我們更改一下這個程式,我們再創建一個char型的c陣列,再來看一看,如果有什么規律,兩次的結果應該是相同的:

輸出的結果是13,與之前的9不同,我們從中也可以看出,不同型別的指標的差值是沒有規律的,因為,我們不能確定他們開辟的空間相距多遠,杠精會問,相同型別不是一個陣列會有規律嗎?我們用一個程式驗證一下:

通過上面這個程式我們發現,即使是同種型別的不同陣列,也沒有什么規律,由此,我們必須清醒地認識到,指標相減是有條件滴,條件就是:兩個指標指的是同一塊連續空間,you know?
3.指標的關系運算:
先來看一個例子:

我們將這個程式稍加改動,再來看一下結果:

我們發現編譯器報錯了,這又是為什么呢?
原來C語言有一個標準標準規定:


好家伙,服氣不?
我們來試著理解一下這個神奇地標準:

也就是說p是可以和R進行比較滴,但不可以和L進行比較,這就是規定,人再江湖,身不由己,該屈服就屈服,即使再抗拒,也就認了這規定吧!
好的,了解了指標運算之后,
我們再來看看指標和陣列
一個問題,陣列名是什么?想知道這個問題的答案快來看一看這迷人的小截圖:

通過這個小程式我們可以發現:陣列名表示的是陣列首元素的地址
于是,我們就可以利用指標,寫出這樣的程式:
#include <stdio.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指標存放陣列首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
}
return 0;
}

并且,二維陣列的陣列名也是陣列首元素地址,但是二維陣列的首元素是它的第一行,類似于一個一維陣列,
對于一個二維陣列:a[3][5]我們看下圖:

好的,我們再來看下一個問題:
二級指標
指標變數也是變數,是變數就有地址,那指標變數的地址存放在哪里? 這就是 二級指標 ,

接下來我們了解一下指標陣列
什么是指標陣列呢?指標陣列本質上是一種陣列,不過指標陣列用來存放指標,
舉一個例子:
#include<stdio.h>
int main()
{
int a=0;
int b=5;
int c=10;
int *arr[3] = { &a, &b, &c };//指標陣列
return 0;
}
為了更好理解,我們來對比一下普通陣列和指標陣列:

好的,今天我們的分享就到這里,這只是關于指標的一些基本的知識,博主會在下一次的博文中與大家分享關于指標的進階知識,也就是我們的《安得指標千萬間,大庇天下地址具歡顏(下)》,還請大家繼續支持,
本篇博文歷時兩天完成,創作不易,如果各位覺得這篇文章還可以,歡迎大家點贊、收藏、轉發、評論,由于本人水平有限,如有錯漏,也歡迎各位批評指正,歡迎大家和我一起交流學習心得,一起加油!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/267085.html
標籤:其他
上一篇:講解web請求和http協議
下一篇:樹莓派(Raspberry Pi) Pico VSCode C/C++開發環境配置(無需Visual Studio)
