目錄
指針這一部分可能很多人在學習的時候都覺得很難,但在這里我想說的是:不要自己嚇自己,想一想,你當初剛上大學的時候可能覺得高數非常難,最后學完整本書的時候回過頭再看還覺得很難嗎? 肯定已經覺得沒有剛開始學那么難了,那么其實指針也是這樣的,只要把里面的東西都搞清楚,你就不覺得難了。
?
?
?在計算機科學中,指針(Pointer)是編程語言中的一個對象,利用地址,它的值直接指向
(points to)存在電腦存儲器中另一個地方的值。由于通過地址能找到所需的內存單元,可以
說,地址指向該變量單元。因此,將地址形象化的稱為“指針”。意思是通過它能找到以它為地址
的內存單元。
?其實計算機在設計的時候很多東西都是參考的生活中的東西
eg.我國的國土面積:960萬平方公里,這么大的國土面積是怎么合理使用的呢?聰明的國家領導人就想到,將這一大塊區域進行劃分,先劃分為各個省,每個省再劃分為各個市區,市區又劃分為縣城,縣劃分為鎮,鎮又劃分為村,每個村的每戶人家都有門牌號,可以很方便的找到,這樣就對這樣一大塊區域進行了很好的管理。
那么其實電腦的設計也是這樣的,在學C語言的這個階段,我們常說的計算機的內存劃分為3部分,棧區,堆區和靜態區。
?計算機在最終也是將內存劃分為了很小的空間--內存單元。
我們平時要在學校找一個同學,也是先確定他的宿舍編號然后才去找的,不可能盲目的去找,而這里宿舍編號就是地址。
那在計算機內存中,我們想要找到某個內存單元,也是要知道它的編號呀,所以這里就對每個內存單元都進行了編號處理,將編號就稱為內存單元的地址。
那么問題又來了
1.計算機中的32位或者62位
32位的機器,它是有32根地址線(32根物理的電線),通電之后會將電信號轉換成數字信號(正電--1,負電--0),32根地址線通電之后會產生以下的二進制序列數字信號:
00000000000000000000000000000000(32位)
00000000000000000000000000000001
00000000000000000000000000000010
………………………………………………
11111111111111111111111111111111
這個時候呢將二進制序列與內存單元一一對應,那么與內存單元相對應的二進制序列就是它的編號--地址。
?2.每一個內存單元到底多大?
這個我們也是可以來計算一下
比如一個內存單元是1bit,那么32位機器的所產生的序列共計2^32個,即2^32bit,轉化為MB就是512MB,要想想我們買的計算機都是起步2G/4G,所以內存單元以bit為單位肯定是不行的。在C語言中,我們創建一個變量所申請的空間最小都是char--1byte,所以其實內存單元單位其實是字節。
請看如下代碼:
int main(){ int a = 10; //創建變量a,向內存申請4個字節的空間,將10存儲進去 return 0;}
我們創建了變量a,如何得到它的地址呢?? 我們只需要在a的前面加上?&?(取地址操作符
)符號,便可以得到它的空間地址
int main(){ int a = 10; //創建變量a,向內存申請4個字節的空間,將10存儲進去 printf("%p/n", &a); //%p--打印地址(16進制) return 0;}
我們可以把打印出來的地址00EFF6E8(16進制)轉化成二進制來看看1110 1111 1111 0110 1110 1000
我們平時可以創建字符變量來存字符,創建整型變量來存整型,那如果想將地址存起來呢?那我們就得創建一個指針變量----用來存放地址
int main(){ int a = 10; //創建變量a,向內存申請4個字節的空間,將10存儲進去 int* p = &a; //&a取出a的地址,創建指針變量p,接收a的地址 return 0;}
* 說明p是指針變量,前面的int說明p指向的是整型變量
?指針變量p里面存放的就是a的地址,我們可以通過p里面所存儲的值(地址)來找到變量a的內存空間,所以我們就說p指向了a,所以將p形象的稱為指針(注意變量名字是p,不是*p)
那么我們以后想要存儲地址的時候,就可以用指針
int main(){ float b = 2.5; float* p = &b; return 0;}
我們創建指針存放變量地址的本質目的并不是為了存放變量的地址,而是為了將來能夠通過地址來找到這個變量的內存空間,使用它。
我們上面已經存放了a的地址在p里面,那么我們怎么找到a呢
int main(){ int a = 10; int* p = &a; *p = 20; //這里*---解引用操作符 return 0;}
?這里的 * --解引用操作符(間接訪問操作符),p里面存的是a的地址,那么*p就是通過地址來找到a
通過上面的代碼我們會發現,一個char類型的變量的地址放在char*的指針里面,整型變量的地址存放在整型指針里面,為什么要這樣呢?
如下代碼:
int main(){ int a = 10; char ch = "f"; int* pa = &a; char* pc = &ch; //兩個指針都是4個字節}
這里要存放a的地址和ch的地址,都只需要4個字節(32位平臺)的指針就可以,那為什么還要用不同類型的指針呢?
雖然它們都是4個字節,但是也是有區別的,我們通過以下代碼的對比來看看
代碼1:
int main(){ int a = 0x11223344; int* pa = &a; *pa = 0;}
在內存里面看
a的內存里面的內容(執行*pa = 0;這個語句前后對比)(先不要管為什么內存里面是倒著存放的)
?代碼2:
int main(){ int a = 0x11223344; char* ca = &a; *ca = 0;}
?a的內存里面的內容(執行*ca = 0;這個語句前后對比)
?
?我們通過代碼1和代碼2以及他們的內存情況可以看出在代碼1int*類型的指針在解引用的時候將a里面4個字節的內容全部改成了0(可訪問4個字節),但是代碼2中char*類型的指針在解引用的時候只改了1個字節的內容(只能訪問一個字節),這就是指針不同類型的差異
通過以下代碼來體驗一下:
#include int main(){ int a = 0x11223344; int* pa = &a; char* ca = &a; printf("%p/n", pa); printf("%p/n", pa + 1); printf("/n"); printf("%p/n", ca); printf("%p/n", ca + 1); return 0;}
?通過這段代碼我們可以發現int*類型的指針進行+1操作地址加了4,char*類型的指針進行+1操作地址加了1
我們也可以通過下面的例子再來看看(通過指針來打印整型數組的內容)
代碼1(通過整型指針來訪問整型數組)
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* parr = arr; int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(parr + i)); } return 0;
?
分析:
整型指針進行+1操作,意味著一次跳過一個整型(如下圖)
?代碼2(通過字符指針來訪問整型數組)
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; char* parr = arr; int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(parr + i)); } return 0;}
?字符類型的指針+1每次跳過一個char(1個字節)
?總結:
指針類型的意義:
概念: 野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
請看如下代碼:
int main(){ int* p; *p = 8;}
分析:
這段代碼里面的p就是野指針,因為p是一個局部變量,指針變量,未主動初始化,那么它里面就是隨機值(隨機地址),就是說這個地址是不清楚的,然后后面又對它進行解引用,將8存放到這塊不明確的地址里面,這就是又問題的
運行結果:
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* pa = arr; int i = 0; for (i = 0; i <= 10; i++) { *pa = 1; pa++; } return 0;}
分析:
這里的數組長度為10,但明顯可以看到循環執行了11次,pa最后所指向的已經不是數組里面的內存單元,越界訪問了
可以來看看內存
這是在數組初始化之后數組中的內容
?
?在執行完11次循環之后
?此時會發現指針pa最后一次循環時越界,并且將數組arr后面的一個內存單元里面的內容改成了1,但是要知道這塊內存并不屬于該程序(這就是非法的)
如下代碼
int* app(){ int b = 3; return &b;}int main(){ int* ps = app(); return 0;}
分析:
這段代碼中,app這個函數返回了臨時變量b的地址,ps這個指針也接受到了b的地址,但是要知道在這個函數調用完之后所創建的b這塊內存空間就已經銷毀了(或者說還給操作系統了),那么ps再記住這塊空間的地址就沒有意義了(保存了一個非法的地址)
示例:(通過指針打印數組元素)
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* pa = arr; int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(pa + i)); } return 0;}
運行結果:
示例:
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%d/n", &arr[9] - &arr[0]); return 0;}
請問這段代碼的運行結果是什么呢?? 是36?
需要知道的是 指針-指針:得到的是兩個指針之間元素的個數(前提:兩個指針指向同一塊空間)
運行結果:
代碼1:
#include int main(){ int arr[5] = { 1,2,3,4,5 }; int* ps = &arr; for (ps = &arr[5]; ps > &arr[0];) { *--ps = 0; } return 0;}
這段代碼將數組中的元素改成了0
代碼2:
#include int main(){ int arr[5] = { 1,2,3,4,5 }; int* ps = &arr; for (ps = &arr[4]; ps >= &arr[0];ps--) { *ps = 0; } return 0;}
代碼2與代碼1相比更容易理解,但是要知道這樣寫是很大有問題的,C標準并不保證它可行
標準規定:?
允許指向數組元素的指針與指向數組最后一個元素后面的那個內存位置的指針比較,但是不允許
與指向第一個元素之前的那個內存位置的指針進行比較
再來啰嗦一下
1.數組名表示首元素地址
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%p/n", &arr[0]); printf("%p/n", arr); return 0;}
可以看到這種方式打印出來的結果是一樣的
?數組名表示數組首元素的地址在絕大多數情況下都成立
兩個例外:
可以通過指針來訪問數組
#include int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* pa = arr; int i = 0; for (i = 0; i < 10; i++) { printf("%d ", *(pa + i)); } return 0;}
?我們都知道指針是用來存地址的,指針也是在內存中開辟了一塊空間然后將地址存儲在里面,所以指針本身也是有自己的地址的
那我們就可以取出指針的地址來進行存放
int main(){ int a = 8; int* ps = &a; //ps稱為一級指針 int** pps = &ps; //pps稱為二級指針 用來 存儲一級指針的地址}
存儲地址就是為了后面能用得到的
現在對它進行解引用操作
#include int main(){ int a = 8; int b = 55; int* ps = &a; //ps稱為一級指針 int** pps = &ps; //pps稱為二級指針 用來 存儲一級指針的地址 *pps = &b; **pps = 666; printf("%d/n", b); printf("%d/n", **pps);}
*pps?通過對ppa中的地址進行解引用,這樣找到的是ps,*pps?其實訪問的就是ps
**pps?先通過*pps?找到ps?,然后對ps?進行解引用操作
運行結果:
我們前面用過的整型數組拿來存放整型,字符數組里面存放字符,那么現在里面存放指針的數組就叫做指針數組
現在先簡單說下,后面在指針進階階段還會再詳細說明
通過以下代碼來體驗一下
#include int main(){ int a = 0; int b = 1; int c = 2; int* arr[3] = { &a,&b,&c }; int i = 0; for (i = 0; i < 3; i++) { printf("%d ", *arr[i]); }}
這里是創建了一個整型指針數組,并對它進行了初始化,里面存放有a,b,c的地址,再通過解引用去打印出a,b,c
運行結果:
?如下圖:
?
?這個數組里面每個元素都是一個整型指針
-----------------------------------------------------------------
-----------------C語言操作符部分完結-------------------
關于C語言,每個知識點后面都會多帶帶寫博客更加詳細的介紹
歡迎大家關注?。?!
一起學習交流 ?。?!
讓我們將編程進行到底?。?!
--------------整理不易,請三連支持------------------
?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/120817.html
目錄 一、什么是C語言? 二、第一個C語言程序 代碼 程序分析 ?程序運行 一個工程中出現兩個及以上的main函數 代碼 運行結果 分析 三、數據類型 數據各種類型 為什么會有這么多的數據類型? 計算機單位 ?各個數據類型的大小 ?注意事項 數據類型的使用 四、變量和常量 變量的分類 變量的使用 變量的作用域和生命周期 ?常量 五、字符串+轉義字符+注釋 字符串 ?轉義字符 注釋 六、選擇語句 ?...
摘要:指針的大小在位平臺是個字節,在位平臺是個字節。比如的指針解引用就只能訪問一個字節,而的指針的解引用就能訪問四個字節。所以是一個指針,指向一個數組,叫數組指針。 準備...
摘要:我們平時說指針,也可以指指針變量。是指針變量這段表達式的意思是定義了一個指針變量,里面存放的是的地址。叫做指針類型就叫做指針變量指針類型又是什么既然變量有不同的類型,比如整型,浮點型等。 ...
閱讀 1413·2021-09-23 11:21
閱讀 3111·2019-08-30 14:14
閱讀 3195·2019-08-30 13:56
閱讀 4144·2019-08-30 11:20
閱讀 1956·2019-08-29 17:23
閱讀 2768·2019-08-29 16:14
閱讀 1699·2019-08-28 18:18
閱讀 1495·2019-08-26 12:14