網站首頁 編程語言 正文
1、先談談內存與地址
引例:
計算機的內存看成大街上的一排房屋,每個房屋都要有門牌號,這個就相當于計算機的內存地址,而房屋里面住的人、家具等等就相當于需要存放的各種各樣的數據,所以要想訪問這些數據就得知道它的內存地址。
**bit:計算機的內存便是由數以億萬計的位(bit)**組成,每個位的容納值為0或1。
- byte:字節,一個字節包含8個位(bit),可以儲存無符號unsigned類型的值為0-255(28-1),儲存有符號signed類型的值為-128到127。無符號類型就是非負數,而有符號類型就是負數,0,正數。它也是可尋址的最小內存塊。
- word:字,是儲存的基本單位,在計算機內存中基本是以一個word來儲存數據的。
在16位的系統中(比如8086微機) 1字 (word)= 2字節(byte)= 16(bit)
在32位的系統中(比如win32) 1字(word)= 4字節(byte)=32(bit)
在64位的系統中(比如win64)1字(word)= 8字節(byte)=64(bit)
地址與字節的關系:
拿我本人的機器來舉例吧,我的操作系統是64位的,1word=8byte=64bit,int類型在內存中占4個字節(64位+VS),
所以地址是4個連在一起的數字,用一般取地址符&輸出的是變量的首地址。
地址就是以字節做單位的。指針類型占4個字節。
C類型所占字節數:
補充:數據類型所占的字節數或者位數實際上與操作系統的位數和編譯器(不同的編譯器支持的位數可能有所不同),反正具體某種數據類型所占的字節數是編譯器根據操作系統的位數決定的,用例如==sizeof()==測一下就好。
C類型 | 32位(所占字節數) | 64位(所占字節數) |
---|---|---|
char | 1個字節 | 1 |
short int | 2 | 2 |
int | 4 | 4 |
wchar_t | 2(寬字符) | 2 |
char16_t | 2(unicode字符) | 2 |
char32_t | 4(unicode字符) | 4 |
float | 4(6位有效數字) | 4 |
double | 8(10位有效數字) | 8 |
int * | 4 | 4 |
int i;//int類型占兩個字節,16位(64位操作系統占4個字節),i在內存起始地址為6申請了2個字節的內存空間,并命名為i char a;//char類型占一個字節,8位,a在地址為8上申請了1字節的內存空間,并命名為a
//將30存入變量i的內存空間 i=30; //將字符't'存入變量a的內存空間 a='t'; //通過取地址符&,輸出變量的首地址6 cout<<"i的地址為:"<<&i<<endl; //輸出變量i所儲存的值 cout<<"i的值為:"<<i<<endl; //通過取地址符&,輸出變量的首地址8 cout<<"a的地址為:"<<&a<<endl; //輸出變量i所儲存的值 cout<<"a的值為:"<<a<<endl;
2、再談指針
//假設pi占2個字節寬度,實際上32位系統中,指針占4個字節 //指針變量pi在起始地址為8上申請了2個字節的內存空間 int *pi; //將變量i的起始地址賦值給pi,所以pi的值為i的起始地址 pi=&i; //輸出指針變量p的首地址11 cout<<"pi的地址為:"<<&pi<<endl; //輸出變量i的首地址,因為pi的值被賦予為i的首地址 cout<<"pi的值為:"<<pi<<endl; //通過解引用符*訪問到變量i所儲存的值 cout<<"pi所指向的值:"<<*pi<<endl; *pi=20;//將通過解引用運算符訪問到變量i并賦值為20,pi的值和地址都沒有變化 cout<<"i的值為:"<<i<<endl;
變量pi的值就是分配給變量pi的內存空間所儲存的數據,在上面這個例子中就是被賦予i的首地址6!
3、區別指針的類型,指針所指的類型,指針的值
(1)、指針的類型:
從語法角度看,把指針聲明語句里面的指針變量的名字去掉,剩下的就是指針的類型。
(2)、指針所指的類型:
從語法角度看,就是把指針聲明語句中的指針變量的名字和名字左邊的指針聲明符*去掉,剩下的就是指針所指的類型了。
(3)、指針的值:
**指針的值本是指針變量自身所儲存的數值,但是例如int p1=&i;p1的值為i的地址,可分解為兩句int p1;p1=&i;這樣就不難理解了,p1所儲存的值就是i的首地址,因為&i表示變量i的首地址。
在32位程序中(4個字節的程序),所有類型的指針的值都是一個32位的整數。因為32位程序里的內存地址都是32位長(4個byte)。
簡而言之,指針的值占4個字節,所以說指針指向了i的內存空間,輸出的值為i這塊內存區域的首地址。
4、指針的算術運算:
int i=0; int *p=&i; cout<<p<<endl;//輸出的是變量p保留的i的首地址 ++p;//p的值加了4(sizeof(int)=1) cout<<p<<endl;//輸出的值為i的首地址+4
一個指針 ptrold 加(減)一個整數 n 后,結果是一個新的指針 ptrnew,ptrnew 的類型和 ptrold 的類型相同,ptrnew 所指向的類型和 ptrold所指向的類型也相同。ptrnew 的值將比 ptrold 的值增加(減少)了 n 乘sizeof(ptrold 所指向的類型)個字節。就是說,ptrnew 所指向的內存區將比 ptrold 所指向的內存區向高(低)地址方向移動了 n 乘sizeof(ptrold 所指向的類型)個字節。
指針和指針進行加減:
兩個指針不能進行加法運算
,這是非法操作,因為進行加法后,得到的結果指向一個不知所向的地方,而且毫無意義。兩個指針可以進行減法操作,但必須類型相同
,一般用在數組方面,不多說了。
5、運算符&和*:
這里&是取地址運算符
,*是間接運算符
,也叫解引用操作符。
重點理解(&a)=20:*
&a表示變量a的地址,(&a)表示通過a的地址找到a,然后通過解引用符給其賦值為20。(int *p=&a; *p=20;這里的p就相當于&a,這樣就比較好理解了。)
p 的運算結果就五花八門了。總之p 的結果是 p 所指向的東西,這個東西有這些特點:它的類型是 p 指向的類型,它所占用的地址是 p所指向的地址。
6、指針與數組的關系:
int a[]={1,2,3,4,5}; int i; i=a[0];//i=*a; i=a[3];//i=*(a+3)
數組名a代表數組本身,類型為int [],但是如果把a看作指針的話,它指向數組的第0個單元,類型為int *,所指向的類型為int。
下面總結一下數組的數組名(數組中儲存的也是數組)的問題:
聲明了一個數組 TYPE array[n],則數組名稱 array 就有了兩重含義:
- 第一,它代表整個數組,它的類型是 TYPE[n];
- 第二 ,它是一個常量指針,該指針的類型是 TYPE*,該指針指向的類型是 TYPE,也就是數組單元的類型,該指針指向的內存區就是數組第 0 號單元,該指針自己占有單獨的內存區,注意它和數組第 0 號單元占據的內存區是不同的。該指針的值是不能修改的,即類似 array++的表達式是錯誤的。
在不同的表達式中數組名 array 可以扮演不同的角色:
在表達式 sizeof(array)中,數組名 array 代表數組本身,故這時sizeof 函數測出的是整個數組的大小。
在表達式array 中,array 扮演的是指針,因此這個表達式的結果就是數組第 0 號單元的值。sizeof(*array)測出的是數組單元的大小。
表達式 array+n(其中 n=0,1,2,…)中,array 扮演的是指針,故 array+n 的結果是一個指針,它的類型是 TYPE *,它指向的類型是 TYPE,它指向數組第 n 號單元。故sizeof(array+n)測出的是指針類型的大小。在 32 位程序中結果是 4。
sizeof(int(*)[10])=4
sizeof(int[10])=40
sizeof(ptr)=4
實際上,sizeof(對象)測出的都是對象自身的類型的大小,而不是別的什么類型的大小。
7、const int *pi與int *const pi:
const int i與int const i沒有區別,const int *pi也與int const *pi沒有區別,int與const那個放前放后都是一樣的。
重點是*在const的左邊還是右邊:
- 1) 如果 const 修飾在* pi的左邊,則不能改的是* pi(即不能類似這樣:* pi=50;賦值)而不是指 pi。
只有通過給指針所向的變量賦值,才能是*pi改變:
pi=&i;i=20;cout<<*pi<<endl; - 2) 如果 const 是直接寫在 pi 前,則 pi 不能改(即不能類似這樣:pi=&i;賦值),pi的地址永遠只能指向初始化時的內存地址了,可以直接修改i的值,也可以通過 * pi來修改i的值。
補充:
情況一:int *pi 指針指向 const int i 常量的情況
const int i1 = 40;
int * pi;
pi = &i1;
//const int 類型的 i1 的地址是不能賦值給指向 int 類型地址的指針 pi 的。否則 pi 豈不是能修改 i1 的值了嗎!
pi = (int * ) &i1;//強制類型轉換可是 C 所支持的。
*p1=80;//編譯能過但是i1的值還是40
情況二:const int *pi 指針指向 const int i1 的情況
const int i1=40;
const int * pi;
pi=&i1;//兩個類型相同,可以這樣賦值。很顯然,i1 的值無論是通過pi 還是 i1 都不能修改的。
情況三:用 const int *const pi 聲明的指針
int i;
const int * const pi=&i; //你能想象 pi 能夠作什么操作嗎?
pi值不能改,也不能通過 pi 修改 i 的值。因為不管是*pi 還是 pi 都是 const的。
原文鏈接:https://blog.csdn.net/qq_43152052/article/details/86760468
相關推薦
- 2022-11-21 正則表達式RegExp語法與用法詳解_正則表達式
- 2023-10-27 np.array()函數的使用方法_python
- 2022-07-07 Django加載配置的過程詳解_python
- 2022-10-11 主從同步中斷(sql_thread)問題一例
- 2022-07-10 linux基礎命令運用
- 2022-04-03 Go語言讀取txt文檔的操作方法_Golang
- 2022-07-25 .Net行為型設計模式之訪問者模式(Visitor)_基礎應用
- 2022-04-23 Python實現B站UP主小助手詳解開發流程_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支