国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

C語言進階第一問:數據在內存中是如何存儲的?(手把手帶你深度剖析數據在內卒中的存儲,超全解析,碼住不

ghnor / 2344人閱讀

摘要:在符號位中,表示正,表示負。我們知道對于整型來說,內存中存放的是該數的補碼。在計算機系統中,數值一律用補碼來表示和存儲。表示有效數字,。規定對于位的浮點數,最高的位是

最近博主開學啦!更新節奏有點跟不上,這里做個檢討~

UU們開學感覺怎么樣呢?見到同學或者舍友有沒有很開心呢?又可以一起愉快地玩???!

但是玩歸玩,學習還是正事,話不多說,開始今天的內容。

在之前的內容中,我們已經把C語言的入門知識進行了一個全面的講解,并介紹了一些實用的調試技巧,以及函數棧幀的創建和銷毀,可以說對于C語言已經算是敲過開門磚了。

那么今天,我們就要開啟深入學習C語言的旅程啦!首先解決C語言進階第一問:數據在內存中是如何存儲的?

當然,我們主要探討的是整型和浮點型這兩種類型。

數據類型

C語言中具以下幾種基本內置類型:

這里說明一下:

  • C語言的基本內置類型只的是C語言本身具有的類型,而庫函數本身是不屬于C語言的,是獨立于C語言之外的。
  • C語言是用來決定語言的語法形式的,而庫函數是編譯器的產商提供,當然庫函數的使用是受C語言標準約束的(比如C語言標準規定了一些庫函數的函數名、參數類型、返回值類型和函數功能)。
  • 這樣做的好處是雖然不同編譯器實現函數的方式不一樣,但是對于我們來說,在不同的編譯器下使用函數的方式是一樣的。
  • 當然在有一些編譯器中對一些庫函數的支持提供得不是很好,比如在VS編譯器下使用scanf函數就可能會報錯,需要使用scanf_s。

由于字符類型在存儲的時候是按照ASCII碼值存儲的,所以字符類型也屬于整型家族中的一員。

前面我們已經學習了以上這么多的數據類型,并且了解了它們所占內存空間的大小。

我們還要明白,我們為什么要給數據分那么多的類型:

  1. 我們生活中出了的數除了整數就是小數,所以為了更好地存儲這兩種類型,數據分為整型和浮點型兩大類
  2. 使用不同的類型時內存開辟的空間大小是不一樣的(使用范圍也不一樣)。我們應該根據數據的大小選擇合適的類型,如果選大了,則浪費空間;選小了,則數據無法完整存儲。
  3. 不同類型決定了我們看待空間時應該采用哪種視角。即對于內存中不同空間的類型存和取的方式是不一樣的。

類型的基本歸類

整型家族

  • char
    unsigned char
    signed char
  • short
    unsigned short [int]
    signed short [int]
  • int
    unsigned int
    signed int
  • long
    unsigned long [int]
    signed long [int]
    -long long
    unsigned long long [int]
    signed long long [int]

注意:



如何理解有符號和無符號:

以char類型舉例:

這里也說明了不同類型決定了我們看待內存中的值時視角也不同。

同時,我們也可以由此推算出一個類型中最大能放一個多大的數字。

還是以char類型舉例:

由此可以得出,有符號的char中可以存放的數的范圍是 -128 ~ 127。

相同道理:

無符號的char中可以存放的數的范圍是 0 ~ 255。

同理,我們可以得出short、int 、long等等類型的范圍。

浮點型

float
double

這兩種類型通常根據數據要求的精度來選擇:精度高選擇double類型(8個字節),精度低選擇float類型(4個字節)。

一般我們更常選擇float類型,但是記住噢~3.14默認是double類型哦!

構造類型

除了內置類型之外,還有構造類型,即可以自己創造的類型。

數組類型
結構體類型 struct
枚舉類型 enum
聯合類型 union

數組類型為什么也屬于構造類型呢?

我們來看看數組的類型:


當我們定義的數組元素的類型和個數不同時,數組的類型也不同,可以通過sizeof反映出來,所以我們也說數組屬于構造類型。

指針類型

int *pi
char *pc
float *pf
void *pv

空類型

void表示空類型(即無類型)
常用于函數的返回類型、函數參數和指針類型

這里說void作為函數參數是什么情況呢?

正常我們在調用函數的時候,如果這個函數不需要傳參,則不寫參數。

但是如果是一個不需要傳參的函數,而我們又給它傳參了,函數會怎樣呢?在有的編譯器中,會報錯,但是有的編譯器則會接受這種情況。

但是如果我們給參數加上一個void。編譯器就會報錯或者警告,告訴你不能傳參啦!

整型在內存中的存儲

我們知道,一個變量創建之后是要在內存中開辟空間的,那么這些變量在內存中到底是怎么存儲的呢?

接下來我們就來看看~

首先看看整型在內存中是如何存儲的。

我們知道,二進制中有符號的整數有原碼、反碼、補碼三種表示方式。

這三種表示方式都有符號位和數值位兩部分。

  • 在符號位中,0表示“正”,1表示“負”。
  • 在數值位中,正數的原、反、補碼相同;負數的三種表示方法各不相同:
    原碼:直接將二進制按照正負數的形式翻譯成二進制。
    反碼:將原碼的符號位不變,其他位依次按位取反。
    補碼:反碼+1得到補碼。

我們知道對于整型來說,內存中存放的是該數的補碼。

在計算機系統中,數值一律用補碼來表示和存儲。

但是存放的是補碼,而不是原碼或者反碼呢?

因為,使用補碼可以將符號位和數值位作統一處理。

同時,加法和減法也可以統一處理(CPU只有加法器)。

因此,補碼與原碼相互轉換,其運算過程是相同的,不需要額外的硬件電路。

比如,我們想計算1-1。但是因為CUP只有加法運算,所以我們可以把表達式寫成1+(-1)。


我們可以看到,用原碼計算,得不出正確的結果。

但是如果用補碼計算,情況就不一樣了。


從上圖的計算中,我們可以看出,使用補碼可以直接對符號位和數值位同一進行處理。

這里有一個有意思的事情:

我們知道原碼、反碼和補碼都是怎么得到的,那么計算一下我們會發現用同樣的方法,我們也可以通過補碼得到原碼。


(不信你試著算一下?。?/p>

所以,由此我們可以看到用補碼來存儲的好處。

大小端字節序

定義


我們看到,a是一個十六進制的數,當我們在內存中查看它的存儲情況時,可以發現,它的存放是從低地址開始放44 33 22 11。

對于它們在內存中的存放順序,其實可以有很多種存放的方式。

但是如果大家都按照自己的想法來寫,則整個存儲就會亂套,而且如果我們不按照正常的順序存儲時,取出來要獲得原來的數就比較麻煩,所以我們最后決定只以下兩種存儲順序。


注意:這里的存儲順序是以字節為單位來討論的。因此,也稱字節序。

其中,上面的存儲順序稱為小端字節序;下面的存儲順序稱為大端字節序。

  • 小端字節序存儲
    把一個數的低位字節的內容,存儲在內存的低地址出,把這個數的高位字節的內容,存儲在內存的高地址處。
  • 大端字節序存儲
    把一個數的低位字節的內容,存儲在內存的高地址出,把這個數的高位字節的內容,存儲在內存的低地址處。

意義

那么,為什么在存儲時還要有大小端之分呢?

這是因為在計算機系統中,內存空間的最小單元是一個字節。所以,如果我們存放的變量大小大于一個字節時,我們就不得考慮每個字節應該以何種順序存放在內存中了。

那么我們當前的編譯器是采取大端存儲還是小端存儲呢?

別著急,回頭看看內存中的值的順序,就能知道啦!

所以,我們當前編譯器采用的是小端字節序。

百度曾經出過一道筆試題,讓被試者設計一個程序來判斷當前機器的字節序。

那么我們應該如何做呢?

我們用1來進行觀察。


所以,我們只需要拿出第一個字節,看看里面存的是0還是1就知道了。

當然,我們要實現的是查看一個機器字節序的功能,所以這里我們最好把程序封裝成一個函數。

浮點型在內存中的存儲

看完了整數在內存中是怎么存儲的,那么浮點型在內存中又是怎么存儲的呢?

我們接下來就來看看。

首先我們常見的浮點數有:

小數:3.1425926
科學計數法:1E10(1.0*1010

在浮點型中,我們有float和double兩種類型。

而這兩種類型的范圍,我們用float.h來定義。

如果我們想看整數的最大值(最小值),我們就用INT_MAX(INT_MIN);并在前面包含頭文件


然后我們就能看到int類型所能存放的最大值啦!


那么,浮點數所能存放的最大最小值是多少呢?

同理,我們可以用FLT_MAX(或者FLT_MIN、DBL_MAX等),引用頭文件,然后轉到定義。

就能得到他們的精度啦~

那么在內存中浮點數的存儲和整數的存儲是一樣的嗎?

我們可以先通過一段代碼來進行驗證。


那么如果浮點型的存儲和整型不一樣,它又是怎么存儲的呢?

根據國際標準IEEE(電氣和電子工程協會) 754,任意一個二進制浮點數V可以表示成下面的形式:

  • (-1)S * M * 2E
    (-1)s表示符號位,當S=0,V為正數;當S=1,V為負數。
    M表示有效數字,1≤M<2。
    2E表示指數位。

我們以小數5.5來舉例。


同理,我們可以寫出9.0的表示形式:

我們會發現,其實任何一個浮點數都可以寫成這種形式。

那么,只要我們把一個浮點數寫成(-1)S * M * 2E這種形式,那么只要我們存儲了S、M、E的信息,就能還原出浮點數的值了。

IEEE 754規定: 對于32位的浮點數,最高的1位是符號位S,接著的8位是指數E,剩下的23位為有效數字M。

對于64位的浮點數,最高的1位為符號位S,接著是11位的指數E,剩下的52位為有效數字M。

  • 此外,IEEE 754對有效數字M和指數E,還有一些特別規定。

因為1≤M<2 即M可以寫成1.XXXXXX 的形式,其中XXXXXX表示小數部分。

IEEE 754規定,在計算機內部保存M時,默認這個數的第一位總是1,因此這個1和它后面的小數點可以被舍去,只保存后面的XXXXXX部分。

比如:當我們要保存1.01的時候,只需要保存01,等到讀取的時候,再把前面的1.加上去。

這樣,我們就節省了1位有效數字。

以32位浮點數(float)為例,留給M只有23位,將第一位的1舍去以后,等于可以保存24位有效數字,這樣精度就得到了提高。

  • 那么對于指數E來說,它又是怎么存進去的呢?

我們知道,對于指數E來說,它是可以去負數的,那么對于負數的E在存儲的時候,我們又應該如何處理呢?

于是人們又想出了一個辦法,不如給這個E加上一個中間數,讓E即使是最小的負數,加上這個數之后也不會為負(等于0),那么就不會出現負數的情況了,只要我們取出來的時候再把這個中間數加上就行了。

這樣,我們就可以把E作為一個無符號整數了。

如果E為8位,那么它的取值范圍就是:0~255,那么它的中間數就是127。

對于11位的E,它的取值范圍是0~2047,它的中間數就是1023。

比如:210的E是10,所以保存成32位浮點數時,就保存成10+127=137,即10001001。

以5.5為例,我們可以在內存中看到它的存儲。

并且我們可以發現,對于浮點數,它在內存中的存儲也是有大小端的。

以上,我們就知道了浮點數在內存中是怎么存的了。
那么它又是怎么取出來的呢?

按道理,我們是怎么放進去的,就應該是怎么取出來的。但是由于指數E比較特別,所以再取出來時,又有一些特別的規定。

在內存中取出E時,我們有一下三種情況:

E不全為0或不全為1

這時,E是怎么存進來的,我們就按照原路取出來。

即指數E的計算值減去127(或1023),得到真實值,再將有效數字M前加上第一位的1。

比如: 0.5的二進制形式為0.1,由于規定正數部分必須為1,即將小數點右移1位,則為1.0*2^(-1)。

同理,反過來,我們可以通過這個二進制序列得到0.5。

E全為0

當E全為0的時候,說明浮點數的指數E等于-127,而2-127是一個非常非常小的數,已經十分接近于0了。

所以這時候,我們就不再按照原來的計算方式,而是把浮點數的指數E直接記為1-127(或者1-1023), 并且有效數字M不再加上第一位的1,而是還原為0.XXXXXX的小數。這樣做是為了表示±0,以及無窮接近于0的很小的數。

E全為1

當E全為1時,則得到的是255,減去127得到的是128,而2128是一個非常大的數。所以這時,如果有效數字M全為0,則該數就表示±無窮大(正負取決于符號位S)

當我們了解完以上浮點型在內存中的存儲規則之后,我們就可以理解之前哪個代碼打印出來的值了。

今天的文章就到這里啦!~

你學廢了嗎?記得點贊收藏加關注,在評論區留下你的腳印~

關注我!一起精進C語言!

今天的代碼都在這里咯!
https://gitee.com/fang-qiuhui/my-code/blob/4ab3bddffe0dc8e520fabbee219aa421f67d6c1b/blog_2021_8_30_data/blog_2021_8_30_data.cpp

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/119293.html

相關文章

  • C語言中還有這些類型,別再說你不知道了!把手帶你解鎖C語言自定義類型,讓你寫你所想。

    摘要:結構體類型的特殊聲明在初階結構體中,我們已經將了結構體類型是如何進行聲明的,那么在這里,我們將講一些特殊的結構體聲明不完全的聲明。所以我們應該這樣寫通過指針來找到下一個同類型結構體的寫法,我們就稱之為結構體的自引用。 ...

    hizengzeng 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發前端掘金作者原文地址譯者插件是為應用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內優雅的實現文件分片斷點續傳。 Vue.js 插件開發 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應用添加全局功能的一種強大而且簡單的方式。插....

    izhuhaodev 評論0 收藏0
  • C語言進階學習】一、數據存儲 (深度剖析數據內存存儲)

    摘要:的理解和區別代表有符號,整數在內存中存儲的二進制位的最高位為符號位,表示負數,表示正數。那接下來我們來學習數據在所開辟的內存空間時如何存儲的。請看下面例子為什么內存中存儲的是補碼對于整數來說數據存放內存中其實存放的是補碼。 ...

    AprilJ 評論0 收藏0
  • Java 總結

    摘要:中的詳解必修個多線程問題總結個多線程問題總結有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升開源的運行原理從虛擬機工作流程看運行原理。 自己實現集合框架 (三): 單鏈表的實現 自己實現集合框架 (三): 單鏈表的實現 基于 POI 封裝 ExcelUtil 精簡的 Excel 導入導出 由于 poi 本身只是針對于 ...

    caspar 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<