摘要:一指針概述指針是個變量存放內(nèi)存單元的地址編號。即存放指針變量的地址的指針二級指針指向的空間的值是一個一級指針??偨Y(jié)指針是語言非常重要的一部分內(nèi)容繁多不易懂本文僅介紹了一些基本知識后續(xù)還會深入了解指針。
指針是個變量,存放內(nèi)存單元的地址(編號)。
在定義指針變量的時候,在變量前面加上’ * ',代表這個變量是一個指針,再往前面加上一個類型名,就代表指針的類型,稱為XX指針。
指針的初始化:
#include int main(){ int a = 10;//在內(nèi)存中開辟一塊空間 int *p = &a;//這里我們對變量a,取出它的地址,可以使用&操作符。 //將a的地址存放在p變量中,p就是一個指針變量。 return 0;}
指針可以是不同的類型,char*、int*、float*、double*、long*等我們熟知的類型,那指針在內(nèi)存中占多大的空間呢?
對于32位的機器,假設(shè)有32根地址線,那么假設(shè)每根地址線在尋址的是產(chǎn)生一個電信號正電/負電(1或者0)
那么32根地址線產(chǎn)生的地址就會是:
00000000 00000000 00000000 00000000
……
111111111 111111111 111111111 111111111
共有232個地址,每一個地址能指向一個內(nèi)存單元(一字節(jié)),那么有232個內(nèi)存單元。
我們知道一個內(nèi)存單元的大小為一字節(jié),一根地址線是32位01組成的,那么要存放指針(地址),也就需要32個bit,也即4字節(jié)。所以在32位平臺下不論是什么類型的指針都是4個字節(jié)。
同理,在64位平臺下有64根地址線,每個地址是64位,所以需要8個字節(jié)。
使用’ * '操作符對指針進行解引用,可以獲取到指針指向空間的值
我們來運行下方代碼。
#include int main(){ int n = 0x11223344; char* pc = (char*)&n;//將n的地址(指針)強制轉(zhuǎn)換成char* 類型 int* pi = &n; *pc = 0;//改變它指向空間的值 *pi = 0; return 0;}
我們開始調(diào)試代碼,查看n的內(nèi)存,最左邊是地址,右邊是以16進制顯示內(nèi)存里存放的數(shù)據(jù),而n也是以16進制存進去的,兩個16進制代表一個字節(jié),如下圖:
當(dāng)執(zhí)行完語句 *pc=0;
因為pc指向的是char* 類型,只能訪問一個字節(jié),所以只能修改一個字節(jié)。
再執(zhí)行*pi = 0;
此時n的內(nèi)存數(shù)據(jù)全部變成了0,說明int*類型的指針可以訪問4個字節(jié)。
總結(jié):
指針的類型決定了,對指針解引用的時候有多大的權(quán)限(能操作幾個節(jié))。 比如: char* 的指針解引用就只能訪問一個字節(jié),而 int* 的指針的解引用就能訪問四個字節(jié)。
指針變量也是變量,是變量就有地址,那指針變量的地址存放在哪里? 這就是 二級指針 。
即存放指針變量的地址的指針,二級指針指向的空間的值是一個一級指針。
int main(){ int a = 20; int* p = &a; int** pp = &p; printf("%d/n", *p);//解引用即可拿到指針指向空間里面的值 printf("%d/n", *p); //對二級指針,需要兩次解引用才能拿到最開始的值 return 0;}
野指針就是指針指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)。
#include int main(){ int *p;//局部變量指針未初始化,默認為隨機值 *p = 20;//往一個隨機的地址(不屬于本程序的空間)里面放入數(shù)據(jù),是不允許的 return 0;}
#include int main(){ int arr[10] = {0}; int *p = arr; int i = 0; for(i=0; i<=11; i++) { //當(dāng)指針指向的范圍超出數(shù)組arr的范圍時,p就是野指針 *(p++) = i; } return 0;}
int main(){ //開辟一個整形空間 int* p = (int*)malloc(sizeof(int)); //釋放該空間 free(p); //此時p即為野指針,因為它指向的空間已經(jīng)無法訪問,一般需要將其置空 //將其指向空指針,防止后續(xù)調(diào)用出錯 p = NULL; return 0;}
關(guān)于指針的運算一般有兩個,指針+指針,語義是合法,但沒有意義。
對int和char類型的指針分別進行+1操作,%p以16進制打印
int main(){ int n = 10; char* pc = (char*)&n;//將n的地址(指針)強制轉(zhuǎn)換成char* 類型 int* pi = &n; printf("&n: %p/n", &n); printf("pc: %p/n", pc); printf("pc + 1:%p/n", pc + 1); printf("pi: %p/n", pi); printf("pi + 1:%p/n", pi + 1); return 0;}
總結(jié):
指針的類型決定了指針向前或者向后走一步有多大(距離)。
int main(){ int arr[10] = { 0 }; //取出數(shù)組第一個元素和最后一個元素的地址 int* start = arr; int* end = &arr[9]; printf("%d/n", end - start); return 0;}
總結(jié):
指針-指針等于它們之間相差的類型數(shù)據(jù)的個數(shù)。即本例的第10個元素和第1個元素之間相差9。
一起來看一下數(shù)組名是什么
#include 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;}
可見數(shù)組名和數(shù)組首元素的地址是一樣的。
結(jié)論: 數(shù)組名表示的是數(shù)組首元素的地址。也是一個指針
那么我們就可以用一個指針來代替數(shù)組名,如下代碼:
int main(){ int arr[10] = { 0 }; int* p = arr; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]);//計算數(shù)組元素個數(shù) //對數(shù)組賦值 for (i = 0; i < sz; i++) { *(p + i) = i; } //打印數(shù)組數(shù)據(jù) for (i = 0; i < sz; i++) { printf("%d ", *(p + i)); } return 0;}
注意:
數(shù)組名在下面兩種情況下不是首元素的地址
int main(){ int arr[10] = { 0 }; int sz = sizeof(arr); printf("sizeof(arr)計算的是整個數(shù)組的大小:%d/n", sz); printf("數(shù)組首地址: %p/n", arr); printf("數(shù)組首元素地址: %p/n", &arr[0]); printf("數(shù)組的地址: %p/n", &arr); printf("數(shù)組首地址+1: %p/n", arr + 1); printf("數(shù)組首元素地址+1:%p/n", &arr[0] + 1); printf("數(shù)組的地址+1: %p/n", &arr + 1); //數(shù)組名確實是首元素的地址 //但是有2個例外: //1. sizeof(數(shù)組名) - 這里的數(shù)組名不是首元素的地址,是表示整個數(shù)組的,這里計算的是整個數(shù)組的大小,單位還是字節(jié) //2. &數(shù)組名 - 這里的數(shù)組名不是首元素的地址,是表示整個數(shù)組的,拿到的是整個數(shù)組的地址 // return 0;}
存放指針的數(shù)組。
int main(){ int a = 1; int b = 2; int c = 3; int* arr[10] = { &a,&b,&c }; for (int i = 0; i < 3 ; i++) { printf("%d ", *(arr[i])); } return 0;}
希望能對大家學(xué)習(xí)指針有所幫助!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/121276.html
摘要:因為所有的數(shù)據(jù)從最底層講是字節(jié),那么就可以使用字節(jié)流這個概念去指代數(shù)據(jù)動態(tài)轉(zhuǎn)移這個過程。而數(shù)據(jù)的轉(zhuǎn)移,就是把一堆字節(jié)流從運往。創(chuàng)建內(nèi)存中的中轉(zhuǎn)區(qū)域,然后將上面的文件的字節(jié)流直接接入到這個。然后再從把字節(jié)流輸出到對應(yīng)的。 I/O的很多操作和使用,其實并不是一個非常直觀的概念,特別是打開文件、創(chuàng)建buffer。這對于終端用戶來講是個非常奇葩和奇怪的過程。我只是想要從一個文件里讀取內(nèi)容,從過...
摘要:作為十幾年的老開發(fā)者,今天我來分享一下,我個人認為的大學(xué)計算機相關(guān)專業(yè)該怎么學(xué),希望你們的四年能夠不負年華。粉絲專屬福利九關(guān)于考研有能力去考研的,我建議去嘗試一下考研,理由有以下幾點第一,畢業(yè)就工作的人,前三年還處于摸索和定性的階段。 ...
摘要:大家好,我是冰河有句話叫做投資啥都不如投資自己的回報率高。馬上就十一國慶假期了,給小伙伴們分享下,從小白程序員到大廠高級技術(shù)專家我看過哪些技術(shù)類書籍。 大家好,我是...
摘要:進入當(dāng)前程序的學(xué)習(xí)系統(tǒng)的所有樣本稱作輸入,并組成輸入空間。結(jié)束語注意這篇文章僅僅是我接下來的機器學(xué)習(xí)系列的第一篇,后續(xù)還會有更多的內(nèi)容。 往期回顧:統(tǒng)計學(xué)習(xí)方法第...
閱讀 943·2023-04-25 19:43
閱讀 4238·2021-11-30 14:52
閱讀 4023·2021-11-30 14:52
閱讀 4132·2021-11-29 11:00
閱讀 4023·2021-11-29 11:00
閱讀 4153·2021-11-29 11:00
閱讀 3871·2021-11-29 11:00
閱讀 6759·2021-11-29 11:00