??個人主頁:fighting小澤
??作者簡介:目前正在學(xué)習(xí)C語言和數(shù)據(jù)結(jié)構(gòu)
??博客專欄:C語言學(xué)習(xí)
???歡迎關(guān)注:評論????點(diǎn)贊????留言????
1. 指針是什么?
指針是什么?
指針理解的2個要點(diǎn):
- 指針是內(nèi)存中一個最小單元的編號,也就是地址
- 平時口語中說的指針,通常指的是指針變量,是用來存放內(nèi)存地址的變量
我們可以把內(nèi)存想象成一座酒店,酒店的每個房間都有它的編號(地址),我們可以通過編號來找到房間,同樣我們也可以通過地址找到內(nèi)存。
總結(jié):指針就是地址,口語中說的指針通常指的是指針變量。
那我們就可以這樣理解:
1.內(nèi)存分為一個個內(nèi)存單元,這個內(nèi)存單元的大小是一個字節(jié)
2.每個字節(jié)都給一個唯一的編號,這個編號我們稱為地址,地址再C語言中也叫指針。
編號 == 地址 == 指針
指針變量
我們可以通過&(取地址操作符)取出變量的內(nèi)存其實(shí)地址,把地址可以存放到一個變量中,這個變量就是指針變量
#include <stdio.h>
int main()
{
int a = 10;//在內(nèi)存中開辟一塊空間
int *p = &a;//這里我們對變量a,取出它的地址,可以使用&操作符。
a變量占用4個字節(jié)的空間,這里是將a的4個字節(jié)的第一個字節(jié)的地址
存放在p變量中,p就是一個之指針變量。
return 0;
}
總結(jié):
指針變量,用來存放地址的變量。(存放在指針中的值都被當(dāng)成地址處理)。在錘子的眼里,什么都是釘子,見了誰都想敲敲。
那這里的問題是:
一個小的單元到底是多大?(1個字節(jié))
如何編址?
經(jīng)過仔細(xì)的計算和權(quán)衡我們發(fā)現(xiàn)一個字節(jié)給一個對應(yīng)的地址是比較合適的。
對于32位的機(jī)器,假設(shè)有32根地址線,那么假設(shè)每根地址線在尋址的時候產(chǎn)生高電平(高電壓)和低電平(低電壓)就是(1或者0);
那么32根地址線產(chǎn)生的地址就會是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
…
11111111 11111111 11111111 11111111
這里就有2的32次方個地址。
每個地址標(biāo)識一個字節(jié),那我們就可以給 (2^32Byte == 2^32/1024KB == 2^32/1024/1024MB == 2^32/1024/1024/1024GB == 4GB) 4G的空間進(jìn)行編址。
同樣的方法,那64位機(jī)器,如果給64根地址線,那能編址多大空間,自己計算。
這里我們就明白:
- 在32位的機(jī)器上,地址是32個0或者1組成二進(jìn)制序列,那地址就得用4個字節(jié)的空間來存儲,所以一個指針變量的大小就應(yīng)該是4個字節(jié)。
- 那如果在64位機(jī)器上,如果有64個地址線,那一個指針變量的大小是8個字節(jié),才能存放一個地址。
總結(jié):
- 指針變量是用來存放地址的,地址是唯一標(biāo)示一個內(nèi)存單元的。
- 指針的大小在32位平臺是4個字節(jié),在64位平臺是8個字節(jié)。
2. 指針和指針類型
我們在創(chuàng)建變量的時候會使用不同的數(shù)據(jù)類型 char,short,int 因?yàn)樗鼈兯鶆?chuàng)建的空間是不一樣的。因?yàn)樗鼈兊哪芰Σ煌庞胁煌念愋?。但是我們?chuàng)建的指針大小都是4或8個字節(jié)
char a 一個字節(jié)
short b 兩個字節(jié)
int c 四個字節(jié)
char* 4/8個字節(jié)
short* 4/8個字節(jié)
int* 4/8個字節(jié)
不同類型的指針大小既然是一樣的,為什么還有搞這么多類型呢?那我們可不可以創(chuàng)建一個通用類型的指針呢?然而我們發(fā)現(xiàn)C語言并沒有這樣取做,還是有各種類型的指針,這是為什么呢?
其實(shí)很簡單,指針類型其實(shí)是有特殊意義的,那它的意義是什么呢?
2.1 指針±整數(shù)
#include <stdio.h>
//演示實(shí)例
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
對于一個整形指針來說,它會默認(rèn)自己存儲的是一個整形變量,對整形指針加1,就會跳過一個整形的距離,也就是4個字節(jié)。同理對于一個字符形指針,加1就跳過了1個字節(jié)
總結(jié) : 指針的類型決定了指針向前或者向后走一步有多大(距離)。
2.2 指針的解引用
//演示實(shí)例
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0; //重點(diǎn)在調(diào)試的過程中觀察內(nèi)存的變化。
*pi = 0; //重點(diǎn)在調(diào)試的過程中觀察內(nèi)存的變化。
return 0;
}
我們發(fā)現(xiàn),想通過一個字符型指針改變一個整形變量,結(jié)果只改變了它最低位的一個字節(jié),而通過一個整形指針,則改變了4個字節(jié), 所以指針類型決定了解引用時訪問的字節(jié)個數(shù)。
總結(jié):
- 指針的類型決定了,對指針解引用的時候有多大的權(quán)限(能操作幾個字節(jié))。
- 比如: char* 的指針解引用就只能訪問一個字節(jié),而 int* 的指針的解引用就能訪問四個字節(jié)。
3. 野指針
概念: 野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒有明確限制的)
3.1 野指針成因
- 指針未初始化
指針未初始化時,默認(rèn)隨機(jī)值,存放的就是一個隨機(jī)的地址。這個地址不屬于我們,當(dāng)我們想要改變這個地址中的數(shù)據(jù)時,就非法訪問了,所以這個P是野指針。
#include <stdio.h>
int main()
{
int *p;//局部變量指針未初始化,默認(rèn)為隨機(jī)值
*p = 20;
return 0;
}
- 指針越界訪問
這個數(shù)組只有10個元素,但是當(dāng)我們想要訪問數(shù)組后面的空間時,這個空間也不屬于我們,當(dāng)我們想解引用時也是非法訪問了。
#include <stdio.h>
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;
}
- 指針指向的空間釋放
這里的a就是一個局部變量,在test函數(shù)中是可以正常使用的,但是出了test函數(shù)就銷毀了,這塊空間就不屬于我們了,我們再想對這塊空間進(jìn)行修改也是非法訪問
int* test()
{
int a=0;
return &a;
}
int main()
{
int *p=test();
*p = 100;
return;
3.2 如何規(guī)避野指針
- 指針初始化
- 小心指針越界
- 指針指向空間釋放,及時置NULL
- 避免返回局部變量的地址
- 指針使用之前檢查有效性
- 指針不知道指向哪里就給它置NULL
#include <stdio.h>
int main()
{
int *p = NULL;
//....
int a = 10;
p = &a;
if(p != NULL)
{
*p = 20;
}
return 0;
}
4. 指針運(yùn)算
- 指針± 整數(shù)
- 指針-指針
- 指針的關(guān)系運(yùn)算
4.1指針±整數(shù)
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指針+-整數(shù);指針的關(guān)系運(yùn)算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
這里就是定義了一個float類型的數(shù)組,每次指針加1就是vp指向的地址向后挪動一個folat位,并把它賦值為0
4.2 指針-指針
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int n = &arr[9] - &arr[0];
printf("%d", n);
return 0;
}
指針減去指針其實(shí)就是地址減地址,指針減指針是有前提條件的:兩個指針類型相同并且指向同一塊空間。得到的結(jié)果是兩個指針之間的元素個數(shù)
4.3 指針的關(guān)系運(yùn)算
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
代碼簡化, 這將代碼修改如下:
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
實(shí)際在絕大部分的編譯器上是可以順利完成任務(wù)的,然而我們還是應(yīng)該避免這樣寫,因?yàn)闃?biāo)準(zhǔn)并不保證它可行。
標(biāo)準(zhǔn)規(guī)定:
允許指向數(shù)組元素的指針與指向數(shù)組最后一個元素后面的那個內(nèi)存位置的指針比較,但是不允許與指向第一個元素之前的那個內(nèi)存位置的指針進(jìn)行比較。
5. 指針和數(shù)組
我們看一個例子:
#include <stdio.h>
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;
}
運(yùn)行結(jié)果:
可見數(shù)組名和數(shù)組首元素的地址是一樣的。
結(jié)論:數(shù)組名表示的是數(shù)組首元素的地址。(兩個例外,sizeof(數(shù)組名)是求整個數(shù)組的大小,&數(shù)組名是取整個數(shù)組的地址)
那么這樣寫代碼是可行的:
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是數(shù)組首元素的地址
既然可以把數(shù)組名當(dāng)成地址存放到一個指針中,我們使用指針來訪問一個就成為可能。
例如:
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr; //指針存放數(shù)組首元素的地址
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
}
return 0;
}
運(yùn)行結(jié)果:
所以 p+i 其實(shí)計算的是數(shù)組 arr 下標(biāo)為i的地址。
那我們就可以直接通過指針來訪問數(shù)組。
如下:
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指針存放數(shù)組首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
6. 二級指針
指針變量也是變量,是變量就有地址,那指針變量的地址存放在哪里?
這就是 二級指針。
對于二級指針的運(yùn)算有:
- *ppa 通過對ppa中的地址進(jìn)行解引用,這樣找到的是 pa , *ppa 其實(shí)訪問的就是 pa .
int b = 20;
*ppa = &b;//等價于 pa = &b;
- **ppa 先通過 *ppa 找到 pa ,然后對 pa 進(jìn)行解引用操作: *pa ,那找到的是 a
**ppa = 30;
//等價于*pa = 30;
//等價于a = 30;
7. 指針數(shù)組
指針數(shù)組是指針還是數(shù)組?
答案:是數(shù)組。是存放指針的數(shù)組。
數(shù)組我們已經(jīng)知道整形數(shù)組,字符數(shù)組。
int arr1[5];
char arr2[6];
那指針數(shù)組是怎樣的?
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
//指針數(shù)組
//存放指針的地址
int* arr3[5] = { &a,&b,&c };
for (int i = 0; i < 3; i++)
{
printf("%d ", *(arr[i]));
}
return 0;
}
arr3是一個數(shù)組,有五個元素,每個元素是一個整形指針。
結(jié)尾
這些就是我給大家分享的關(guān)于初識指針的知識啦,希望我們都能有所收獲
先贊后看,養(yǎng)成習(xí)慣??!^ _ ^
碼字不易,大家的支持就是我堅持下去的動力,點(diǎn)贊后不要忘了關(guān)注我哦!文章來源:http://www.zghlxwxcb.cn/news/detail-420672.html
如有錯誤,還請您批評改正(?ì _ í?)文章來源地址http://www.zghlxwxcb.cn/news/detail-420672.html
到了這里,關(guān)于讓你立刻學(xué)會指針的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!