真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

指針其實(shí)也沒(méi)有那么難

指針其實(shí)也沒(méi)有那么難 — 初級(jí)指針

本章內(nèi)容是指針的內(nèi)容,有哪些地方寫的不好還請(qǐng)多多指點(diǎn)。????

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到天峨網(wǎng)站設(shè)計(jì)與天峨網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋天峨地區(qū)。

首先說(shuō)一下指針的初級(jí)知識(shí)點(diǎn)什么是指針。


指針是什么?

按傳統(tǒng)的方式來(lái)講:

在計(jì)算機(jī)科學(xué)中,指針(Pointer)是編程語(yǔ)言中的一個(gè)對(duì)象,利用地址,它的值直接指向
(points to)存在電腦存儲(chǔ)器中另一個(gè)地方的值。由于通過(guò)地址能找到所需的變量單元,可以
說(shuō),地址指向該變量單元。因此,將地址形象化的稱為“指針”。意思是通過(guò)它能找到以它為地址
內(nèi)存單元。

內(nèi)存單元是什么呢?就好比現(xiàn)實(shí)生活中我們的房間,不就是哪個(gè)單元哪個(gè)房間號(hào)嘛。

我們用畫圖的形式來(lái)展示。

指針

指針是個(gè)變量,存放內(nèi)存單元的地址(編號(hào))。

用代碼方式表示:

#include 
int main()
{
    int i = 9;//向內(nèi)存申請(qǐng)一塊空間
    int* p = &i;//&i 取出i的地址 放到p變量中  而p就是一個(gè)指針變量 它指向的是i變量所在的地址
    return 0;
}

簡(jiǎn)單的來(lái)說(shuō): 指針就是個(gè)變量,這個(gè)變量是用來(lái)存放地址的。(存放到指針變量中的值都將被當(dāng)作地址處理)。

比如說(shuō): int* p = 12;

數(shù)據(jù)在內(nèi)存中都是地址的形式存放的,而在內(nèi)存中地址是以4位16進(jìn)制和8位16進(jìn)制表示的,而12的16進(jìn)制不就是字母C嗎。

上面一行代碼解釋為:定義一個(gè)整型指針變量,把12這個(gè)值當(dāng)作地址賦值給變量p。%p以地址的形式打印所以是 --> 0000000C。

  • 一個(gè)小的單元到底是多大?(1個(gè)字節(jié))

對(duì)于32位機(jī)器來(lái)說(shuō),我們假設(shè)有32根地址線,每根地址線在尋找地址的時(shí)候產(chǎn)生一個(gè)電信號(hào)正電或者負(fù)電(1/0)

那么32根地址線產(chǎn)生的地址是:

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

00000000 00000000 00000000 00000010

......

2的32次方個(gè)地址。

每個(gè)地址標(biāo)識(shí)一個(gè)字節(jié),那么就可以給(2^32Byte == 2^32/1024KB == 2^32/1024/1024MB == 2^32/1024/1024/1024GB == 4GB)

4GB的空閑編址。同樣的方法放到64位機(jī)器上,編址有TB,是這么多嗎

。

這里我們就明白了:

  • 在32位機(jī)器上,地址是32個(gè)0或者1組成的二進(jìn)制序列,那地址就應(yīng)該用4個(gè)字節(jié)的空間來(lái)存儲(chǔ),所以一個(gè)指針變量大小就是4個(gè)字節(jié)
  • 換做64位機(jī)器上,那地址就應(yīng)該用8個(gè)字節(jié)來(lái)存儲(chǔ),指針變量大小就是8個(gè)字節(jié)。

由此我們得出結(jié)論:

  • 指針是用來(lái)存放地址的,地址是唯一標(biāo)示一塊地址空間的。
  • 指針的大小在32位平臺(tái)上是4個(gè)字節(jié),在64位平臺(tái)上是8個(gè)字節(jié)。

指針和指針類型

在此之前我們學(xué)過(guò)基本類型有:整型、字符型、浮點(diǎn)型等。既然指針也是變量,那指針是不是也會(huì)有不同的類型呢?答案是肯定的!

指針也是變量,所以也會(huì)有該對(duì)應(yīng)的指針類型。下面舉幾個(gè)例子:

#include 
int main()
{
    int a = 10;//整型
    char b = 'w';//字符型
    float c = 3.14;//單精度浮點(diǎn)型
    double d = 123.789;//雙精度浮點(diǎn)型
    
    int* pa = &a;//整形指針
    char* pb = &b;//字符指針
    float* pc = &c;//浮點(diǎn)型指針
    double* pd = &d;//浮點(diǎn)型指針
    return 0;
}

以上代碼就列舉了部分指針類型。

下面我們來(lái)看一段代碼

sizeof()是計(jì)算數(shù)據(jù)大小的操作符,單位是字節(jié),可以看到不管是什么類型的指針都是4個(gè)字節(jié)。誒~既然大小都是4個(gè)字節(jié),那我們定義不同類型的指針又有什么意義呢?那我們何不造一個(gè)通用類型的指針呢?當(dāng)然不行呢。你看我們每個(gè)人每天都要吃飯,雖然說(shuō)有不同的方式可以讓自己吃飽,但是為什么要這么多不同的食品讓我們填飽肚子呢?直接造一種可以讓人吃飽的食品不就好了。這個(gè)時(shí)候大家又知道了不同的食品有不同的作用,有些要補(bǔ)維生素A呀或者是維生素B呀等等。同樣的指針類型也會(huì)有它不同的意義呀!

下面我們繼續(xù)看段代碼

我們看到內(nèi)存上,a的地址,后面是變量a的數(shù)據(jù)存儲(chǔ)方式 -->小端存儲(chǔ)方式。當(dāng)我們把a(bǔ)的地址存放到變量pa中,我們通過(guò)地址去改變a的值,請(qǐng)看下面

右下角我們看到pa變量的值變成了a的地址,而且a的值也被改成了20。好這個(gè)看不出什么,下面我們看另外一段代碼

跟上面一樣,我只是改變了指針的類型,改變指針類型后我們看到*pa=20執(zhí)行之后,為什么右上角的值變成了 14 46 13 00呢?

通過(guò)觀察,指針類型不同,操作的字節(jié)數(shù)就不同,可以看到int* 指針改變的是4個(gè)字節(jié),而char* 指針改變的是1個(gè)字節(jié)。

由此我們得出結(jié)論:

指針類型決定了,對(duì)指針解引用的時(shí)候有多大權(quán)限(能操作幾個(gè)字符)。比如說(shuō):char* 的指針解引用就只能訪問(wèn)一個(gè)字節(jié),而int*的指針解引用能訪問(wèn)4個(gè)字節(jié)。

指針類型意義1:

指針類型決定了指針解引用時(shí),能訪問(wèn)的空間大小。

我們繼續(xù)看下面一段代碼的運(yùn)行結(jié)果:

可以看到int類型指針p的地址與p+1的地址之間差了4 而char類型指針pc和pc+1的地址之間差了1。雖然說(shuō)是以數(shù)組來(lái)舉例子,不過(guò)就算不用數(shù)組舉例也是一樣的。

指針類型意義2:

指針類型決定了指針+1或者-1有多大距離(指針的步長(zhǎng))。也就是字節(jié)

這有啥用呢?

可以知道我們創(chuàng)建了一個(gè)整型數(shù)組,這個(gè)數(shù)組有10個(gè)元素全部初始化成0了。數(shù)組名代表數(shù)組首元素的地址,把數(shù)組首元素的地址傳給變量p通過(guò)循環(huán)給數(shù)組賦值。

結(jié)果很明顯,通過(guò)指針+整數(shù)訪問(wèn)數(shù)組的元素,然后再給數(shù)組元素賦值。那么我們把指針類型改一下呢會(huì)出現(xiàn)什么效果?

它改變的是什么?搜嘎斯內(nèi),它只改變了整型數(shù)據(jù)中一個(gè)字節(jié)的內(nèi)容。這是一個(gè)字節(jié)一個(gè)字節(jié)的訪問(wèn),沒(méi)改變指針類型之前呢,沒(méi)改變之前是4個(gè)字節(jié)4個(gè)字節(jié)的訪問(wèn)所以啊。

  1. 希望一個(gè)字節(jié)一個(gè)字節(jié)訪問(wèn) 可以用char類型的指針
  2. 一個(gè)整型一個(gè)整型訪問(wèn) 可以用int類型的指針

以此類推,想怎樣訪問(wèn)就用什么樣類型的指針。

總結(jié)一下指針類型的作用

  1. 指針類型決定了指針解引用(訪問(wèn)字節(jié))的權(quán)限有多大。
  2. 指針類型決定了指針向前走或者向后走有多大(距離,步長(zhǎng))。

野指針

野指針,大家看到會(huì)想起啥?野狗?野貓?它們都是沒(méi)得家的沒(méi)得主人,到處流浪。那么野指針是啥?

先按傳統(tǒng)的說(shuō)法:

野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒(méi)有明確限制的)

那為什么會(huì)產(chǎn)生野指針這玩意兒呢?

接下來(lái)我們看看野指針形成的原因。

野指針成因

1.指針未初始化

 #include 
 int main()
 {
     int* p ;//定義一個(gè)局部的指針變量,局部變量不初始化的話,默認(rèn)是隨機(jī)值
     *p = 10;//*p是對(duì)指針的解引用操作,這里非法訪問(wèn)內(nèi)存
 	//使用了未初始化的局部變量p
 	//使用未初始化的內(nèi)存p
     return 0;
 }

2.指針越界訪問(wèn)

 int main()
 {
 	int arr[10] = { 0 };
 	int* p = arr;
 	int i = 0;
 	for (i = 0; i <= 10; i++)
 	{
 		//當(dāng)指針指向的范圍超出數(shù)組arr的范圍時(shí),p就是野指針
 		*p = i;
 		p++;
 	}
 	return 0;
 }

3.指針指向的空間釋放

int* work()
{
	int a = 20;//函數(shù)調(diào)用后變量a銷毀了
	return &a;//所以此時(shí)a的地址雖然說(shuō)還是那地址,但是指向的那塊空間已經(jīng)還給了操作系統(tǒng)
}
int main()
{
	int* p = work();
    //對(duì)p指針的解引用 去訪問(wèn)一個(gè)已經(jīng)還給操作系統(tǒng)的空間 那片空間說(shuō)不定操作系統(tǒng)已經(jīng)存放其他內(nèi)容 而且這也是屬于非法訪問(wèn)內(nèi)存
	*p = 30;
	return 0;
}

說(shuō)了這么多的野指針成因,那我們應(yīng)該怎樣有效的避免野指針的產(chǎn)生呢?

  1. 初始化指針
  2. 小心指針越界
  3. 指針指向空間釋放即使置NULL
  4. 指針使用之前檢查有效性 可用assert斷言
#include 
int main()
{
    //當(dāng)不知道p應(yīng)該初始化為什么地址的時(shí)候,可以初始化NULL
    int* p = NULL;//初始化指針
    return 0;
}

指針運(yùn)算

指針運(yùn)算有3種形式:

  • 指針±整數(shù)
  • 指針-指針
  • 指針的關(guān)系運(yùn)算

指針±整數(shù)

int main()
{
	int arr[10] = { 20,21,22,23,24,25,26,27,28,29 };
	int* p = arr;
	int* end = arr + 9;
	while (p <= end)
	{
		printf("%d\n", *p);
		p++;//指針+整數(shù)    p+=1;
	}
	return 0;
}

可以知曉,指針+整數(shù) 在整型數(shù)組中訪問(wèn)下一個(gè)元素,既然可以+那肯定也能-

指針-整數(shù)

指針-指針

指針-指針,聯(lián)系之前學(xué)過(guò)的內(nèi)容,指針不就是地址嘛,那指針-指針 不就是 地址 - 地址。指針+指針沒(méi)啥意義,就和日期一樣,日期+日期有啥用嘛?日期-日期可以,日期+天數(shù)也可以。但是日期加日期就沒(méi)啥意義了。

#include 
int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int* p = arr;
    int* end = arr + 9;
    printf("%d\n", end - p);
    return 0;
}

代碼運(yùn)行如下:

運(yùn)行結(jié)果是9,我們發(fā)現(xiàn)從arr[0]到arr[9]之間剛好就是9個(gè)元素。

試試arr - (arr +9)這不是-9嘛看看代碼運(yùn)行效果:

結(jié)果也是-9,雖然數(shù)字是相同了,但是符號(hào)卻不相同,而數(shù)組中是隨著數(shù)組下標(biāo)的增長(zhǎng)地址是由低到高的。內(nèi)存中地址也是由低到高。

因此我們?nèi)缫枰玫皆氐膫€(gè)數(shù),應(yīng)該用高地址- 低地址。

注意事項(xiàng):

指針-指針的前提是:兩個(gè)指針指向的是通一塊空間

給大家來(lái)個(gè)實(shí)際點(diǎn)的:

#include 
//函數(shù)遞歸方法
int me_strlen(char*str)
{
    if(*str != '\0')
        return 1 + me_strlen(str + 1);
    else
        return 0;
}
int me_strlen(char* str)
{
    char* p = str;//p指針指向 str 變量   str 指向的是 字符串首字符的地址
    while(p != '\0')//字符串長(zhǎng)度是找'\0'
    {
        p++;
    }
    return p - str;//指針-指針 就是中間元素個(gè)數(shù) 
}
int main()
{
    char arr[] = "hello world";
    int ret = me_strlen(arr);//傳字符串首字符的地址
    return 0;
}

指針關(guān)系的運(yùn)算

指針關(guān)系運(yùn)算,我們知道關(guān)系運(yùn)算是啥,關(guān)系運(yùn)算不就是 > < >= <= != ==

用代碼舉個(gè)例子吧:

#include 
int main()
{
    int arr[5];
    int *p;
    for( p = &arr[5]; p > arr[0])
    {
        *--p = 0;
    }
    return 0;
}

這個(gè)代碼不太標(biāo)準(zhǔn),看著有點(diǎn)難受。修改一下

#include 
int main()
{
    int arr[5];
    int *p;
    for( p = &arr[4]; p > arr[0]; p--)
    {
        *p = 0;
    }
    return 0;
}

這個(gè)代碼是什么意思呢?咱們畫圖理解一下

該代碼的意思是:取出arr數(shù)組后面一個(gè)元素的地址,判斷該地址是否大于數(shù)組首元素的地址,如果大于那就把p變量所指向的內(nèi)容改為0,然后在自減,也就是往arr[0]那邊走,再以同樣的方式賦值,直到p的地址要小于或者是等于arr[0]循環(huán)就結(jié)束。

但是請(qǐng)注意:

允許指向數(shù)組元素的指針與指向數(shù)組最后一個(gè)元素后面的那個(gè)內(nèi)存位置的指針比較,但是不允許與指向第一個(gè)元素之前的那個(gè)內(nèi)存位置的指針進(jìn)行比較。

如果還不明白請(qǐng)自己畫圖理解一下。

指針和數(shù)組

指針和數(shù)組的關(guān)系:指針是地址嘛,而數(shù)組名是數(shù)組首元素地址。 我們舉個(gè)例子

有圖有真相(doge),可以看到arr和&arr[0]的地址是一樣的,所以說(shuō),數(shù)組名就是數(shù)組首元素地址。

#include 
int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int* p = arr;//p存放的就是數(shù)組首元素地址
    return 0;
}

但是數(shù)組名就一定是數(shù)組首元素地址嗎?NONONO。也有例外啦!請(qǐng)記住下面2點(diǎn)

  1. sizeof(數(shù)組名) --> 只有數(shù)組名沒(méi)有其他操作符 數(shù)組名表示整個(gè)數(shù)組,計(jì)算的是整個(gè)數(shù)組的大小,單位是字節(jié)。
  2. &數(shù)組名 -- > 取出的是整個(gè)數(shù)組的地址 數(shù)組名表示整個(gè)數(shù)組

其他情況下,數(shù)組名就是首元素地址。

首元素的地址和數(shù)組的地址有啥區(qū)別呢?

靠,這不一樣嘛(手動(dòng)狗頭)?雀食哈,這打印出來(lái)都一樣,但是意義卻截然不同呢,不信再舉個(gè)例子:

看到區(qū)別沒(méi),arr是數(shù)組名,代表首元素地址,+1 因?yàn)閿?shù)組類型是int 而int類型指針+1 不就是跳過(guò)4個(gè)字節(jié) 剛好差4。

而&arr,arr代表整個(gè)數(shù)組,+1 跳過(guò)了一個(gè)數(shù)組,兩個(gè)地址之間差 40個(gè)字節(jié)。

既然可以把數(shù)組名當(dāng)成地址存放到一個(gè)指針中,我們可以使用指針來(lái)一個(gè)個(gè)的訪問(wèn)。

#include 
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%p <==> %p\n", &arr[i], p + i);
		*(p + i) = i;
	}
	return 0;
}

效果:

所以 p+i 其實(shí)計(jì)算的是數(shù)組 arr 下標(biāo)為i的地址 。

那我們就可以直接通過(guò)指針來(lái)訪問(wèn)數(shù)組 。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;//數(shù)組名
    int sz = sizeof(arr)/sizeof(arr[0]);
    int i = 0;
    for(i=0;i *(p+2)
	//arr[2] --> *(arr+2) --> *(2+arr) --> 2[arr]
	//arr[2]<==> *(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr) == 2[arr]
	//2[arr] <==> *(2+arr)
	return 0;
} 

二級(jí)指針

二級(jí)指針,有沒(méi)有覺(jué)得好高級(jí)。之前了解到指針本質(zhì)上還是變量嘛,只是用來(lái)存放地址的變量而已。既然是變量那它是不是也會(huì)有地址?

那當(dāng)然,那么存放指針變量的地址就叫二級(jí)指針咯。畫圖舉個(gè)例子就知道了:

這樣是不是好理解一些。

#include 
int main()
{
    int a= 1;
    int* p = &a;//p是指針變量,一級(jí)指針
    int** pa = &p;//pa也是指針變量,二級(jí)指針
    return 0;
}

說(shuō)完了什么是二級(jí)指針,那二級(jí)指針如何使用呢?其實(shí)和一級(jí)指針的使用是類似的。

  • *pa 通過(guò)對(duì)pa的地址解引用,找到p, *pa其實(shí)訪問(wèn)的就是p。

    int b = 1;
    *pa = &a;//等價(jià)于 p = &a;
    
  • **pa先通過(guò) *pa找到p,然后對(duì)p進(jìn)行解引用操作: *p,找到a

    **pa = 30;
    //等價(jià)于*pa = 30;
    //等價(jià)于a = 30;
    

指針數(shù)組

我們學(xué)過(guò)整型數(shù)組、字符型數(shù)組。那么指針有沒(méi)有數(shù)組呢?

答案肯定是有的。還記得數(shù)組的定義是什么嗎?數(shù)組是一組相同類型元素的集合。那么一組相同類型的指針?lè)旁谝黄疬@算不算是數(shù)組呢?

這肯定是數(shù)組,因?yàn)樗鼭M足數(shù)組的定義。那么指針數(shù)組又是怎么樣的呢?

首先指針數(shù)組的定義:一組相同類型的指針的集合。

int arr[10];//這是整型數(shù)組,數(shù)組有10個(gè)元素,數(shù)組中每個(gè)元素都是整型。

char arry[5];//這是字符型數(shù)組,數(shù)組有5個(gè)元素,數(shù)組中每個(gè)元素都是字符型。

#include 
int main()
{
    int a = 1;
    int b = 2;
    int c = 3;
    int* pa = &a;
    int* pb = &b;
    int* pc = &c;
    return 0;
}

這段代碼中,a、b、c均為整型變量,pa、pb、pc均為整形指針。3個(gè)整型變量用3個(gè)整型指針來(lái)接收豈不是浪費(fèi)空間了?那我們干脆把這3個(gè)整型指針?lè)旁谝黄鸾M成一個(gè)整型指針數(shù)組不就好了嘛,誒指針數(shù)組這不就出來(lái)了嘛。

首先定義一個(gè)數(shù)組 int arr[10]; 既然每個(gè)類型都是指針,那么把數(shù)組的類型改一下不就好了嘛。 int* arr[10]; 這時(shí)我們就說(shuō)這個(gè)數(shù)組是指針數(shù)組嘛,這是一個(gè)整型指針數(shù)組,該數(shù)組有10個(gè)元素且每一個(gè)元素都是整型指針。那么我們畫圖展示一下:

用代碼的形式:

int main()
{
	int arr[10];//整形數(shù)組 - 存放整形的數(shù)組就是整形數(shù)組
	char ch[5];//字符數(shù)組 - 存放的是字符
	//指針數(shù)組 - 存放指針的數(shù)組
	int* parr[5];//整形指針的數(shù)組
	char* pch[5];//字符型指針數(shù)組
	return 0;
}

想必大家看了這幾幅圖和代碼,對(duì)指針數(shù)組應(yīng)該有大概的了解了吧。


感謝大家的收看,以上都是鄙人學(xué)習(xí)的個(gè)人理解如果有哪些地方說(shuō)錯(cuò)了或者是沒(méi)有講明白,還請(qǐng)大家多多指點(diǎn)指點(diǎn)。謝謝大家!?。?/p>

這部分是鄙人對(duì)指針的初步了解后面進(jìn)階的會(huì)在【指針其實(shí)也沒(méi)有那么難—進(jìn)階指針】這篇中講解。


本文標(biāo)題:指針其實(shí)也沒(méi)有那么難
當(dāng)前鏈接:http://weahome.cn/article/dsoipcc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部