網(wǎng)站首頁 編程語言 正文
前言
本文開始指針相關(guān)內(nèi)容的學(xué)習(xí),主要內(nèi)容包括:
- 指針是什么
- 指針和指針類型
- 野指針
- 指針運算
- 指針和數(shù)組
- 二級指針
- 指針數(shù)組
1、指針是什么
指針理解的2個要點:
- 平時口語中說的指針,通常指的是指針變量,是用來存放內(nèi)存地址的變量
- 指針是內(nèi)存中一個最小單元的編號,也就是地址
1.1 指針變量
我們可以通過&(取地址操作符)取出變量的內(nèi)存其實地址,把地址可以存放到一個變量中,這個變量就是指針變量:
int main()
{
int a = 1;//在內(nèi)存中開辟一塊空間
//a變量占用4個字節(jié)的空間,這里是將a的4個字節(jié)的第一個字節(jié)的地址存放在p變量中,p就是一個指針變量
int* pa = &a;//這里我們對變量a,取出它的地址,可以使用&操作符
printf("%p\n", &a);
printf("%p\n", pa);
a = 10;
printf("%p\n", &a);
return 0;
}
利用內(nèi)存和監(jiān)視來查看&a 和pa的變化:
見下圖所示:
- &a為取變量a的地址:0x00CFFEE0
- pa是指針變量,存放的值是變量a的地址: 0x00CFFEE0
a變量占用4個字節(jié)的空間,下圖在內(nèi)存中能看到a的地址占用了4個字節(jié),存放 00 00 00 01
內(nèi)存顯示列數(shù)可根據(jù)自己調(diào)節(jié),4列就是4個字節(jié)放一行,見下圖:
對a重新賦值10,變量a的值發(fā)生變化,但地址是不變的。
因此,指針變量,用來存放地址的變量。(存放在指針中的值都被當(dāng)成地址處理)。
1.2 指針是內(nèi)存中一個最小單元的編號
- 指針是內(nèi)存中一個最小單元的編號,這個最小單元是一個字節(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
內(nèi)存最小單元即一個字節(jié),與其對應(yīng)的地址見下圖:
因此,32位的機(jī)器就有2的32次方個地址。每個地址標(biāo)識一個字節(jié),那我們就可以給 :
2^32 Byte == 2^32/1024 KB == 2^32/1024/1024 MB == 2^32/1024/1024/1024 GB == 4 GB
4 GB的空閑進(jìn)行編址。同樣的方法,那64位機(jī)器,如果給64根地址線,那能編址 8 GB 空間。
- 在32位的機(jī)器上,地址是32個0或者1組成二進(jìn)制序列,那地址就得用4個字節(jié)的空間來存儲,所以一個指針變量的大小就應(yīng)該是4個字節(jié)
- 在64位機(jī)器上,有64個地址線,那一個指針變量的大小是8個字節(jié),才能存放一個地址
- 指針是用來存放地址的,地址是唯一標(biāo)示一塊地址空間的
- 指針的大小在32位平臺是4個字節(jié),在64位平臺是8個字節(jié)
int main()
{
int a = 10;
int* pa = &a;
char ch = 'a';
char* pc = &ch;
printf("%d\n", sizeof(pa));//4
printf("%d\n", sizeof(pc));//4
return 0;
}
上例說明,不管什么類型的指針變量,它的大小就是4個字節(jié)。因為地址是32位0 1表示的,而指針變量就是存放地址的變量,需要4個字節(jié)存放。跟他的類型無關(guān)。
2、指針和指針類型
變量有不同的類型,整形,浮點型等。那指針同樣也有類型:
int num = 10;
p = #//num的地址保存到 p
要將&num(num的地址)保存到 p 中,我們知道 p 就是一個指針變量,那它的類型是怎樣的呢?我們給指針變量相應(yīng)的類型
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
指針的定義方式是: type + *
- char* 類型的指針是為了存放 char 類型變量的地址:即地址里面的變量是char 類型,占用1個字節(jié),地址本身4個字節(jié)
- short* 類型的指針是為了存放 short 類型變量的地址:即地址里面的變量是short類型,占用1個字節(jié),地址本身4個字節(jié)
- int* 類型的指針是為了存放 int 類型變量的地址:即地址里面的變量是 int 類型,占用4個字節(jié),地址本身4個字節(jié)
2.1 指針±類型
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;
}
指針的類型決定了指針向前或者向后走一步有多大(距離):
- int *向后+1,就是移動到下一個 int 類的變量的地址,就是移動4個字節(jié)
- char *向后+1,就是移動到下一個 char 類型的變量的地址,就是移動1個字節(jié)
- 指針的類型,是指向地址里存儲數(shù)值的類型
2.2 指針的解引用
指針的類型決定了,對指針解引用的時候有多大的權(quán)限(能操作幾個字節(jié))
2.2.1 int* 類型的解引用
int main()
{
int a = 0x11223344;
int* pa = &a;
*pa = 0;
return 0;
int* 的指針的解引用就能訪問四個字節(jié):
2.2.2 char* 類型的解引用
int main()
{
int a = 0x11223344;
char* pa = (char*)&a;//&a是int*,所以在這里強(qiáng)制轉(zhuǎn)換
*pa = 0;
return 0;
}
char* 的指針解引用就只能訪問一個字節(jié):
3、野指針
野指針就是指針指向的位置是不可知的(隨機(jī)的、不正確的、沒有明確限制的)
3.1 野指針成因
3.1.1 指針未初始化
int main()
{
int *p;//局部變量指針未初始化,默認(rèn)為隨機(jī)值
*p = 20;
return 0;
}
3.1.2 指針越界訪問
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)//超過數(shù)組的元數(shù)個數(shù)
{
//當(dāng)指針指向的范圍超出數(shù)組arr的范圍時,p就是野指針
*(p++) = i;
}
return 0;
}
3.1.3 指針指向的空間釋放
int* test()
{
int a = 10;
printf("%d\n", a);
return &a;//開辟的空間已經(jīng)釋放了
}
int main()
{
int* p = test();//函數(shù)調(diào)用結(jié)束后,開辟的內(nèi)存空間釋放了
*p = 100;
return 0;
}
3.2 如何規(guī)避野指針
- 指針初始化
- 小心指針越界
- 指針指向空間釋放即使置NULL
- 避免返回局部變量的地址
- 指針使用之前檢查有效性
int main()
{
int *p = NULL;//初始化
//....
int a = 10;
p = &a;
if(p != NULL)
{
*p = 20;
}
return 0;
}
總結(jié)
本文學(xué)習(xí)了指針的部分內(nèi)容,下一篇繼續(xù)學(xué)習(xí)指針的內(nèi)容。(鏈接直達(dá))
原文鏈接:https://blog.csdn.net/taibudong1991/article/details/123788274
相關(guān)推薦
- 2024-07-15 bootspring第三方資源配置管理
- 2022-10-07 mybatis?調(diào)用?Oracle?存儲過程并接受返回值的示例代碼_oracle
- 2022-07-19 Oracle 集群sysbackup用戶登陸隨機(jī)報錯ORA-01017
- 2022-12-07 python中的eval函數(shù)使用實例_python
- 2023-02-02 一文帶你深入了解C++中的類型轉(zhuǎn)換_C 語言
- 2022-07-29 Jetpack?Compose實現(xiàn)列表和動畫效果詳解_Android
- 2022-08-19 WPF使用Geometry繪制幾何圖形_C#教程
- 2022-11-26 詳解Python如何實現(xiàn)惰性導(dǎo)入-lazy?import_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支